【问题标题】:Python function pointer in class __init____init__ 类中的 Python 函数指针
【发布时间】:2013-08-15 22:41:00
【问题描述】:

在下面的代码中,类 A 有一个成员函数,它被设置为指向在类之外定义的函数。 在类 B 中,相同的函数被设置到类定义中的外部指针。 为 A 类型的对象调用函数将失败,因为 self 没有传递给函数。但是对于 B,自我通过了。 为什么 B 可以通过 self ,而 A 不能通过 self?

def f1(s,a):
    print s
    print a

class A(object):
    def __init__(self):
        self.fp1 = f1

class B(object):
    fp1 = f1

a=A()
b=B()
try:a.fp1("blaa")
except Exception, e: print `e` 
try:b.fp1("bluu")
except Exception, e: print `e` 

输出:

TypeError('f1() takes exactly 2 arguments (1 given)',)
<__main__.B object at 0x2ab0dacabed0>
bluu

【问题讨论】:

    标签: python function pointers init


    【解决方案1】:

    当您执行self.fp1 = f1 时,您只是将一个函数分配给A 类的实例变量。所以当你调用它时,你必须传递两个参数。

    当你这样做时:

       class B(object):
           fp1 = f1
    

    在类B的创建过程中,python在类范围内找到了一个函数fp1并从中创建了一个instancemethod(将名称为fp1的变量替换为从该函数创建的instancemethod它之前举行过)。当您在对象上调用 instancemethod 时,self 会自动作为第一个参数传递。

    您可以通过键入以下内容进行检查:

    >>> a = A()
    >>> b = B()
    >>> type(a.fp1)
    function
    >>> type(b.fp1)
    instancemethod
    

    【讨论】:

      【解决方案2】:

      A 类中,您将函数绑定到实例。这实际上可以被视为“函数指针”,因此必须显式传递所有参数。在B 类中,您将函数绑定到将导致函数作为方法工作的类。您可以将类定义 A 修改为

      class A(object):
          def __init__(self):
              A.fp1 = f1
      

      具有相同行为的类 B,即所有实例中的 fp1 指向 f1,或者您可以包装 f1

      class A(object):
          def __init__(self):
              self.fp1 = lambda a: f1(self, a)
      

      这将允许为每个实例单独更改fp1。后一种变体可能正是您要寻找的。​​p>

      【讨论】:

        【解决方案3】:

        使instance.method(...) 等同于Class.method(instance, ...) 的魔力取决于作为类属性的函数对象。细节各不相同(以及它们,您可以创建这种方法的丑陋解决方法)。在 Python 3 中,所有函数都是descriptors。在 Python 2 中,有一些特殊的 unbound method 对象被隐式创建以包装存储为类属性的函数,并大致完成 Python 3 中所有函数自己所做的事情。

        在任何一种情况下,通过实例访问它都会创建一个绑定方法,该方法在调用时将实例作为第一个参数传递。在任何一种情况下,通过实例属性访问的函数都没有什么特别之处,它只是另一个可以传递和使用的对象。

        您可以通过使用partial(有点泄漏的抽象)来实现类似的行为:

        from functools import partial
        # in __init__
        self.fp1 = partial(f1, self)
        

        或者通过创建一个委托的方法:

        def __init__(self):
            self._fp1 = f1
        
        def fp1(*args, **kwds):
            return self._fp1(self, *args, **kwds)
        

        【讨论】:

          【解决方案4】:

          在第一种情况下,您在类中创建一个字段,其中存储了一个方法对象。所以“a.fp1”不是一个方法调用,因此“a”没有作为第一个参数。这是一个方法对象的检索,然后调用它。

          第二种情况,可以参考documentation

          任何作为类属性的函数对象都定义了一个方法 该类的实例。

          因此,对于 b,“fp1”成为类 b 实例的方法。

          你可以在这里找到更详细的解释:method objects vs function objects , Python class instances vs class

          【讨论】:

            猜你喜欢
            • 2013-12-21
            • 1970-01-01
            • 2016-01-18
            • 2011-01-17
            • 1970-01-01
            • 2018-02-06
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多