为什么具有相同id
值的两个函数具有不同的属性,如__doc__
或__name__
?
这是一个玩具示例:
some_dict = {}
for i in range(2):
def fun(self, *args):
print i
fun.__doc__ = "I am function {}".format(i)
fun.__name__ = "function_{}".format(i)
some_dict["function_{}".format(i)] = fun
my_type = type("my_type", (object,), some_dict)
m = my_type()
print id(m.function_0)
print id(m.function_1)
print m.function_0.__doc__
print m.function_1.__doc__
print m.function_0.__name__
print m.function_1.__name__
print m.function_0()
print m.function_1()
打印哪些:
57386560
57386560
I am function 0
I am function 1
function_0
function_1
1 # <--- Why is it bound to the most recent value of that variable?
1
我尝试混合调用copy.deepcopy
(不确定函数是否需要递归副本,或者它是否过度杀伤)但这并没有改变任何内容。
答案 0 :(得分:18)
您正在比较方法,每次访问实例或类时,都会重新创建方法对象(通过descriptor protocol)。
一旦你测试了他们的id()
你再次丢弃了这个方法(没有引用它),所以Python在你创建另一个方法时可以自由地重用id。您想使用m.function_0.__func__
和m.function_1.__func__
:
>>> id(m.function_0.__func__)
4321897240
>>> id(m.function_1.__func__)
4321906032
方法对象从它们包装的函数继承__doc__
和__name__
属性。实际的底层函数实际上仍然是不同的对象。
关于返回1
的两个函数;两个函数都使用i
作为闭包;当您调用方法时,会查找i
的值,而不是在创建函数时查找的值。请参阅Local variables in Python nested functions。
最简单的解决方法是使用工厂函数添加另一个范围:
some_dict = {}
for i in range(2):
def create_fun(i):
def fun(self, *args):
print i
fun.__doc__ = "I am function {}".format(i)
fun.__name__ = "function_{}".format(i)
return fun
some_dict["function_{}".format(i)] = create_fun(i)
答案 1 :(得分:3)
根据您对ndpu的答案的评论,这里有一种方法可以创建函数而无需具有可选参数:
for i in range(2):
def funGenerator(i):
def fun1(self, *args):
print i
return fun1
fun = funGenerator(i)
fun.__doc__ = "I am function {}".format(i)
fun.__name__ = "function_{}".format(i)
some_dict["function_{}".format(i)] = fun
答案 2 :(得分:2)
您应该保存当前i
以进行此操作:
1 # <--- Why is it bound to the most recent value of that variable?
1
工作,例如通过将默认值设置为函数参数:
for i in range(2):
def fun(self, i=i, *args):
print i
# ...
或创建一个闭包:
for i in range(2):
def f(i):
def fun(self, *args):
print i
return fun
fun = f(i)
# ...
答案 3 :(得分:2)
@Martjin Pieters是完全正确的。为了说明,请尝试此修改
some_dict = {}
for i in range(2):
def fun(self, *args):
print i
fun.__doc__ = "I am function {}".format(i)
fun.__name__ = "function_{}".format(i)
some_dict["function_{}".format(i)] = fun
print "id",id(fun)
my_type = type("my_type", (object,), some_dict)
m = my_type()
print id(m.function_0)
print id(m.function_1)
print m.function_0.__doc__
print m.function_1.__doc__
print m.function_0.__name__
print m.function_1.__name__
print m.function_0()
print m.function_1()
c = my_type()
print c
print id(c.function_0)
你会发现乐趣每次都有不同的id,并且与最后的id不同。它是方法创建逻辑,它发送指向与存储类代码的位置相同的位置。此外,如果您将my_type用作某种类,则使用它创建的实例具有该函数的相同内存地址
此代码给出:
id 4299601152
id 4299601272
的 4299376112
4299376112 强>
我是功能0
我是职能1
function_0
function_1
1
无
1
无
&lt; main .my_type对象位于0x10047c350&gt;
的 4299376112
强>