我有一个对象,它包含许多静态访问的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__
所以我试图找到一种方法来完成这项工作(也许是元类?)
答案 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实例,而不适用于该类。