Python setattr()函数采用初始函数名称

Emm*_*wan 5 python class setattribute setattr dynamic-function

我确实了解setattr()python的工作原理,但是我的问题是当我尝试动态设置属性并将其未绑定函数作为值提供时,因此该属性是可调用的,当我使用该属性时,该属性最终会使用未绑定函数的名称调用attr.__name__,而不是属性的名称。

这是一个例子:

我有一Filter堂课:

class Filter:
    def __init__(self, column=['poi_id', 'tp.event'], access=['con', 'don']):
        self.column = column
        self.access = access
        self.accessor_column = dict(zip(self.access, self.column))
        self.set_conditions()

    def condition(self, name):
        # i want to be able to get the name of the dynamically set 
        # function and check `self.accessor_column` for a value, but when
        # i do `setattr(self, 'accessor', self.condition)`, the function 
        # name is always set to `condition` rather than `accessor`
        return name

    def set_conditions(self):
        mapping = list(zip(self.column, self.access))
        for i in mapping:
            poi_column = i[0]
            accessor = i[1]
            setattr(self, accessor, self.condition)

Run Code Online (Sandbox Code Playgroud)

在上面的类中,该set_conditions函数动态设置Filter类的属性(condon)并为它们分配一个可调用的属性,但它们保留该函数的初始名称。

当我运行这个:

>>> f = Filter()
>>> print(f.con('linux'))
>>> print(f.con.__name__)
Run Code Online (Sandbox Code Playgroud)

预期:

  • linux
  • con(应该是动态设置属性的名称)

我得到:

  • linux
  • 条件(self.condition属性值的名称(未绑定))

但我希望f.con.__name__返回属性的名称(con),而不是condition分配给它的未绑定函数()的名称。

有人可以向我解释为什么这样的行为,我该如何解决?

谢谢。

bru*_*ers 2

function.__name__是函数最初定义时使用的名称,与访问它时使用的名称无关。实际上,重点function.__name__是正确识别函数,无论使用什么名称来访问它。您肯定想阅读本文以了解有关 Python“名称”的更多信息

condition这里可能的解决方案之一是用闭包替换 的静态定义:

class Filter(object):
    def __init__(self, column=['poi_id', 'tp.event'], access=['con', 'don']):
        self.column = column
        self.access = access
        self.accessor_column = dict(zip(self.access, self.column))
        self.set_conditions()

    def set_conditions(self):
        mapping = list(zip(self.column, self.access))
        for column_name, accessor_name in mapping:
            def accessor(name):
                print("in {}.accessor '{}' for column '{}'".format(self, accessor_name, column_name))
                return name

            # this is now technically useless but helps with inspection
            accessor.__name__ = accessor_name
            setattr(self, accessor_name, accessor)
Run Code Online (Sandbox Code Playgroud)

顺便说一句(完全不相关,但我想你可能想知道这一点),使用可变对象作为函数参数默认值是最臭名昭著的 Python 陷阱之一,可能会产生完全意想不到的结果,即:

>>> f1 = Filter()
>>> f2 = Filter()
>>> f1.column
['poi_id', 'tp.event']
>>> f2.column
['poi_id', 'tp.event']
>>> f2.column.append("WTF")
>>> f1.column
['poi_id', 'tp.event', 'WTF']
Run Code Online (Sandbox Code Playgroud)

编辑:

谢谢你的回答,但这与我的问题无关。我的问题不是如何命名或定义函数,我的问题是当我使用 setattr() 并设置一个属性并给它一个函数作为它的值时,我可以访问该值并执行该值所做的事情,但是因为它是一个函数,为什么它不返回它的名称作为函数名称

因为正如我上面已经解释的那样,函数的属性和引用该函数的实例属性__name__的名称完全无关,并且该函数对引用它的变量或属性的名称绝对一无所知,如参考文献中所述我链接到的文章。Filter

实际上,您传递给的对象是一个函数这一事实setattr是完全无关的,从对象的 POV 来看,它只是一个名称和一个对象,句号。实际上,您将此对象(函数或任何对象)绑定到实例属性(无论是直接还是使用setattr(),它的工作原理都是一样的)而不是普通变量的事实也是完全无关的 - 这些操作都不会产生任何影响对绑定对象的影响(除了增加它的引用计数器,但这是 CPython 实现细节 - 其他实现可能会以不同方式实现垃圾收集)。