Python 调用保存在类属性中的函数:内置函数与普通函数的不同行为
使用以下脚本:Python 调用保存在类属性中的函数:内置函数与普通函数的不同行为,python,python-2.7,python-internals,Python,Python 2.7,Python Internals,使用以下脚本: import time class Foo(object): func = time.gmtime def go(self): return self.func(0.0) print time.strftime('%Y', Foo().go()) 我得到以下输出: 1970 但是,如果我稍作修改并包装time.gmtime: import time def tmp(stamp): return time.gmtime(stamp)
import time
class Foo(object):
func = time.gmtime
def go(self):
return self.func(0.0)
print time.strftime('%Y', Foo().go())
我得到以下输出:
1970
但是,如果我稍作修改并包装time.gmtime
:
import time
def tmp(stamp):
return time.gmtime(stamp)
class Foo(object):
func = tmp
def go(self):
return self.func(0.0)
print time.strftime('%Y', Foo().go())
然后我得到以下错误:
回溯(最近一次呼叫最后一次):
文件“/test.py”,第13行,在
打印时间.strftime(“%Y”,Foo().go())
文件“/test.py”,第11行,在go中
返回self.func(0.0)
TypeError:tmp()正好接受1个参数(给定2个)
显然,它试图调用Foo.func
,就好像它是一个实例方法,并将self
作为第一个参数传递
两个问题:
和time.gmtime
都是采用单个参数的函数,那么为什么这两个脚本的行为不同呢tmp
- 如何安全地将普通函数保存在类/实例属性中,并在以后从实例方法调用它
class Foo(object):
def __init__(self):
self.func = tmp
def go(self):
return self.func(0.0)
您需要在实例的上下文中分配函数,在初始值设定项中这样做是很可能的
希望这能有所帮助。请注意其中的区别…:
>>> import time
>>> type(time.gmtime)
<type 'builtin_function_or_method'>
>>> def f(*a): return time.gmtime(*a)
...
>>> type(f)
<type 'function'>
导入时间
>>>类型(time.gmtime)
>>>def f(*a):返回时间.gmtime(*a)
...
>>>类型(f)
一个
(它是一个描述符)与一个
(它不是)
您会问“如何安全地将普通函数保存在类/实例属性中,并在以后从实例方法调用它?”
如果“普通函数”是指
,则将其包装为静态方法
,以避免调用时将self
作为第一个参数插入。而且,也可以将staticmethod
封装在内置的方法周围。所以我想这是你最好的选择
time.gmtime
和tmp
都是采用单个参数的函数,那么为什么这两个脚本的行为不同呢self.func
从
当引用的实例属性不是数据属性时,将搜索其类。如果名称表示函数对象的有效类属性,则通过打包(指向)实例对象和在抽象对象中刚刚找到的函数对象来创建方法对象:这是方法对象。使用参数列表调用方法对象时,将从实例对象和参数列表构造新的参数列表,并使用此新参数列表调用函数对象
因此,如果func
是self
中的有效函数对象,则将创建一个绑定方法对象,该对象期望第一个参数是调用此函数的对象
现在我们来比较一下,
print type(time.gmtime)
class Foo(object):
func = time.gmtime
def go(self):
print type(self.func)
return self.func(0.0)
当使用Foo().go()
调用go
时,它将打印
<type 'builtin_function_or_method'>
<type 'builtin_function_or_method'>
将打印
<type 'function'> <function tmp at 0x7f34d9983578>
<type 'instancemethod'> <bound method Foo.tmp of <__main__.Foo object at ...>>
这是有效的
tmp(self, 0.0)
这就是为什么会出现以下错误
TypeError:tmp()正好接受1个参数(给定2个)
Foo.func(self, 0.0)
import time
def tmp(stamp):
return time.gmtime(stamp)
class Foo(object):
def __init__(self):
self.func = tmp # Instance variable, not a class variable
def go(self):
return self.func(0.0)
print time.strftime('%Y', Foo().go())
class Foo(object):
func = staticmethod(tmp)
def go(self):
# `return Foo.func(0.0)` This will also work
return self.func(0.0)
class Foo(object):
@staticmethod
def func(stamp):
return time.gmtime(stamp)
def go(self):
# `return Foo.func(0.0)` This will also work
return self.func(0.0)
这里,self.func
将转换为tmp(0.0)
,因为没有发生绑定方法构造
解决方案2:
使用这样的函数
Foo.func(self, 0.0)
import time
def tmp(stamp):
return time.gmtime(stamp)
class Foo(object):
def __init__(self):
self.func = tmp # Instance variable, not a class variable
def go(self):
return self.func(0.0)
print time.strftime('%Y', Foo().go())
class Foo(object):
func = staticmethod(tmp)
def go(self):
# `return Foo.func(0.0)` This will also work
return self.func(0.0)
class Foo(object):
@staticmethod
def func(stamp):
return time.gmtime(stamp)
def go(self):
# `return Foo.func(0.0)` This will also work
return self.func(0.0)
现在,self.func
仍然会引用tmp
。类似于这样定义类
Foo.func(self, 0.0)
import time
def tmp(stamp):
return time.gmtime(stamp)
class Foo(object):
def __init__(self):
self.func = tmp # Instance variable, not a class variable
def go(self):
return self.func(0.0)
print time.strftime('%Y', Foo().go())
class Foo(object):
func = staticmethod(tmp)
def go(self):
# `return Foo.func(0.0)` This will also work
return self.func(0.0)
class Foo(object):
@staticmethod
def func(stamp):
return time.gmtime(stamp)
def go(self):
# `return Foo.func(0.0)` This will also work
return self.func(0.0)
我怀疑它会有帮助:在
func(0.0)
调用时,您会收到namererror
。确实,谢谢。删除了第二个代码段。如果需要的话,第一种方法是有效的。