116

Pythonのプロパティを使用すると、次のようにすることができます

obj.y 

値を返すだけでなく、関数を呼び出します。

モジュールでこれを行う方法はありますか? 欲しいケースがある

module.y 

そこに格納されている値を返すだけでなく、関数を呼び出す。

4

7 に答える 7

61

新しいスタイルのクラスのインスタンスのみがプロパティを持つことができます。に格納することで、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()
于 2009-05-19T01:09:42.430 に答える
59

モジュールのすべての属性を適切に継承し、 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
于 2009-05-19T02:40:12.230 に答える
14

ジョン・リンの答えに基づく:

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 はプロパティが存在することを認識せず、赤い波線を表示することに注意してください。

于 2019-10-23T15:58:19.067 に答える
1

簡単な答え: 使用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
于 2020-02-07T19:57:16.517 に答える