python动态属性_Python动态函数属性

在尝试实现动态排序时,我遇到了一个有趣的问题.

给出以下代码:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值