Jos*_*son 87 python properties python-module
使用python属性,我可以这样做
obj.y
Run Code Online (Sandbox Code Playgroud)
调用函数而不是仅返回值.
有没有办法用模块做到这一点?我有一个我想要的案例
module.y
Run Code Online (Sandbox Code Playgroud)
调用函数,而不是只返回存储在那里的值.
Ale*_*lli 55
只有新式类的实例才能拥有属性.你可以让Python相信这样一个实例是一个模块,通过存储它sys.modules[thename] = theinstance.因此,例如,您的m.py模块文件可能是:
import sys
class _M(object):
def __init__(self):
self.c = 0
def afunction(self):
self.c += 1
return self.c
y = property(afunction)
sys.modules[__name__] = _M()
Run Code Online (Sandbox Code Playgroud)
编辑:删除了对全局变量的隐式依赖(与示例的要点无关,但是通过使原始代码失败而确实混淆了事情!).
Unk*_*own 51
我这样做是为了正确地继承模块的所有属性,并通过isinstance()正确识别
import types
class MyModule(types.ModuleType):
@property
def y(self):
return 5
>>> a=MyModule("test")
>>> a
<module 'test' (built-in)>
>>> a.y
5
Run Code Online (Sandbox Code Playgroud)
然后你可以将它插入到sys.modules中:
sys.modules[__name__] = MyModule(__name__) # remember to instantiate the class
Run Code Online (Sandbox Code Playgroud)
Joh*_*Lin 12
由于PEP 562已在Python> = 3.7中实现,现在我们可以执行此操作
文件:module.py
def __getattr__(name):
if name == 'y':
return 3
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
other = 4
Run Code Online (Sandbox Code Playgroud)
用法:
>>> import module
>>> module.y
3
>>> module.other
4
>>> module.nosuch
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "module.py", line 4, in __getattr__
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
AttributeError: module 'module' has no attribute 'nosuch'
Run Code Online (Sandbox Code Playgroud)
请注意,如果您raise AttributeError在__getattr__函数中省略,则表示函数以结束return None,则的module.nosuch值将为None。
小智 11
基于约翰林的回答:
def module_property(func):
"""Decorator to turn module functions into properties.
Function names must be prefixed with an underscore."""
module = sys.modules[func.__module__]
def base_getattr(name):
raise AttributeError(
f"module '{module.__name__}' has no attribute '{name}'")
old_getattr = getattr(module, '__getattr__', base_getattr)
def new_getattr(name):
if f'_{name}' == func.__name__:
return func()
else:
return old_getattr(name)
module.__getattr__ = new_getattr
return func
Run Code Online (Sandbox Code Playgroud)
用法(注意前导下划线),在the_module.py:
@module_property
def _thing():
return 'hello'
Run Code Online (Sandbox Code Playgroud)
然后:
import the_module
print(the_module.thing) # prints 'hello'
Run Code Online (Sandbox Code Playgroud)
前导下划线是区分属性化函数与原始函数所必需的。我想不出重新分配标识符的方法,因为在装饰器执行期间,它还没有被分配。
请注意,IDE 不会知道该属性存在并会显示红色波浪。
一个典型的用例是:使用一些动态属性来丰富(庞大的)现有模块,而无需将所有模块内容转换为类布局。不幸的是,最简单的模块类补丁如sys.modules[__name__].__class__ = MyPropertyModule失败了TypeError: __class__ assignment: only for heap types。因此,需要重新创建模块。
这种方法无需使用Python导入钩子就能做到这一点,只需在模块代码的顶部添加一些序言即可:
# propertymodule.py
""" Module property example """
if '__orgmod__' not in globals():
# constant prolog for having module properties / supports reload()
print "PropertyModule stub execution", __name__
import sys, types
class PropertyModule(types.ModuleType):
def __str__(self):
return "<PropertyModule %r from %r>" % (self.__name__, self.__file__)
modnew = PropertyModule(__name__, __doc__)
modnew.__modclass__ = PropertyModule
modnew.__file__ = __file__
modnew.__orgmod__ = sys.modules[__name__]
sys.modules[__name__] = modnew
exec sys._getframe().f_code in modnew.__dict__
else:
# normal module code (usually vast) ..
print "regular module execution"
a = 7
def get_dynval(module):
return "property function returns %s in module %r" % (a * 4, module.__name__)
__modclass__.dynval = property(get_dynval)
Run Code Online (Sandbox Code Playgroud)
用法:
>>> import propertymodule
PropertyModule stub execution propertymodule
regular module execution
>>> propertymodule.dynval
"property function returns 28 in module 'propertymodule'"
>>> reload(propertymodule) # AFTER EDITS
regular module execution
<module 'propertymodule' from 'propertymodule.pyc'>
>>> propertymodule.dynval
"property function returns 36 in module 'propertymodule'"
Run Code Online (Sandbox Code Playgroud)
注意:诸如此类的东西from propertymodule import dynval会产生一个冻结的课程副本-对应于dynval = someobject.dynval
| 归档时间: |
|
| 查看次数: |
22046 次 |
| 最近记录: |