[python] Bound method or Function

5763 ワード

まずコードを見てみましょう
#!/usr/bin/env python

# encoding: utf-8



class Foo(object):

	pass

	

def func():

	pass	

		

if __name__ == "__main__":

	Foo.method = func

	f = Foo()

	print Foo.method

	print f.method

	print func


コードは非常に簡単で、結果は次のとおりです.

>

この結果を見ると、同じ方法でunbound method/bound methodを出力したり、functionを出力したりするのではないかと悩んでいます.
この理由を理解するにはpythonのdescriptorから話さなければなりません.
まず、descriptorとは何ですか?
“The following methods only apply when an instance of the class containing the method (a so-called descriptor class) appears in the class dictionary of another new-style class, known as the owner class. ”
ここでfollowing methodsとは、次の3つの方法を指します.
  • object.__get__(self, instance, owner) Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner. This method should return the (computed) attribute value or raise an AttributeError exception.
  • object.__set__(self, instance, value) Called to set the attribute on an instance instance of the owner class to a new value, value.
  • object.__delete__(self, instance) Called to delete the attribute on an instance instance of the owner class.

  • descriptorでは、指包には_が含まれています.get__方法のdescriptorはnon-overriding descriptorと呼ばれています.同時に__を含む場合get__,__set__, 私たちはoverriding descriptorと呼ばれています. 
    descriptorは何の役に立ちますか?
    class OverridingDescriptor(object):
    
    	
    
    	def __init__(self, value= "Data value"):
    
    		self._value = value
    
    		
    
    	def __get__(self, obj, type = None):
    
    		print self, obj, type
    
    		return self._value
    
    		
    
    	def __set__(self, obj, value):
    
    		print self, obj, value
    
    		self._value = value
    
    	
    
    class Foo(object):
    
    	name = OverridingDescriptor()	
    
    
    
    if __name__ == "__main__":
    
    	print Foo.name
    
    	Foo.name ="smith"
    
    	print Foo.name
    
    

    まず最初の文を見てみましょうnameの出力:
    <__main__.Descriptor object at 0x100510510> None No-data value
    Descriptorを直接呼び出したのは明らかです.get__方法.pythonのpropertyがobject属性にパッケージを提供していることはよく知られていますが、ここではdescriptorがobject自体のパッケージを提供しているのではないでしょうか.次に分析すると、2番目の文のコードは出力されていないことがわかりました.最後の文のコードの出力は次のとおりです.
    smith
    つまりここでdescriptorを呼び出す_はありませんset__方法、これはまたどうしてですか?ここではpythonのdescriptorに対する検索ポリシー、pythonのdescriptorに対する_get__/__set__また、2つの異なる戦略を採用しました.
  • 対_get__, もし私たちがobjにアクセスするなら.v(ここのobjはclassでもinstanceでもよい).

  •  
  • pythonはまずobjを検査する.class__dict__vが含まれているかどうか(pythonではclassもオブジェクトであり、classオブジェクトの__class__は一般的にtypeであることに注意してください)、vが見つかり、vがoverriding descriptorである場合、overriding descriptorの_を呼び出します.get__方法.見つからない場合はobj._class__に表示されます.次のステップ
  • が見つからなかったら
  • このステップpythonはclassとinstanceをそれぞれ扱います.Instanceの場合、pythonはobject._をチェックします.dict__存在するかどうかは、見つかったら直接戻ればいいです.classの場合、pythonはobject._を順次チェックします.dict__とobjectの親の_dict__vが存在するかどうか、vがdescriptorである場合に呼び出される_get__, それ以外の場合はobject._を返します.dict__['v']この時点でまだ見つからない場合は、次の
  • に進みます.
  • pythonがobj._に戻るclass__.__dict__で、obj._を順に検索します.class__の親_dict__, しかし、今回探したのはoverriding descriptorではなくdescriptor(overriding descriptorではないかもしれません.そうしないと最初のステップが見つかります)、vがdescriptorであれば呼び出します.get__,通常のプロパティが見つかった場合は、直接戻ります.まだ見つからない場合はAttributeError
  • 対_set__,同じようにobjに渡すと仮定します.v賦値
  •  
  • pythonまずobj._を順番にチェックしますclass__.__dict__とobj._class__親_dict__, vが見つかり、vがoverriding descriptorである場合、その__が呼び出されます.set__, そうでなければ、次のステップ
  • に進みます.
  • このときpythonはobj._dict__[‘v’〕直接賦課
  • これらの検索ポリシーの検証は、紙面に鑑みて検証されません.興味のある友達は自分で検証してもいいです.ヒントとして、これらのポリシーの実行は、最初の使用時に適用されます.つまり、classの定義時に(例えば__init_)class定義が完了した後にclassを使用するときに適用するのではなく、適用します.
    そういえば、こんなにたくさんのdescriptor.いったいdescriptorは文初の問題と何の関係があるのだろうか.function自体がdescriptor(pythonではfunctionもオブジェクト)です.では、instanceまたはclassのメソッドにアクセスすると、functionの__を呼び出すのではないでしょうか.get__どうですか.
    	print func.__get__(None, Foo)
    
    	print func.__get__(f, Foo)
    
    

    出力の結果とFooを発見しましたmethod/f.methodの一致は,我々の考えが正しいことを証明した.
    さらに分析すると
    print id(Foo.method)
    
    print id(f.method)
    
    print id(func)
    
    

    出力は次のとおりです.
    429963857642996385764299376592
    私たちはFooを見た.methodとf.methodが返すオブジェクトidとfunctionのオブジェクトidは異なります.ではこれget__いったい何をしたら、対象idが変わるのでしょうか.
    print func.__get__
    
    

    出力:
    このfunctionの_get__method-wrapperですね.つまり、instanceまたはclassでmethodを呼び出すと、functionのwrapperが返されます.
    さらに、
    print Foo.__dict__['method']
    
    

    pythonにfunction descriptorの__を呼び出させないget__, やはり返された結果は直接print funcとそっくりです.
    では、このmethod-wrapperはいったいinstance、class、および呼び出されたfunctionとどのように関連しているのでしょうか.
    print f.method.im_func
    
    print f.method.im_self
    
    print f.method.im_class
    
    

    出力:
    <__main__.Foo object at 0x100475f90>
    はっきりとim_が見えますfuncはfunction,im_を指すselfは呼び出したinstancを指し(classでこの3つの文を実行するとFoo.method.im_selfはNoneを返す)、im_classはclassを指します.
    bound method/unbound methodとfunctionの解析によりpythonにおけるdescriptorという非常に重要な概念も理解した.私たちはpythonの学習の道で堅固な一歩を踏み出した.