Pythonのプロパティを使用すると、次のようにすることができます
obj.y
値を返すだけでなく、関数を呼び出します。
モジュールでこれを行う方法はありますか? 欲しいケースがある
module.y
そこに格納されている値を返すだけでなく、関数を呼び出す。
Pythonのプロパティを使用すると、次のようにすることができます
obj.y
値を返すだけでなく、関数を呼び出します。
モジュールでこれを行う方法はありますか? 欲しいケースがある
module.y
そこに格納されている値を返すだけでなく、関数を呼び出す。
新しいスタイルのクラスのインスタンスのみがプロパティを持つことができます。に格納することで、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()
モジュールのすべての属性を適切に継承し、 isinstance() によって正しく識別されるようにするためにこれを行います
import types
class MyModule(types.ModuleType):
@property
def y(self):
return 5
>>> a=MyModule("test")
>>> a
<module 'test' (built-in)>
>>> a.y
5
そして、これを sys.modules に挿入できます:
sys.modules[__name__] = MyModule(__name__) # remember to instantiate the class
ジョン・リンの答えに基づく:
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
使用法 (先頭のアンダースコアに注意してください) the_module.py
:
@module_property
def _thing():
return 'hello'
それで:
import the_module
print(the_module.thing) # prints 'hello'
プロパティ化された関数を元の関数と区別するには、先頭のアンダースコアが必要です。デコレーターの実行中はまだ割り当てられていないため、識別子を再割り当てする方法が思いつきませんでした。
IDE はプロパティが存在することを認識せず、赤い波線を表示することに注意してください。
proxy_tools
proxy_tools
パッケージは機能を提供しようとします@module_property
。
でインストールします
pip install proxy_tools
@Mareinの例をわずかに変更しthe_module.py
て、
from proxy_tools import module_property
@module_property
def thing():
print(". ", end='') # Prints ". " on each invocation
return 'hello'
今、別のスクリプトから、私はできる
import the_module
print(the_module.thing)
# . hello
このソリューションには、注意事項がないわけではありません。つまり、文字列the_module.thing
ではありません! これは、文字列を模倣するために特別なメソッドがオーバーライドされたオブジェクトです。ポイントを説明するいくつかの基本的なテストを次に示します。proxy_tools.Proxy
res = the_module.thing
# [No output!!! Evaluation doesn't occur yet.]
print(type(res))
# <class 'proxy_tools.Proxy'>
print(isinstance(res, str))
# False
print(res)
# . hello
print(res + " there")
# . hello there
print(isinstance(res + "", str))
# . True
print(res.split('e'))
# . ['h', 'llo']
内部的には、元の関数は次の場所に保存され the_module.thing._Proxy__local
ます:
print(res._Proxy__local)
# <function thing at 0x7f729c3bf680>
正直なところ、なぜモジュールにこの機能が組み込まれていないのか、私は困惑しています。問題の核心は、それがクラスthe_module
のインスタンスであるということだと思います。「モジュール プロパティ」を設定すると、クラス自体ではなく、このクラスのインスタンスtypes.ModuleType
にプロパティを設定することになります。詳細については、この回答を参照してください。types.ModuleType
types.ModuleType
結果は良くありませんが、実際には次のようにプロパティを実装できます。組み込み型を直接変更することはできませんが、それらを呪うことはできます。
# python -m pip install forbiddenfruit
from forbiddenfruit import curse
from types import ModuleType
# curse has the same signature as setattr.
curse(ModuleType, "thing2", property(lambda module: f'hi from {module.__name__}'))
これにより、すべてのモジュールに存在するプロパティが得られます。すべてのモジュールで設定動作を中断するため、これは少し扱いにくいです。
import sys
print(sys.thing2)
# hi from sys
sys.thing2 = 5
# AttributeError: can't set attribute