概述
在尝试实现动态排序时,我遇到了一个有趣的问题.
给出以下代码:
>>> l = []
>>> for i in range(2):
>>> def f():
>>> return f.v
>>> f.v = i
>>> l.append(f)
你必须要小心如何使用l中的函数:
>>> l[0]()
1
>>> l[1]()
1
>>> [h() for h in l]
[1, 1]
>>> [f() for f in l]
[0, 1]
>>> f = l[0]
>>> f()
0
>>> k = l[1]
>>> k()
0
>>> f = l[1]
>>> k()
1
>>> del f
>>> k()
NameError: global name 'f' is not defined
函数的行为取决于当前的f.
我该怎么做才能避免这个问题?如何设置不依赖于函数名称的函数属性?
更新
阅读你的评论和答案,这是我的实际问题.
我有一些数据,我想根据用户输入排序(所以我不知道提前排序标准).用户可以选择应用连续排序的数据部分,这些排序可以是升序或降序.
所以我的第一次尝试是循环用户输入,为每个标准定义一个函数,将此函数存储在列表中,然后将此列表用于排序的键,如下所示:key = lambda x:[f(x)for f in functions ].为了避免将条件乘以函数本身,我在函数定义之前计算了一些所需的值,并将它们绑定到函数(具有不同预先计算值的不同函数).
在调试时,我理解函数属性不是这里的解决方案,所以我确实用__call__方法编写了一个类.
解决方法:
问题是由于返回f.v加载全局f,而不是你想要的那个.你可以通过反汇编代码看到这个:
>>> dis.dis(l[0])
3 0 LOAD_GLOBAL 0 (f)
3 LOAD_ATTR 1 (v)
6 RETURN_VALUE
在填充l的循环之后,f是对最后创建的闭包的引用,如下所示:
>>> l
[, ]
>>> f
因此,当你调用l [0]()时,它仍会加载指向最后创建的函数的f,并返回1.当你通过执行f = l [0]重新定义f时,全局f现在指向第一个功能.
你似乎想要的是一个具有状态的函数,它实际上是一个类.你可以这样做:
class MyFunction:
def __init__(self, v):
self.v = v
def __call__(self):
return self.v
l = [MyFunction(i) for i in range(2)]
l[0]() # 0
l[1]() # 1
虽然首先解释您的实际问题可能是个好主意,因为可能有更好的解决方案.
1:为什么不加载全局f而不是当前实例,你可能会问?
回想一下,当你创建一个类时,你需要传递一个self参数,如下所示:
# ...
def my_method(self):
return self.value
self实际上是对象的当前实例的引用.这就是Python知道加载属性值的位置.它知道它必须查看self引用的实例.所以当你这样做时:
a.value = 1
a.my_method()
self现在是对a的引用.
所以当你这样做时:
def f():
return f.v
Python无法知道实际上是什么.它不是参数,因此必须从其他地方加载它.在您的情况下,它是从全局变量加载的.
因此,当你执行f.v = i时,当你为f的实例设置属性v时,无法知道你在函数体中引用了哪个实例.
标签:python
最后
以上就是靓丽冰淇淋为你收集整理的python动态属性_Python动态函数属性的全部内容,希望文章能够帮你解决python动态属性_Python动态函数属性所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复