tl;dr:属性装饰器如何与类级别的函数定义一起使用,而不是与模块级别的定义一起使用?
我将属性装饰器应用于一些模块级函数,认为它们将允许我仅通过属性查找来调用方法。
这特别诱人,因为我定义了一组配置函数,比如get_port
,get_hostname
等,所有这些都可以替换为更简单、更简洁的属性对应物:port
,hostname
等。
因此,config.get_port()
会更好config.port
当我发现以下回溯时,我很惊讶,证明这不是一个可行的选择:
TypeError: int() argument must be a string or a number, not 'property'
我知道我在模块级别看到了一些类似属性的功能的先例,因为我使用它来使用优雅但 hacky pbs library编写 shell 命令脚本。
下面有趣的 hack 可以在pbs 库源代码中找到。它能够在模块级别进行类似属性的属性查找,但它非常可怕,非常骇人听闻。
# this is a thin wrapper around THIS module (we patch sys.modules[__name__]).
# this is in the case that the user does a "from pbs import whatever"
# in other words, they only want to import certain programs, not the whole
# system PATH worth of commands. in this case, we just proxy the
# import lookup to our Environment class
class SelfWrapper(ModuleType):
def __init__(self, self_module):
# this is super ugly to have to copy attributes like this,
# but it seems to be the only way to make reload() behave
# nicely. if i make these attributes dynamic lookups in
# __getattr__, reload sometimes chokes in weird ways...
for attr in ["__builtins__", "__doc__", "__name__", "__package__"]:
setattr(self, attr, getattr(self_module, attr))
self.self_module = self_module
self.env = Environment(globals())
def __getattr__(self, name):
return self.env[name]
下面是将此类插入导入命名空间的代码。居然sys.modules
直接打补丁!
# we're being run as a stand-alone script, fire up a REPL
if __name__ == "__main__":
globs = globals()
f_globals = {}
for k in ["__builtins__", "__doc__", "__name__", "__package__"]:
f_globals[k] = globs[k]
env = Environment(f_globals)
run_repl(env)
# we're being imported from somewhere
else:
self = sys.modules[__name__]
sys.modules[__name__] = SelfWrapper(self)
现在我已经了解pbs
了必须经历的时间,我想知道为什么 Python 的这种功能没有直接内置到语言中。特别property
是装饰器似乎是添加此类功能的自然场所。
为什么这不是直接内置的,有什么特别的原因或动机吗?