上一篇文章我們詳細解釋瞭如何利用元類來控制類的建立,下面我們利用元類來控制例項的建立:
在此之前我們先來理解一下python的一些內建函式init 、new、__call__的一些用法,這樣才能更好的理解建立例項的過程:
- new(cls, args, *kwargs) 建立物件時呼叫,返回當前物件的一個例項;注意:這裡的第一個引數是cls即class本身
- init(self, args, *kwargs) 建立完物件後呼叫,對當前物件的例項的一些初始化,無返回值,即在呼叫new之後,根據返回的例項初始化;注意,這裡的第一個引數是self即物件本身【注意和new的區別】
- call(self, args, *kwargs) 如果類實現了這個方法,相當於把這個型別的物件當作函式來使用,相當於 過載了括號運算子
下面我們來看一下程式碼演示,更加清晰明瞭:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Test(object): def __init__(self, *args, **kwargs): print "init" super(Test, self).__init__(*args, **kwargs) def __new__(cls, *args, **kwargs): print "new", cls return super(Test, cls).__new__(cls, *args, **kwargs) def __call__(self, *args, **kwargs): print "call" test= Test() print "________" test() |
列印出來的結果:
1 2 3 4 |
new init ________ call |
由此可以清晰的看出來類例項建立的過程,首先呼叫的是new,然後是init初始化,然後當我們使用類作為函式時,這時候會呼叫call方法。
再理解上面一段內容的基礎上,我們來進行例項建立的控制,先來編寫一個簡單的類:
1 2 3 4 5 6 |
class SimpleClass: def __init__(self, name): self.name = name a = SimpleClass("job") b = SimpleClass("kevin") |
在這個例子基礎上我們進行改造,使用元類來影響例項的生成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class NoInstances(type): def __call__(self, *args, **kwargs): raise TypeError("Can't instantite directlyl") class Spam(): __metaclass__=NoInstances @staticmethod def test(x): print("Spam.test") >>> Spam.test(1) 1 >>> s = Spam() Traceback (most recent call last): File "<pyshell#21>", line 1, in <module> s = Spam() File "<pyshell#10>", line 3, in __call__ raise TypeError("can not instantite directly") TypeError: can not instantite directly |
這裡我們利用元類來控制例項的生成,使其只可以呼叫靜態方法,而不能建立類的例項。
這節就先到這裡,下一節我們承接這節的應用,繼續深入理解,感謝大家閱讀。