我在使用self参数时遇到了一些问题,而Python中一些看似不一致的行为让我烦恼,所以我想我最好问一些知情人士。我有一个班级,Foo
。这个类将有一堆方法m1
,通过mN
。对于其中一些,我将使用标准定义,如下面m1
的情况。但对于其他人来说,直接分配方法名称更方便,就像我使用m2
和m3
一样。
import os
def myfun(x, y):
return x + y
class Foo():
def m1(self, y, z):
return y + z + 42
m2 = os.access
m3 = myfun
f = Foo()
print f.m1(1, 2)
print f.m2("/", os.R_OK)
print f.m3(3, 4)
现在,我知道os.access
没有采用self
参数(貌似)。它仍然没有这种类型的任务问题。但是,我不能对我自己的模块做同样的事情(想象myfun
中定义的mymodule.myfun
。运行上面的代码会产生以下输出:
3
True
Traceback (most recent call last):
File "foo.py", line 16, in <module>
print f.m3(3, 4)
TypeError: myfun() takes exactly 2 arguments (3 given)
问题在于,由于我所使用的框架,我至少无法避免使用类Foo
。但是我想避免将我的mymodule
内容放入虚拟课堂中。为了做到这一点,我需要做一些事情
def m3(self,a1, a2):
return mymodule.myfun(a1,a2)
当你有20个人时,这是多余的。所以,问题是,或者我如何以完全不同的,明显更智能的方式做到这一点,或者我如何使我自己的模块像内置模块一样,所以它不会抱怨接收1个参数太多。
答案 0 :(得分:4)
os.access()
是一个内置函数,因为它是用C编写的扩展模块的一部分。当定义类时,Python不会将m2
识别为方法,因为它是错误的类型 - 方法是Python函数,而不是C函数。但是,m3
是一个Python函数,因此它被认为是一种方法并按此处理。
换句话说,m2
在这里是例外,而不是m3
。
一种简单的方法就是让m3
成为一种静态方法:
m3 = staticmethod(myfun)
现在,当解释器被称为Foo对象的myfun()
方法时,解释器知道永远不会尝试传递self
m3
参数。
答案 1 :(得分:2)
我认为你正在寻找staticmethod()。请参阅文档here。
m2 = staticmethod(os.access)
m3 = staticmethod(myfun)
至于为什么m2在你的例子中起作用而m3没有,那对我来说并不清楚。在原始示例中打印f.m2和f.m3表明f.m2是对内置函数os.access的直接引用,而f.m3是绑定方法(绑定到实例f)。
答案 2 :(得分:2)
我只想补充说,这种行为并不像卢克暗示的那样不一致。
试试以下
print Foo.__dict__
{'__doc__': None,
'__module__': '__main__',
'm1': <function m1 at 0x02861630>,
'm2': <built-in function access>,
'm3': <function myfun at 0x028616F0>}
在这里你可以看到Python无法区分m1和m2。 这就是为什么两者都被评估为绑定方法的原因。
绑定方法类似于带有指向对象的附加第一个参数的方法:self.m(1, 2) -> m(self, 1, 2)
此绑定行为仅针对用户定义的方法实现。这解释了为什么self.m2("/", os.R_OK)
未评估为m2(self, "/", os.R_OK)
。
最后一个演示:
print Foo.m1
<unbound method Foo.m1>
print Foo.m2
<built-in function access>
print f.m1
<bound method Foo.m1 of <__main__.Foo instance at 0x02324418>>
print f.m2
<built-in function access>
有关不同功能类型的更多信息,请访问:
http://docs.python.org/reference/datamodel.html
如前所述,使用 staticmethod描述符也可以防止这种绑定机制:
答案 3 :(得分:1)
在这种情况下,您应该使用staticmethod功能。编写静态类方法时,可以将其用作装饰器:
class A:
def printValue(self,value):
print value
@staticmethod
def staticPrintValue(value):
print value
>>> A.printValue(5)
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
A.printValue(5)
TypeError: unbound method printValue() must be called with A instance as first argument (got int instance instead)
>>> A.staticPrintValue(5)
5
答案 4 :(得分:0)
一种方法是手动应用静态方法装饰器:
class Foo(object):
m3 = staticmethod(mymodule.myfun)