微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

对函数的类变量引用更改为 instancemethod

如何解决对函数的类变量引用更改为 instancemethod

我正在尝试通过类变量调用外部函数。以下是我的真实代码的简化:

def func(arg):
    print(arg)

class MyClass(object):
    func_ref = None

    @classmethod
    def setUpClass(cls):
        #MyClass.func_ref = func
        cls.func_ref = func

    @staticmethod
    def func_override(arg):
        print("override printing arg...")
        MyClass.func_ref(arg)

if __name__ == "__main__":
    print(type(func))
    print(type(MyClass.func_ref))
    MyClass.setUpClass()
    print(type(MyClass.func_ref))
    MyClass.func_override("hello!")

以上代码产生以下输出

[~]$ python tmp.py
<type 'function'>
<type 'nonetype'>
<type 'instancemethod'>
override printing arg...
Traceback (most recent call last):
  File "tmp.py",line 20,in <module>
    MyClass.func_override("hello!")
TypeError: func_override() takes exactly 2 arguments (1 given)

如果我在 classmethod MyClass 中使用 cls 代替 setUpClass(),情况似乎没有改变。

我希望 MyClass.func_ref 的类型在 function 中的赋值之后是 setUpClass(),这解释了我尝试调用它时得到的 TypeError。当我分配给它的值是 func_ref 类型时,为什么将 instancemethod 的类型更改为 function

这似乎只是 Python 2 中的一个问题。Python 3 的行为符合我的预期。

如何调用静态方法 MyClass.func_override()调用 func()

更新

通过应用以下补丁,我能够使上述内容正常工作:

@@ -14,7 +14,7 @@ class MyClass(object):
     def func_override(arg):
         print("override printing arg...")
         func(arg)
-        MyClass.func_ref.__func__(arg)
+        MyClass.func_ref(arg)

 if __name__ == "__main__":
     print(type(func))

虽然上述方法有效,但我完全不清楚为什么我需要这样做。我仍然不明白为什么 func_ref 的类型在我为其分配了类型为 instancemethod 的值时以 function 结束。

解决方法

只需将函数通过 staticmethod 如下:

    @classmethod
    def setUpClass(cls):
        #MyClass.func_ref = func
        cls.func_ref = staticmethod(func)

在这种情况下不需要使用基于 @ 的装饰器,因为您想修改方法绑定到 MyClass 的方式,而不是 func 的一般定义。

为什么需要这样做?因为,当您将方法分配给类时,Python 假定您要引用实例(通过 self)或类(通过 cls)。 self 与 JS 中的 this 不同,它只是一个命名约定,因此当它看到 arg 时,它假定它有一个实例,但您在调用中传递了一个字符串。

因此,正如 Python 所关心的那样,您也可以编写 def func(self):。这就是消息显示 unbound method func() must be called with MyClass ?instance? as first argument 的原因。

staticmethod 的意思是,“请不要管它,不要在第一个变量中假设一个实例或一个类”。

您甚至可以省去setUpClass entirely

class MyClass(object):
    func_ref = staticmethod(func)

顺便说一句:在 2021 年,即 EOL 后的 16 个月,Python 2.7 具有发霉的运动袜的所有微妙气味。除了不太安全,从病毒学角度来说。

,

当调用 func_ref 时,它需要一个 self 参数,就像任何其他普通(实例)类方法一样(有关原因的讨论,请参阅 this question and answers)。您可以向 self 添加 func 参数或使 func 成为静态方法:

@staticmethod
def func(arg):
    print(arg)

>>> MyClass.setUpClass()
>>> MyClass.func_override("hello!")
override printing arg...
hello!

请注意,在这两种情况下,func 现在通常不能作为常规函数调用:

>>> func('what does this do?')
TypeError: 'staticmethod' object is not callable

如果您需要将 func 用作常规函数,您可以用另一个合格的函数包装它并在 MyClass 中使用包装器:

def func(arg):
    print(arg)

@staticmethod
def func_wrapper(arg):
    func(arg)

class MyClass(object):
    @classmethod
    def setUpClass(cls):
        cls.func_ref = func_wrapper  # use wrapper function

>>> MyClass.setUpClass()
>>> MyClass.func_override("success!")
override printing arg...
success!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。