我正在嘗試使用PEP 3115(即,可以按聲明順序訪問其成員的類)中描述的'ordered class'。給出的實現是Python 3中的有序類
# The custom dictionary
class member_table(dict):
def __init__(self):
self.member_names = []
def __setitem__(self, key, value):
# if the key is not already defined, add to the
# list of keys.
if key not in self:
self.member_names.append(key)
# Call superclass
dict.__setitem__(self, key, value)
# The metaclass
class OrderedClass(type):
# The prepare function
@classmethod
def __prepare__(metacls, name, bases): # No keywords in this case
return member_table()
# The metaclass invocation
def __new__(cls, name, bases, classdict):
# Note that we replace the classdict with a regular
# dict before passing it to the superclass, so that we
# don't continue to record member names after the class
# has been created.
result = type.__new__(cls, name, bases, dict(classdict))
result.member_names = classdict.member_names
return result
class MyClass(metaclass=OrderedClass):
# method1 goes in array element 0
def method1(self):
pass
# method2 goes in array element 1
def method2(self):
pass
有幾件事我很困惑。首先,__prepare__
是classmethod
的原因是什麼?該定義不使用metacls
- 這只是一個約定?
其次,當我嘗試此代碼,'__module__'
最終在MyClass.member_names
'method1'
和'method2'
之前,顯然與該權利要求'method1'
是第一要素的評論。爲什麼這個特殊的屬性會出現在列表中,而沒有其他的屬性呢?有沒有其他人可能會讓我感到驚訝(除了__doc__
,如果該類有一個文檔字符串,並且我明確定義)?
最後,此實現不從基類檢索member_names
。如果我想達到這個目的,那麼對__prepare__
進行如下更改會有什麼不妥(除了不檢查重複的事實)嗎?
@classmethod
def __prepare__(metacls, name, bases):
prep_dict = member_table()
for base in bases:
try:
prep_dict.member_names.extend(base.member_names)
except AttributeError:
pass
return prep_dict
'__prepare__'將與2個參數一起使用,但當被稱爲MyClass .__ prepare__'時,它將作爲MyClass的方法綁定。無論你是否會這樣做,最好將它綁定到元類並使用第一個參數來獲取'mcls'實例。我想你可以把它變成一個「靜態方法」。 – eryksun
PEP表示「在評估類體之前,將」__prepare__「屬性作爲函數調用」。所以它必須是classmethod或staticmethod,而不是實例方法,因爲此時尚未調用(實例化)元類。 – yak
感謝eryksun和犛牛,但我不確定自己完全理解 - 我想我對'classmethod'確實有什麼天真的想法。我明白,如果'__prepare__'沒有被聲明爲'classmethod',它接收'name'和'bases'作爲參數,而如果它是'classmethod'它也會接收這個類 - 但是classmethod有什麼其他效果在這種情況下?另外,爲什麼從元類繼承的方法不會出現在'dir(MyClass)'中? – James