2014-06-15 65 views
2

我有一個我希望註冊的類層次結構,以便以後可以訪問它。到目前爲止,我一直在做手工:如何在評估Python類時運行代碼

class FirstClass(MyBaseClass): 
    .... 
registry.register(FirstClass) 

class SecondClass(FirstClass): 
    .... 
registry.register(SecondClass) 

我正在尋找一種方法來調用registry.register(Class)類時評估(即,當有人導入包類),而不必調用它明確。

我想我必須添加一些東西到MyBaseClass,但我無法弄清楚什麼。所有特殊方法似乎都與實例相關,而不是與類有關。

有沒有辦法做到這一點?

說明: 註冊表跟蹤從BaseClass派生的類。在代碼的某個地方,我會遍歷所有這些類並實例化對象。這有點複雜,因爲註冊管理機構也在做其他事情,但這是主要想法。

+1

只是一個小點,但你想要的是上課的時候被評估,而不是在它的聲明(其宣稱只有一次,當你寫它)。 –

+0

你能分享一下更多的代碼嗎?什麼是註冊表,它在哪裏聲明,它在幹什麼? – timgeb

+0

@Burhan Khalid - 謝謝,我修正了措詞。 – zmbq

回答

2

這是正是是什麼元類爲:申請的操作的整個類層次結構:

In [1]: def register(cls): 
    ...:  # just to show when it is called. 
    ...:  print('Register: {}'.format(cls)) 
    ...: 
    ...: 
    ...: class MyMeta(type): 
    ...:  def __new__(cls, name, bases, attrs): 
    ...:   the_cls = super().__new__(cls, name, bases, attrs) 
    ...:   register(the_cls) 
    ...:   return the_cls 

In [2]: class FirstClass(metaclass=MyMeta): 
    ...:  pass 
    ...: 
Register: <class '__main__.FirstClass'> 
In [3]: class SecondClass(FirstClass): 
    ...:  pass 
    ...: 
Register: <class '__main__.SecondClass'> 

請注意,您必須只在層次結構的根加元類,這將是在所有子類中繼承,因此您只需將其添加爲MyBaseClass即可完成。

對於深入說明請參閱本SO問題:What is a metaclass in Python?


我用python3語法。在python2加元類,你必須設置__metaclass__屬性:

class MyClass(object): 
    __metaclass__ = MyMeta 

我想指出的是得到一個類的子類可以使用__subclasses__方法。有沒有必要跟蹤它們的明確,不使用自定義的元類:

In [4]: FirstClass.__subclasses__() 
Out[4]: [__main__.SecondClass] 
+0

元類! Python絕對規則。 – zmbq

0

我最近的項目需要跟蹤類,我最初的方法是使用globals()或類似的東西來查找類,但是irc.freenode.org#python的pythonistas建議使用像這樣的裝飾器和它看起來非常Python化:

registry = {} 
def registered(cls): 
    registry[cls.__name__] = cls 
    return cls 

@registered 
class Foo: 
    """ 
    """ 
@registered 
class Bar: 
    """ 
    """ 

在導入此文件,file.registry將它裏面的所有的類和你同CAL註冊表[「CLASS_NAME」]查找。在我們的用例中,我們根據配置的Class_Name選擇了我們的類實現。

+0

這與我原來的方法類似。有時候我(或圖書館的其他用戶)忘記了這個問題,並導致不必要的錯誤。 – zmbq

2

用Python object自動保持任何新的樣式類(類的直接子類中的軌道作爲其基類或基這樣派生的類)定義在名爲__subclasses__的類屬性中。這意味着您不必親自手動註冊它們。

要獲得完整的繼承層次結構,您需要遞歸地收集每個子類的屬性中的內容。這就是我的意思是:

class MyBaseClass(object): pass 
class FirstClass(MyBaseClass): pass 
class SecondClass(FirstClass): pass 

def get_subclasses(cls): 
    return cls.__subclasses__() + [g for s in cls.__subclasses__() 
            for g in get_subclasses(s)] 

print(get_subclasses(MyBaseClass)) 

輸出:

[<class '__main__.FirstClass'>, <class '__main__.SecondClass'>]