【问题标题】:Different way to create an instance method object in Python在 Python 中创建实例方法对象的不同方法
【发布时间】:2016-09-19 03:05:56
【问题描述】:

Python 3.x 语言参考描述了两种创建方法对象的方法:

如果该属性是用户定义的函数对象或类方法对象,则可以在获取类的属性时(可能通过该类的实例)创建用户定义的方法对象。

当通过实例之一从类中检索用户定义的函数对象来创建实例方法对象时,它的 self 属性是实例,并且方法对象被称为绑定。新方法的 func 属性是原来的函数对象。

当通过从类或实例中检索另一个方法对象来创建用户定义的方法对象时,其行为与函数对象相同,只是新实例的 func 属性不是原始方法对象而是它的 func 属性。

当一个实例方法对象被调用时,底层函数(func)被调用,将类实例(self)插入到参数列表的前面。例如,当 C 是一个包含函数 f() 定义的类,而 x 是 C 的一个实例时,调用 x.f(1) 等效于调用 C.f(x, 1)。

当实例方法对象派生自类方法对象时,存储在self中的“类实例”实际上就是类本身,因此调用xf(1)或Cf(1 ) 等价于调用 f(C,1),其中 f 是底层函数。

在不同的方面,它们都有不同的__func____self__ 值,但我不太了解这两种不同的方式,谁能给我解释一下?

Python 语言参考 |标准类型层次结构: https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy

【问题讨论】:

    标签: python python-3.x methods attributes instance


    【解决方案1】:

    我不能 100% 确定我完全理解你的问题,但也许看一个例子会有所帮助。首先,让我们创建一个在定义中具有函数的类:

    >>> class Foo(object):
    ...   def method(self):
    ...     pass
    ... 
    >>> f = Foo()
    

    获取类的属性时可以创建用户定义的方法对象(可能通过该类的实例),如果该属性是用户定义的函数对象或类方法对象.

    好的,所以我们可以通过访问实例上的属性来创建一个方法对象(如果该属性是一个函数)。在我们的设置中,f 是类 Foo 的一个实例:

    >>> type(f.method)
    <class 'method'>
    

    与访问上的方法属性比较:

    >>> type(Foo.method)
    <class 'function'>
    

    当通过实例之一从类中检索用户定义的函数对象来创建实例方法对象时,其 __self__ 属性就是该实例,并且该方法对象被称为已绑定。新方法的 __func__ 属性是原来的函数对象。

    这只是告诉我们实例方法上存在哪些属性。让我们来看看:

    >>> instance_method = f.method
    >>> instance_method.__func__ is Foo.method
    True
    >>> instance_method.__self__ is f
    True
    

    所以我们看到方法对象有一个__func__ 属性,它只是对实际Foo.method 函数的引用。它还有一个 __self__ 属性,它是对 instance 的引用。

    当一个实例方法对象被调用时,底层函数(func)被调用,将类实例(self)插入到参数列表的前面。例如,当 C 是一个包含函数 f() 定义的类,而 x 是 C 的一个实例时,调用 x.f(1) 等效于调用 C.f(x, 1)。

    基本上,参考我们上面的例子,这只是说如果:

    instance_method = f.method
    

    然后:

    instance_method(arg1, arg2)
    

    执行以下操作:

    instance_method.__func__(instance_method.__self__, arg1, arg2)
    

    【讨论】:

      【解决方案2】:

      为了完整起见并作为对@mgilson 提供的出色答案的补充,我想解释原始问题中引用的其余 2 段。

      首先让我们创建一个带有classmethod的类:

      >>> class Foo(object):
      ...   @classmethod
      ...   def cmethod(cls):
      ...     pass
      ... 
      >>> f = Foo()
      

      现在是第 3 段:

      当通过从类或实例中检索另一个方法对象来创建用户定义的方法对象时,其行为与函数对象相同,只是新实例的 func 属性不是原始方法对象而是它的 func 属性。

      这意味着:

      >>> class_method = f.cmethod
      >>> class_method.__func__ is Foo.cmethod.__func__
      True
      >>> class_method.__self__ is Foo
      True
      

      请注意,__self__ 是对 Foo 类的引用。最后,最后一段:

      当实例方法对象派生自类方法对象时,存储在self中的“类实例”实际上就是类本身,因此调用xf(1)或Cf(1)相当于调用f( C,1) 其中 f 是底层函数。

      这只是说以下所有内容都是等效的:

      >>> f.cmethod(arg1, arg2)
      >>> Foo.cmethod(arg1, arg2)
      >>> f.cmethod.__func__(Foo, arg1, arg2)
      >>> Foo.cmethod.__func__(Foo, arg1, arg2)
      >>> f.cmethod.__func__(f.cmethod.__self__, arg1, arg2)
      >>> Foo.cmethod.__func__(Foo.cmethod.__self__, arg1, arg2)
      

      【讨论】:

        猜你喜欢
        • 2022-11-24
        • 2010-10-15
        • 1970-01-01
        • 2018-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-24
        相关资源
        最近更新 更多