[英]What is a wrapper_descriptor, and why is Foo.__init__() one in this case?
[英]Python 2/3: Why is type(Foo.__init__) different?
考慮一下類:
Foo(object):
def __init__(self):
pass
在Python 2上執行type(Foo.__init__)
Python 2.7.5 (default, Mar 9 2014, 22:15:05)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo(object):
... def __init__(self):
... pass
...
>>> type(Foo.__init__)
<type 'instancemethod'>
在Python 3上執行type(Foo.__init__)
Python 3.4.1 (default, May 19 2014, 13:10:29)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class Foo(object):
... def __init__(self):
... pass
...
>>> type(Foo.__init__)
<class 'function'>
為什么在Python 2和3上type(Foo.__init__)
的返回值不同?
如果您要詢問更改了什么 ,則簡短版本位於3.0的新功能中 :
語言中刪除了“未綁定方法”的概念。 現在將方法作為類屬性引用時,您將獲得一個普通的函數對象。
更詳細地:
函數對象是描述符,其__get__
返回方法。 在Python 2.x中,它看起來像這樣(在純Python偽代碼中,略有簡化):
class FunctionType(object):
# other stuff
def __get__(self, instance, cls):
return MethodType(func=self, instance=instance, cls=cls)
class MethodType(object):
def __init__(self, func, instance, cls):
self.__func__, self.__instance__, self.__class__ = func, instance, cls
def __call__(self, *args, **kwargs):
if self.__self__ is not None:
return self.__func__(self.__self__, *args, **kwargs)
else:
return self.__func__(*args, **kwargs)
因此,當您編寫Foo.__init__
,您將獲得未綁定的方法MethodType(__init__, None, Foo)
。
在3.x中,它看起來像這樣:
class FunctionType(object):
# other stuff
def __get__(self, instance, cls):
if instance is not None:
return MethodType(func=self, instance=instance)
else:
return self
class MethodType(object):
def __init__(self, func, instance):
self.__func__, self.__instance__, self.__class__ = func, instance, type(instance)
def __call__(self, *args, **kwargs):
return self.__func__(self.__self__, *args, **kwargs)
有關完整詳細信息,請參閱“可調用類型”下的3.x與2.x的參考文檔中的標准層次結構。
如果您要問為什么更改了它……據我所知,對此並沒有太多的討論—沒有PEP,也沒有關於python-dev或-ideas等的長期討論,並且僅給出了在文檔中一行。
但是推理似乎很明顯。 未綁定的方法並不是特別有用。 它們只是額外的腳手架,提供與它們包裝的功能完全相同的行為。*它們僅在2.2-2.7中存在,以更好地對經典類的行為進行建模**,並且/或者因為似乎更容易實現該方式和/或因為在設計初期,尚不清楚是否可以在沒有它的情況下實現@classmethod
東西,並且當Guido變得足夠多以至於意識到那里沒有問題時,離開設計變得更容易,因為他是最初寫的。
*綁定方法的CPython實現添加了一個isinstance
檢查,以驗證第一個參數是self.__class__
,但是沒有明確記錄,沒有人依賴它編寫代碼,並且它對調試的幫助不如您會期望的。
**如果您想知道經典類為什么會如此工作,那么您必須瀏覽Guido的Python History博客-如果有時間,所有這些都值得一讀。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.