Python 污染班级环境

Python 污染班级环境,python,oop,Python,Oop,我有一个对象,它包含大量静态访问的ID。我想把它分割成另一个对象,它只保存那些ID,而不需要修改已经存在的代码库。例如: class _CarType(object): DIESEL_CAR_ENGINE = 0 GAS_CAR_ENGINE = 1 # lots of these ids class Car(object): types = _CarType 我希望能够通过调用CAR.types.DIESEL\u CAR\u ENGINE或通过CAR.DIESEL\

我有一个对象,它包含大量静态访问的ID。我想把它分割成另一个对象,它只保存那些ID,而不需要修改已经存在的代码库。例如:

class _CarType(object):
    DIESEL_CAR_ENGINE = 0
    GAS_CAR_ENGINE = 1 # lots of these ids

class Car(object):
    types = _CarType
我希望能够通过调用CAR.types.DIESEL\u CAR\u ENGINE或通过CAR.DIESEL\u CAR\u ENGINE访问_CarType.DIESEL\u CAR\u ENGINE,以向后兼容现有代码。很明显,我不能使用u_getattr_u____________________________________

类似于:

class Car(object):
    for attr, value in _CarType.__dict__.items():
        it not attr.startswith('_'):
            locals()[attr] = value
    del attr, value
或者,您可以在类声明之外执行此操作:

class Car(object):
    # snip

for attr, value in _CarType.__dict__.items():
    it not attr.startswith('_'):
        setattr(Car, attr, value)
del attr, value
比如:

class Car(object):
    for attr, value in _CarType.__dict__.items():
        it not attr.startswith('_'):
            locals()[attr] = value
    del attr, value
或者,您可以在类声明之外执行此操作:

class Car(object):
    # snip

for attr, value in _CarType.__dict__.items():
    it not attr.startswith('_'):
        setattr(Car, attr, value)
del attr, value

虽然这并不完全是子类化的目的,但它实现了您所描述的:

class _CarType(object):
    DIESEL_CAR_ENGINE = 0
    GAS_CAR_ENGINE = 1 # lots of these ids

class Car(_CarType):
    types = _CarType

虽然这并不完全是子类化的目的,但它实现了您所描述的:

class _CarType(object):
    DIESEL_CAR_ENGINE = 0
    GAS_CAR_ENGINE = 1 # lots of these ids

class Car(_CarType):
    types = _CarType

这是如何使用元类实现的:

class _CarType(type):
    DIESEL_CAR_ENGINE = 0
    GAS_CAR_ENGINE = 1 # lots of these ids
    def __init__(self,name,bases,dct):
        for key in dir(_CarType):
            if key.isupper():
                setattr(self,key,getattr(_CarType,key))

class Car(object):
    __metaclass__=_CarType

print(Car.DIESEL_CAR_ENGINE)
print(Car.GAS_CAR_ENGINE)

这是如何使用元类实现的:

class _CarType(type):
    DIESEL_CAR_ENGINE = 0
    GAS_CAR_ENGINE = 1 # lots of these ids
    def __init__(self,name,bases,dct):
        for key in dir(_CarType):
            if key.isupper():
                setattr(self,key,getattr(_CarType,key))

class Car(object):
    __metaclass__=_CarType

print(Car.DIESEL_CAR_ENGINE)
print(Car.GAS_CAR_ENGINE)
如果找不到对象的属性,并且它定义了一个神奇的方法uu getattr uuu,则调用该方法来尝试查找它

仅适用于Car实例,不适用于类

如果找不到对象的属性,并且它定义了一个神奇的方法uu getattr uuu,则调用该方法来尝试查找它


仅适用于Car实例,不适用于类。

您的选项分为两大类:要么将属性从\u CarType复制到Car中,要么使用委托给\u CarType的\uu getattr\uuuuuu方法将Car的元类设置为自定义元类,因此不能使用\uu getattr\uuuuu:您可以,您只需要将其放入Car的元类中,而不是放入Car本身;-

第二种选择的含义可能会让您觉得很奇怪,除非您特别需要:属性不会显示在dirCar上,也不能在Car实例上访问它们,只能在Car本身上访问。即:

>>> class MetaGetattr(type):
...   def __getattr__(cls, nm):
...     return getattr(cls.types, nm)
... 
>>> class Car:
...   __metaclass__ = MetaGetattr
...   types = _CarType
... 
>>> Car.GAS_CAR_ENGINE
1
>>> Car().GAS_CAR_ENGINE
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Car' object has no attribute 'GAS_CAR_ENGINE'
要使这两种查找都能正常工作,可能需要执行以下操作:

>>> Car.GAS_CAR_ENGINE
1
>>> Car().GAS_CAR_ENGINE
1
然而,定义两个本质上相等的getattr似乎并不优雅

因此,我怀疑更简单的方法,复制所有属性,更可取。在Python 2.6或更高版本中,这显然是类装饰器的候选对象:

def typesfrom(typesclass):
  def decorate(cls):
    cls.types = typesclass
    for n in dir(typesclass):
      if n[0] == '_': continue
      v = getattr(typesclass, n)
      setattr(cls, n, v)
    return cls
  return decorate

@typesfrom(_CarType)
class Car(object):
  pass
一般来说,如果你不止一次地使用它,那么定义一个装饰者是值得的;如果您只需要为一个类执行此任务,那么在class语句之后扩展内联代码可能会更好

如果您一直使用Python 2.5甚至2.4,您仍然可以用同样的方法定义类型,您只需将其应用于稍微不那么优雅的事情,即汽车定义变成:

class Car(object):
  pass
Car = typesfrom(_CarType)(Car)

请记住2.2中为函数引入的装饰语法,2.6中为类引入的装饰语法只是包装这些重要且经常重复出现的语义的一种简便方法。

您的选项分为两大类:您可以将属性从_CarType复制到Car中,或者使用委托给CarType的uu getattr uu方法将Car的元类设置为自定义元类,这样就不一定不能使用u getattr uu了:可以,只需要将其放入Car的元类中,而不是放入Car本身中;-

第二种选择的含义可能会让您觉得很奇怪,除非您特别需要:属性不会显示在dirCar上,也不能在Car实例上访问它们,只能在Car本身上访问。即:

>>> class MetaGetattr(type):
...   def __getattr__(cls, nm):
...     return getattr(cls.types, nm)
... 
>>> class Car:
...   __metaclass__ = MetaGetattr
...   types = _CarType
... 
>>> Car.GAS_CAR_ENGINE
1
>>> Car().GAS_CAR_ENGINE
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Car' object has no attribute 'GAS_CAR_ENGINE'
要使这两种查找都能正常工作,可能需要执行以下操作:

>>> Car.GAS_CAR_ENGINE
1
>>> Car().GAS_CAR_ENGINE
1
然而,定义两个本质上相等的getattr似乎并不优雅

因此,我怀疑更简单的方法,复制所有属性,更可取。在Python 2.6或更高版本中,这显然是类装饰器的候选对象:

def typesfrom(typesclass):
  def decorate(cls):
    cls.types = typesclass
    for n in dir(typesclass):
      if n[0] == '_': continue
      v = getattr(typesclass, n)
      setattr(cls, n, v)
    return cls
  return decorate

@typesfrom(_CarType)
class Car(object):
  pass
一般来说,如果你不止一次地使用它,那么定义一个装饰者是值得的;如果您只需要为一个类执行此任务,那么在class语句之后扩展内联代码可能会更好

如果您一直使用Python 2.5甚至2.4,您仍然可以用同样的方法定义类型,您只需将其应用于稍微不那么优雅的事情,即汽车定义变成:

class Car(object):
  pass
Car = typesfrom(_CarType)(Car)

请记住,2.2中为函数引入的decorator语法,2.6中为类引入的decorator语法只是包装这些重要且经常重复出现的语义的一种简便方法。

它工作得很好,但我正在寻找一种更优雅的解决方案。如果没有结果,你就是赢家!非常感谢。您不应该修改局部变量:setattr的使用是您将获得的最优雅、最简单的解决方案。它工作得非常好,但我正在寻找一个更优雅的解决方案。如果没有结果,你就是赢家!非常感谢。您不应该修改局部变量:setattr的使用是您将获得的最优雅、最简单的解决方案。Thnaks balpha是您的答案,但我不喜欢它,因为我忘了提到Car将子类化其他类,我不太喜欢多重继承。但这是
不过,这是个好主意!在这种情况下,多重继承不应该构成问题-只要_CarType只包含您的常量,并且它们不会出现在其他任何地方,我看不到任何MRO的风险。事实上,与我的尝试不同,这回答了这个问题,看起来是最干净的方法。Thnaks balpha为您的答案,但我倾向于不喜欢它,因为我忘了提到Car将子类化其他一些类,我不太喜欢多重继承。不过,这是个好主意!在这种情况下,多重继承不应该造成问题-只要_CarType只包含您的常量,并且它们不会出现在其他任何地方,我看不到任何MRO的风险。事实上,与我的尝试不同,它回答了这个问题,这看起来是最干净的方法。我同意简单比复杂好,这里并不需要元类。然而,作为一个试图理解元类的人,我希望这可能对其他走同样道路的人有用。我同意简单比复杂好,这里并不真正需要元类。然而,作为一个试图理解元类的人,我希望这可能对其他同行有用?这似乎是最简单的解决办法。检查isupper和do getattr\u CarType,键入为什么不能使用uuuu getattr\uuuuu?这似乎是最简单的解决办法。检查isupper并执行getattr_CarType,Keys,您是否尝试过此解决方案?汽车、柴油车、汽车发动机如何工作?self指的是一个已经创建的对象…哎呀,它应该。。。修正了错误。是的,但我需要以静态方式访问类型,所以你的解决方案不起作用。。。这就是为什么我甚至指定getattr对我无效。啊,是的。我不会称之为“以静态方式访问类型”,我认为通常的说法是“通过类访问类型”。不管怎样,我不太明白你想做什么…你有没有尝试过这个解决方案?汽车、柴油车、汽车发动机如何工作?self指的是一个已经创建的对象…哎呀,它应该。。。修正了错误。是的,但我需要以静态方式访问类型,所以你的解决方案不起作用。。。这就是为什么我甚至指定getattr对我无效。啊,是的。我不会称之为“以静态方式访问类型”,我认为通常的说法是“通过类访问类型”。不管怎样,我不明白你想做什么。。。