污染一个阶级的环境

时间:2010-01-06 11:52:19

标签: python oop

我有一个对象,它包含许多静态访问的ID。我想把它拆分成另一个只包含那些id的对象,而不需要对已经存在的代码库进行修改。举个例子:

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

class Car(object):
    types = _CarType

我希望能够通过_CarType.DIESEL_CAR_ENGINE调用Car.types.DIESEL_CAR_ENGINE来访问Car.DIESEL_CAR_ENGINE,以便向后兼容现有代码。很明显我不能使用__getattr__所以我试图找到一种方法来完成这项工作(也许是元类?)

5 个答案:

答案 0 :(得分:4)

虽然这不完全是为子类化做的,但它完成了你所描述的内容:

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

class Car(_CarType):
    types = _CarType

答案 1 :(得分:3)

类似的东西:

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

答案 2 :(得分:2)

这是使用元类执行此操作的方法:

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)

答案 3 :(得分:2)

您的选项分为两大类:您可以将_CarType中的属性复制到Car,或将Car的元类设置为__getattr__的自定义类别委托给_CarType的方法(所以你不能使用__getattr__并不完全正确:你可以,只需要输入Car类而不是Car本身; - )。

第二种选择具有您可能会发现的特殊含义(除非特别需要):属性不会显示在dir(Car)上,无法访问它们<{1}}的实例,仅在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' 添加__getattr__来修复“非实例”问题:

Car

使这两种查找工作正如预期的那样:

>>> class Car:
...   __metaclass__ = MetaGetattr
...   types = _CarType
...   def __getattr__(self, nm):
...     return getattr(self.types, nm)
... 

但是,定义两个,基本上相等>>> Car.GAS_CAR_ENGINE 1 >>> Car().GAS_CAR_ENGINE 1 s,看起来并不优雅。

所以我怀疑更简单的方法,“复制所有属性”,更可取。在Python 2.6或更高版本中,这是类装饰器的明显候选者:

__getattr__

一般情况下,如果你不止一次使用它,那么定义装饰器是值得的;如果你只需要为一个类执行此任务,那么改为内联代码(在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 语句之后)可能会更好。

如果您坚持使用Python 2.5(甚至2.4),您仍然可以用同样的方式定义class,只需将它应用于稍微不那么优雅的事物,即typesfrom定义变为:

Car

请记住装饰器语法(在2.2中为函数引入,在2.6中为类引入)只是一种方便的方式来包装这些重要且经常重复的语义。

答案 4 :(得分:0)

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

class Car:
  types = _CarType
  def __getattr__(self, name):
    return getattr(self.types, name)

如果未找到对象的属性,并且它定义了该魔术方法__getattr__,则会调用该方法以尝试找到它。

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