我想知道为什么我的类使用参数调用引用的函数(赋值给静态类变量)。如果我将函数引用分配给普通的类变量,它就像预期的那样工作。
这是我的示例代码:
# This function is not editable, because it's imported from an API
def getStuff():
print "I do my stuff!!!"
class foo(object):
GET_STUFF = getStuff
def __init__(self):
print "static var: ",self.GET_STUFF
self.GET_STUFF()
print "outer func: ",getStuff
foo()
这会出现以下错误:
outer func: <function getStuff at 0x0000000003219908>
static var: <bound method foo.getStuff of <__main__.foo object at 0x00000000030AB358>>
Traceback (most recent call last):
File "C:/example.py", line 13, in <module>
foo()
File "C:/example.py", line 10, in __init__
self.GET_STUFF()
TypeError: getStuff() takes no arguments (1 given)
要解决此问题,我将构造函数中的函数引用指向类变量:
class foo(object):
def __init__(self):
self.GET_STUFF = getStuff
print "static var: ",self.GET_STUFF
self.GET_STUFF()
结果与预期的一样好,工作正常:
outer func: <function getStuff at 0x000000000331F908>
static var: <function getStuff at 0x000000000331F908>
I do my stuff!!!
可是:
我想使用静态类变量,因为它使得它易于阅读并且易于为不同的API设置。所以最后我会想出一些包装类,如下所示:
from API01 import getStuff01
from API02 import getStuff02
# bar calculates stuff object from the API (it calls GET_STUFF)
# and stores the object into self.stuff
import bar
class foo01(bar):
GET_STUFF = getStuff01
def DoSomething(self, volume):
self.stuff.volume = volume
class foo02(bar):
GET_STUFF = getStuff02
def DoSomething(self, volume):
self.stuff.volume = volume
# [...] and so on..
有没有办法以我想要设置我的包装类的方式使它工作,或者我真的必须为每个包装类定义一个构造函数吗?
由于
答案 0 :(得分:3)
错误的原因是
self.GET_STUFF()
实际上意味着
tmp = getattr(self, 'GET_STUFF')
tmp(self)
这意味着这两个类是等价的:
def foo(self): pass
class Foo(object):
a = foo
class Bar(object):
def a(self): pass
在这两种情况下,函数对象作为成员添加到类中,这意味着对于Python,函数需要self
作为第一个参数。
实现您的目标:
from API01 import getStuff01
def wrapper01(self):
getStuff01()
class foo01(object):
GET_STUFF = wrapper01
答案 1 :(得分:0)
只是为了扩展Aaron的答案,如果你想拥有静态方法,你可以使用@staticmethod装饰器:
class Calc:
@staticmethod
def sum(x, y):
return x + y
print (Calc.sum(3,4))
>>> 7
答案 2 :(得分:0)
我认为我的对象是将自己作为参数调用引用的函数。经过一番研究,我终于找到了解决方案。当我使用类变量指向函数时,它不会引用直接指针。它将函数引用为它的类的反弹方法。要删除使用getattr
调用方法的默认调用,必须覆盖getattr
对类本身的调用函数(在本例中为类bar
,因为{{ 1}}(包装类)继承了foo
:
bar
import inspect
class bar(object):
GET_STUFF = None
def __getattribute__(self, name):
attr = object.__getattribute__(self,name)
if name == "GET_STUFF":
# Check: is method and is bounced?
if inspect.ismethod(attr) and attr.im_self is not None:
return attr.__func__
return attr
的{{1}}现在指向原始函数引用,但仅针对类变量getattr
,因为我想保留其余变量的默认功能。
所以,当我现在执行以下内容时:
bar
我得到了预期的结果,可以编写我的包装器,而不会为每个包含这些包装类的模块生成额外的代码:
GET_STUFF