python - Python setattr() 函数采用初始函数名
问题描述
我确实了解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)
在上面的类中,set_conditions
函数动态设置 Filter 类的属性 (con
和don
) 并为其分配一个可调用对象,但它们保留了函数的初始名称。
当我运行这个:
>>> f = Filter()
>>> print(f.con('linux'))
>>> print(f.con.__name__)
预期的:
- linux
- con(应该是动态设置属性的名称)
我得到:
- linux
self.condition
条件(属性值的名称(未绑定))
但我希望f.con.__name__
返回属性的名称 ( ) 而不是分配给它con
的未绑定函数的名称 ( )。condition
有人可以向我解释为什么这种行为会这样,我该如何解决?
谢谢。
解决方案
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)
作为旁注(完全不相关,但我认为您可能想知道这一点),使用可变对象作为函数参数默认值是最臭名昭著的 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']
编辑:
谢谢你的回答,但这并没有触及我的问题。我的问题不是函数是如何命名或定义的,我的问题是当我使用 setattr() 并设置一个属性并给它一个函数作为它的值时,我可以访问该值并执行该值的作用,但是因为它是一个函数,为什么它不返回它的名字作为函数名
因为正如我上面已经解释的那样,函数的__name__
属性和引用该函数的Filter
实例属性的名称是完全不相关的,并且该函数对引用它的变量或属性的名称一无所知,如参考中所述我链接到的文章。
实际上,您传递给的对象setattr
是一个函数这一事实完全无关紧要,从对象的 POV 来看,它只是一个名称和一个对象,句号。实际上,您将此对象(函数或任何对象)绑定到实例属性(无论是直接还是使用setattr()
,它的工作原理都一样)而不是普通变量这一事实也完全不相关 - 这些操作都不会有任何对绑定对象的影响(除了增加它的引用计数器,但这是一个 CPython 实现细节 - 其他实现可能会以不同的方式实现垃圾收集)。
推荐阅读
- javascript - 在 Prisma2 中出现错误“无法为不可为空的字段 Joke.id 返回 null”
- node.js - 如何在启用letsencrypt https的情况下连接到节点服务器
- javascript - 如果它与另一个字符串匹配,如何使 JavaScript 更改字符串?
- python-3.x - 一个excel表格列表,我如何组合成一个单行字符串
- firebase - 如何解决它“RangeError(索引):无效值:有效值范围为空:0”在颤动中?
- c++ - 如何通过程序添加到 QAT 。程序使用c++、mfc mdi
- javascript - Laravel 和 Vuetify 未知的自定义元素
- sqlite - 加快 SQLite 中的 COUNT DISTINCT 查询
- http - 如何使用 Wireshark 访问网站?
- java - android java从内部类访问,需要声明final