
On Sat, Apr 16, 2016, at 23:42, Chris Angelico wrote:
It's not as clean as actually supporting @property, but it could be done without the "bootstrap problem" of trying to have a module contain the class that it's to be an instance of. All you have to do is define __getattr__ as a regular top-level function, and it'll get called. You can then dispatch to property functions if you wish (eg """return globals()['_property_'+name]()"""), or just put all the code straight into __getattr__.
Or you could have ModuleType.__getattr(ibute?)__ search through some object other than the module itself for descriptors. from types import ModuleType, SimpleNamespace import sys # __magic__ could simply be a class, but just to prove it doesn't have to be: @property def foo(self): return eval(input("get foo?")) @foo.setter def foo(self, value): print("set foo=" + repr(value)) def __call__(self, v1, v2): print("modcall" + repr((v1, v2))) __magic__ = SimpleNamespace() for name in 'foo __call__'.split(): setattr(__magic__, name, globals()[name]) del globals()[name] class MagicModule(ModuleType): def __getattr__(self, name): descriptor = getattr(self.__magic__, name) return descriptor.__get__(self, None) def __setattr__(self, name, value): try: descriptor = getattr(self.__magic__, name) except AttributeError: return super().__setattr__(name, value) return descriptor.__set__(self, value) def __call__(self, *args, **kwargs): # Because why not? try: call = self.__magic__.__call__ except AttributeError: raise TypeError("Could not access " + self.__name__ + "__magic__.__call__ method.") return call(self, *args, **kwargs) sys.modules[__name__].__class__ = MagicModule