gpt4 book ai didi

python - 调用保存在类属性中的函数 : different behavior with built-in function vs. 普通函数

转载 作者:太空狗 更新时间:2023-10-29 23:58:45 27 4
gpt4 key购买 nike

使用以下脚本:

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())

然后我得到以下错误:

Traceback (most recent call last):
File "./test.py", line 13, in <module>
print time.strftime('%Y', Foo().go())
File "./test.py", line 11, in go
return self.func(0.0)
TypeError: tmp() takes exactly 1 argument (2 given)

很明显,它试图调用 Foo.func,就好像它是一个实例方法一样,并将 self 作为第一个参数传递。

两个问题:

  • time.gmtimetmp 都是采用单个参数的函数,那么为什么这两个脚本的行为不同?
  • 如何安全地将普通函数保存在类/实例属性中并稍后从实例方法中调用它?

最佳答案

  1. Both time.gmtime and tmp are functions that take a single argument, so why do the two scripts behave differently?

让我们了解当您这样做时 Python 会做什么

self.func

来自 the documentation ,

When an instance attribute is referenced that isn’t a data attribute, its class is searched. If the name denotes a valid class attribute that is a function object, a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object. When the method object is called with an argument list, a new argument list is constructed from the instance object and the argument list, and the function object is called with this new argument list.

因此,如果 funcself 中的有效函数对象,那么将创建一个绑定(bind)方法对象,它需要第一个参数成为调用此函数的对象。

现在让我们比较一下,

print type(time.gmtime)

class Foo(object):
func = time.gmtime
def go(self):
print type(self.func)
return self.func(0.0)

goFoo().go() 调用时,它会打印

<type 'builtin_function_or_method'>
<type 'builtin_function_or_method'>

没错。由于 time.gmtime 是内置函数(与函数对象不同),因此这里没有创建绑定(bind)方法对象。现在让我们试试你的第二个例子,

def tmp(stamp):
return time.gmtime(stamp)

print type(tmp), tmp

class Foo(object):
func = tmp
def go(self):
print type(self.func), self.func
return self.func(0.0)

会打印

<type 'function'> <function tmp at 0x7f34d9983578>
<type 'instancemethod'> <bound method Foo.tmp of <__main__.Foo object at ...>>

因为 tmp 是一个函数对象,根据上面显示的文档,创建了一个绑定(bind)方法对象,它期望 Foo 的对象作为第一个参数。因此,tmp 实际上作为 instancemethod 绑定(bind)到 Foo。当你像 Foo().go() 一样调用 go 时,它会在内部像这样调用 tmp

Foo.func(self, 0.0)

这是有效的

tmp(self, 0.0)

这就是为什么你会收到以下错误

TypeError: tmp() takes exactly 1 argument (2 given)
  1. How can I safely save an ordinary function in a class/instance attribute and call it later from an instance method?

解决方案一:

引用 Python documentation再次,

It is also important to note that user-defined functions which are attributes of a class instance are not converted to bound methods; this only happens when the function is an attribute of the class.

这意味着,当您将用户定义的函数分配给类变量时,绑定(bind)方法构造就会发生。但是,如果您将它分配给一个实例,那么它就不会发生。

所以,你可以利用它来发挥你的优势,就像这样

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())

在这里,self.func 将转换为 tmp(0.0),因为没有绑定(bind)方法构造发生。

解决方案 2:

使用staticmethod像这样的功能

class Foo(object):
func = staticmethod(tmp)

def go(self):
# `return Foo.func(0.0)` This will also work
return self.func(0.0)

现在,self.func 仍会引用 tmp。它类似于这样定义你的类

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)

关于python - 调用保存在类属性中的函数 : different behavior with built-in function vs. 普通函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28007368/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com