使用 Python setattr 设置对方法或函数的属性引用
Using Python setattr to set an attribute reference to a method or function
我需要使用 setattr 从配置文件中读取,并将 class 的属性设置为另一个模块中的函数。粗略地说,这就是问题所在。
这个有效:
class MyClass:
def __init__(self):
self.number_cruncher = anothermodule.some_function
# method works like this, of course;
foo = MyClass()
foo.number_cruncher(inputs)
好吧,这很简单,但是如果我想从配置文件中读取 some_function
的名称怎么办?读取文件和使用setattr也很简单:
def read_ini(target):
# file reading/parsing stuff here, so we effectively do:
setattr(target, 'number_cruncher', 'anothermodule.some_function')
bar = MyClass()
read_ini(bar)
bar.number_cruncher(inputs)
这给了我一个 'str' object is not callable 错误。如果我理解正确的话,那是因为在第一种情况下我将属性设置为对另一个模块的引用,但在第二种情况下它只是将属性设置为字符串。
问题:1) 我对这个错误的理解是否正确? 2) 如何使用 setattr
将属性设置为对函数的引用而不是简单的字符串属性?
我查看了其他问题并发现了类似的问题,但似乎没有任何内容可以准确解决这个问题。
是的,你的理解是正确的。当您使用 setattr
时,您正在将属性设置为当前示例中的字符串。因此,当您随后调用 bar.number_cruncher(inputs)
时,它会正确地告诉您字符串对象不可调用。相反,如果你想让 bar.number_chruncher
成为函数 anothermodule.some_function
的可调用等价物,那么你可以导入它并将函数(而不是字符串)设置为属性。
def read_ini(target):
# file reading/parsing stuff here, so we effectively do:
__import__("anothermodule.some_function") #Allows you to import based on a string parsed from your configuration file.
setattr(target, 'number_cruncher', anothermodule.some_function)
最简单的方法类似于:
module_name, function_name = "module.func".rsplit('.', 1)
f = getattr(sys.modules[module_name], function_name)
f() # f is now callable, analogous to anothermodule.some_function in your code snippets.
显然,许多潜在问题没有得到解决。首先,它假定模块已经导入。要解决这个问题,您可以参考 Dynamic module import in Python 并使用 __import__
的 return 值。别担心,CPython 会在内部对其进行优化,相同的模块不会被解释多次。
稍微好一点的版本是:
module_name, function_name = "module.func".rsplit('.', 1)
f = getattr(__import__(module_name), function_name)
f()
我需要使用 setattr 从配置文件中读取,并将 class 的属性设置为另一个模块中的函数。粗略地说,这就是问题所在。
这个有效:
class MyClass:
def __init__(self):
self.number_cruncher = anothermodule.some_function
# method works like this, of course;
foo = MyClass()
foo.number_cruncher(inputs)
好吧,这很简单,但是如果我想从配置文件中读取 some_function
的名称怎么办?读取文件和使用setattr也很简单:
def read_ini(target):
# file reading/parsing stuff here, so we effectively do:
setattr(target, 'number_cruncher', 'anothermodule.some_function')
bar = MyClass()
read_ini(bar)
bar.number_cruncher(inputs)
这给了我一个 'str' object is not callable 错误。如果我理解正确的话,那是因为在第一种情况下我将属性设置为对另一个模块的引用,但在第二种情况下它只是将属性设置为字符串。
问题:1) 我对这个错误的理解是否正确? 2) 如何使用 setattr
将属性设置为对函数的引用而不是简单的字符串属性?
我查看了其他问题并发现了类似的问题,但似乎没有任何内容可以准确解决这个问题。
是的,你的理解是正确的。当您使用 setattr
时,您正在将属性设置为当前示例中的字符串。因此,当您随后调用 bar.number_cruncher(inputs)
时,它会正确地告诉您字符串对象不可调用。相反,如果你想让 bar.number_chruncher
成为函数 anothermodule.some_function
的可调用等价物,那么你可以导入它并将函数(而不是字符串)设置为属性。
def read_ini(target):
# file reading/parsing stuff here, so we effectively do:
__import__("anothermodule.some_function") #Allows you to import based on a string parsed from your configuration file.
setattr(target, 'number_cruncher', anothermodule.some_function)
最简单的方法类似于:
module_name, function_name = "module.func".rsplit('.', 1)
f = getattr(sys.modules[module_name], function_name)
f() # f is now callable, analogous to anothermodule.some_function in your code snippets.
显然,许多潜在问题没有得到解决。首先,它假定模块已经导入。要解决这个问题,您可以参考 Dynamic module import in Python 并使用 __import__
的 return 值。别担心,CPython 会在内部对其进行优化,相同的模块不会被解释多次。
稍微好一点的版本是:
module_name, function_name = "module.func".rsplit('.', 1)
f = getattr(__import__(module_name), function_name)
f()