带有装饰器的动态方法创建者的python setattr [英] python setattr for dynamic method creator with decorator

查看:293
本文介绍了带有装饰器的动态方法创建者的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))

这篇关于带有装饰器的动态方法创建者的python setattr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆