带有装饰器的动态方法创建者的python setattr
我有一个定义了多个方法的类.
I have a class which has multiple methods defined.
import mat
class Klass(object):
@mat.sell(mat.CanSet):
def method1(self):
return None
@mat.sell(mat.CanSet):
def method2(self):
return 'value2'
假设我有10种方法需要填充此"Klass".我想生成这些方法而不显式地编写它们.所以我想做一个工厂,为每个方法做setattr.问题是我遵循以下方法,并且last方法具有最后一个值.每个都不获取其相关值,而是value10.另外下面的解决方案没有实现装饰器,我不知道如何分配装饰器
Imagine I have 10 methods that I need to populate for this 'Klass'. I want to generate these methods without explicitely writing them all. So I want to do a factory that does setattr for each method. Problem is that I do following and the last method has the last value. Each do not get its related value but value10. Also below solution does not implement the decorator, I have no idea how to do assign the decorator
class Klass(object):
pass
list1 = [('method1', 'value1'), ('method2', 'value2').....('method10', 'value10')]
for each in list1:
method_name, method_value = each
setattr(Klass, method_name, lambda self: method_value)
所以当我关注时......
So when I do following....
k = Klass()
print k.method1(), method2()...., method10()
对于每种方法,所有结果均为value10.不明白为什么 ? 另外,任何人都可以提供有关如何使用一个属性实现装饰器的帮助吗? PS:如果您有不使用'setattr'的建议,那也将受到欢迎.
it all results in value10 for each method. Do not understand why ? Plus, can anyone help on how to implement the decorator with one attribute ? PS: if you have suggestion that does not use 'setattr', that would be welcomed as well.
使用lambda
创建每个方法时,会将其绑定到当前本地作用域.该作用域只有一个名为method_value
的变量实例,并且在每次循环后都将其设置为新值.因为每个lambda
都引用了这个局部变量,所以它们都看到相同的值(例如,最后设置的值).
When you use the lambda
to create each method, you are binding it to the currently-local scope. That scope has a single instance of a variable named method_value
, and it is being set to a new value after each loop. Because each lambda
refers to this one local variable, they all see the same value (e.g., the last value that was set).
如果您使用不同的方法创建lambda,它将具有不同的作用域,因此您可以获得所需的行为:
If you create the lambda in a different method, it will have a different scope, and you can therefore get the desired behavior:
class Klass(object):
pass
list1 = [('method1', 'value1'), ('method2', 'value2'), ('method10', 'value10')]
def make_attr(value):
return lambda self: value
for method_name, method_value in list1:
setattr(Klass, method_name, make_attr(method_value))
c = Klass()
print c.method1(), c.method2(), c.method10() # "value1, value2, value10"
在这里,make_attr
创建一个新的作用域,因此存在变量value
的唯一实例,每个创建的lambda都一个.
Here, make_attr
creates a new scope, and so there are unique instances of the variable value
, one for each lambda created.
您还可以使用一个不错的技巧来内联创建一个lambda范围的变量,如下所示:
You can also use a nice trick to create a lambda-scoped variable inline, as follows:
lambda self, val=method_value: val
此处,在声明lambda时,为val
分配了method_value
的值,从而为lambda的每个实例赋予了自己的值.这使您可以使用更紧凑的产品:
Here, val
is assigned the value of method_value
at the time of the lambda declaration, giving each instance of lambda its own value. This lets you use the more compact:
for method_name, method_value in list1:
setattr(Klass, method_name, lambda self, val=method_value:val))
最后,Marti在一个不同的答案中指出了如何修改我的make_attr
函数以应用所需的装饰器:
Finally, Marti points out in a different answer how to modify my make_attr
function to apply the desired decorator:
def make_attr(value):
return mat.sell(mat.CanSet)(lambda self: value))