繁体   English   中英

为什么具有相同`id`的两个函数具有不同的属性?

[英]Why can two functions with the same `id` have different attributes?

为什么具有相同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 (不确定函数是否需要递归副本或者它是否过度)但这并没有改变任何东西。

您正在比较方法 ,并且每次访问实例或类(通过描述符协议 )时,方法对象都会重新创建。

一旦你测试了他们的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的值,而不是在创建函数时查找。 请参阅Python嵌套函数中的局部变量

最简单的解决方法是使用工厂函数添加另一个范围:

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)

根据您对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

你应该保存当前的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)
# ...

@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,并且与最后一个不同。 这是方法创建逻辑,它发送它指向相同的位置,就像存储类的代码一样。 此外,如果将my_type用作某种类,则使用它创建的实例具有该函数的相同内存地址

此代码给出:
id 4299601152
id 4299601272
4299376112
4299376112
我是功能0
我是职能1
function_0
function_1
1
没有
1
没有
<0x10047c350处的主要 .my_type对象>
4299376112

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM