func属性上的标记似乎无法正常工作

时间:2018-01-18 07:17:07

标签: python-3.x

我定义了以下装饰器:

class My_Decorator:

    def __init__(self, marker_list):
        assert isinstance(marker_list, list)
        self.marker_list = marker_list

    def __call__(self, original_class):
        for this_marker in self.marker_list:
            def _method(self):
                print("marker on this func attribute: ", _method.marker)
            _method.marker = this_marker

            setattr(
                    original_class,
                    this_marker,
                    _method
            )

        return original_class


@My_Decorator(['marker1', 'marker2'])
class A: pass

我期望可调用方法内部的循环将生成不同的_method个对象,并相应地分配,每次迭代都有自己对应的_method.marker。但是,下面是我得到的:

a = A()
>>> A.marker1
<function My_Decorator.__call__.<locals>._method at 0x7fc0ded21bf8>
>>> A.marker2
<function My_Decorator.__call__.<locals>._method at 0x7fc0dec371e0>
>>> A.marker1.marker
'marker1'
>>> A.marker2.marker
'marker2'
>>> a.marker1()
marker on this func attribute:  marker2
>>> a.marker2()
marker on this func attribute:  marker2

正如我们在这里可以看到的那样,该方法停留在循环的最后一个标记处。 有人可以帮忙指出原因吗?感谢。

1 个答案:

答案 0 :(得分:0)

在循环内定义一个函数会导致后期绑定:事实上你在循环外调用函数,使它查找最新的_method定义。

实施早期绑定将解决您的问题:

def __call__(self, original_class):
    for this_marker in self.marker_list:
        # set a default value, which is the currently iterated "this_marker"
        def _method(self, this_marker=this_marker):
            # move the attribute setting for "_method" inside the function
            _method.marker = this_marker
            print("marker on this func attribute: ", _method.marker)

        setattr(
                original_class,
                this_marker,
                _method
        )

    return original_class    

现在:

>>> a.marker1()
marker on this func attribute:  marker1
>>> a.marker2()
marker on this func attribute:  marker2