2017-05-25 63 views
1

從我所瞭解的關於Python面向對象的編程中,如果一個類已經定義了__call__方法,如果我們像使用函數調用一樣使用類的實例,就會調用該方法。例如:__call__類型的方法

class Employee: 
    def __init__(self,name,sal): 
     self.name = name 
     self.salary = sal 
    def __call__(self,value): 
     return self.salary * value 

e = Employee("Subhayan",20000) 
print (e(10)) 

因此,__call__方法將對象實例作爲第一個參數。

我只是想了解Python中的元類,我讀到type是所有用戶定義的類的默認元類。

如果我定義Python中的基本定製元類:

class Meta(type): 
    def __new__(meta, classname, supers, classdict): 
     # Run by inherited type.__call__ 
     return type.__new__(meta, classname, supers, classdict) 

現在按照書中給出的文檔的元類__new__方法將由從類型繼承了__call__方法運行。

現在我的問題是使用任何類的__call__方法,我們必須擁有該類的對象,然後將其作爲函數調用。

這裏我們沒有任何類型的對象使用它的__call__函數。

有人可以請我解釋一下類型類的__call__函數是如何進入圖片的?

回答

0

請記住,type是一個元類,所以它的實例是類,而不是對象。不是方法(除其他事項外),當你做到這一點:

e= Employee(*args,**kwargs) 

要調用Employee.__init__並從元類的一些方法,包括Meta.__call__,同樣的道理,當你做。

print (e(10)) 

您正在調用您的自定義__call__方法。

就拿這個Singleton元類:

class Singleton(type): 
    _instances = {} 
    def __call__(cls, *args, **kwargs): 
     if cls not in cls._instances: 
      cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) 
     return cls._instances[cls] 

class MyClass(BaseClass): 
    __metaclass__ = Singleton 

現在每次創建的MyClass一個新的實例時,在元類的__call__方法之前調用創建實際的實例讓你檢查前一個存在並返回。

希望這會有所幫助。

+0

這裏有一個問題。在Singleton __call__函數內部,cls參數將具有MyClass的值。 _instances屬於Singleton類。那麼MyClass如何擁有_instances字典? –

+0

因爲'MyClass'是'Singleton'的一個實例。 – yorodm

+0

Subhayan:...和所有'Singleton'實例共享相同的'_instances'字典,因爲它是一個類,_not_不是實例,屬性。 – martineau

1

任何類本身都是類型「type」的一個實例 - 因此,「調用」一個類只是調用其類上的方法__call__ - 碰巧類型爲__call__。 的type.__call__的效果是完全: 上類似的代碼:

class A: 
    pass 
b = A() 
  1. type.__call__接收類A本身作爲第一個參數。
  2. 它調用A.__new__ - 以僞代碼的形式,我們可以編寫instace = A.__new__(cls)作爲運行的代碼。
  3. ,返回「A」類的一個實例
  4. 然後在實例(instance.__init__()
  5. 調用__init__ ...並返回該實例return instance

但是,如果類本身是從「類型」派生的,即它是「新」類的實例化,需要採取額外的步驟:魔術__class__變量的特殊值填充在任何類方法中 - 如果其中任何一種方法使用了調用到super。在Python 3.6中,還有另外兩個步驟:調用定義__set_name__方法的任何類屬性,並調用該類的__init_subclass__方法。

+0

我會開一個新的問題,因爲當類本身是從類型派生的時候,我還不清楚。我將在那裏粘貼一個新的代碼,所以請幫助我。 –

+0

另外,直到一個類被創建,它不是一個類型的實例。所以當上面的代碼調用A()時,我可以理解被調用類型的__call__方法。但__new__應該在類語句運行時立即調用。但正如你所提到的__new__正在從__call__中調用。不知道我是否理解正確。 –