這裏是一個元類來做你想做的(我認爲)。它通過將要繼承的方法存儲在字典中並將其手動插入到新的類字典中來工作。它還存儲傳遞給namedtuple
構造函數的屬性字符串,並將其與子類中的屬性字符串合併。然後它將其傳遞給namedtuple
,並返回一個類,該類從其結果的namedtuple
中繼承,並在其字典中包含所有適當的方法。因爲元類派生自abc.ABCMeta
,所以您可以免費獲得工作類型檢查。以下是如何構建幾個類的樣子:
class Foo(object):
__metaclass__ = ImmutableMeta
_attributes_ = 'a b'
def sayhi(self):
print "Hello from {0}".format(type(self).__name__)
class Bar(Foo):
_attributes_ = 'c'
def saybye(self):
print "Goodbye from {0}".format(type(self).__name__)
這裏的元類:
import collections as co
import abc
class ImmutableMeta(abc.ABCMeta):
_classes = {}
def __new__(meta, clsname, bases, clsdict):
attributes = clsdict.pop('_attributes_')
if bases[0] is object:
# 'new' class
methods = clsdict
else:
# we're 'inheriting' from an existing class
base = bases[0]
attributes = meta._classes[base]['attributes'] + ' ' + attributes
base_methods = meta._classes[base]['methods'].copy()
base_methods.update(clsdict)
methods = base_methods
# construct the actual base class and create the return class
new_base = co.namedtuple(clsname + 'Base', attributes)
cls = super(ImmutableMeta, meta).__new__(meta, clsname, (new_base,),
methods)
# register the data necessary to 'inherit' from the class
# and make sure that it passes typechecking
meta._classes[cls] = {'attributes': attributes,
'methods': methods}
if bases[0] is not object:
base.register(cls)
return cls
下面是一些微不足道的測試代碼。
a = Foo(1, 2)
a.sayhi()
b = Bar(1, 2, 3)
b.sayhi() # 'inherited' from class Foo
b.saybye()
try:
b.c = 1 # will raise an AttributeError
except AttributeError:
print "Immutable"
print "issubclass(Bar, Foo): {0}".format(issubclass(Bar, Foo))
try:
d = {b: 1} # No problems
except TypeError:
print "Cant put it in a dict"
else:
print "Can put it in a dict"
希望有所幫助。如果您不希望將每種方法都附加到應該繼承它的每個類,則還可以提供默認的__getattr__
,該元素通過元類字典進行查找並找到適當的方法。這需要以某種方式將基類硬編碼到方法中,可能使用閉包。
我從來沒有做到這一點,它目前給我麻煩,但我知道你通過使用__new__而不是__init__來做任何修改。當我弄明白的時候我會發布。 – aaronasterling 2010-10-11 08:05:42
是的,我知道你可以用'__new__'繼承'tuple',但是我也想要命名的字段。 – detly 2010-10-11 08:07:02
你需要能夠使用issubclass測試它們嗎? – aaronasterling 2010-10-11 08:48:10