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'
Я знал, что видел некоторый прецедент для свойства -, например, функциональность на уровне модуля -, так как я использовал его для сценариев команд оболочки, используя элегантную, но хакерскую библиотеку pbs .
Интересный хак ниже можно найти в исходном коде библиотеки 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
кажется естественным местом для добавления такой функциональности.
Есть ли какая-то конкретная причина или мотивация, почему это не встроено напрямую?