12

関数を非推奨としてマークし、その関数が使用されるたびに警告が表示されるようにするデコレータを見てきました。グローバル変数に対して同じことをしたいのですが、グローバル変数のアクセスを検出する方法が思いつきません。私は globals() 関数について知っており、その内容を確認できましたが、実際に使用されているかどうかではなく、グローバルが定義されているかどうかがわかります (関数が非推奨であり、すべてが削除されていない場合でもそうです)。 . 私が考えることができる最良の代替案は、次のようなものです。

# myglobal = 3
myglobal = DEPRECATED(3)

しかし、DEPRECATED を「3」とまったく同じように動作させる方法の問題以外に、DEPRECATED がアクセスされるたびに検出できるようにするために何ができるかはわかりません。私ができる最善の方法は、グローバルのすべてのメソッドを反復処理し (Python ではすべてがオブジェクトであるため、「3」にも文字列などに変換するためのメソッドがあるため)、それらをすべて非推奨にするために「装飾」することだと思います。しかし、それは理想的ではありません。

何か案は?他の誰かがこの問題に取り組みましたか?

4

4 に答える 4

14

モジュールアクセスを傍受する方法がないため、これを直接行うことはできません。ただし、そのモジュールを、特定のプロパティへのアクセスを探して、プロキシとして機能する選択したオブジェクトに置き換えることができます。

import sys, warnings

def WrapMod(mod, deprecated):
    """Return a wrapped object that warns about deprecated accesses"""
    deprecated = set(deprecated)
    class Wrapper(object):
        def __getattr__(self, attr):
            if attr in deprecated:
                warnings.warn("Property %s is deprecated" % attr)

            return getattr(mod, attr)

        def __setattr__(self, attr, value):
            if attr in deprecated:
                warnings.warn("Property %s is deprecated" % attr)
            return setattr(mod, attr, value)
    return Wrapper()

oldVal = 6*9
newVal = 42

sys.modules[__name__] = WrapMod(sys.modules[__name__], 
                         deprecated = ['oldVal'])

これで、次のように使用できます。

>>> import mod1
>>> mod1.newVal
42
>>> mod1.oldVal
mod1.py:11: UserWarning: Property oldVal is deprecated
  warnings.warn("Property %s is deprecated" % attr)
54

欠点は、モジュールにアクセスするときに2つのルックアップを実行しているため、パフォーマンスがわずかに低下することです。

于 2009-05-28T19:16:29.253 に答える
5

見よ:

コード

from types import *

def wrapper(f, warning):
    def new(*args, **kwargs):
        if not args[0].warned:
            print "Deprecated Warning: %s" % warning
            args[0].warned = True
        return f(*args, **kwargs)
    return new

class Deprecated(object):
    def __new__(self, o, warning):
        print "Creating Deprecated Object"
        class temp(o.__class__): pass
        temp.__name__ = "Deprecated_%s" % o.__class__.__name__
        output = temp.__new__(temp, o)

        output.warned = True
        wrappable_types = (type(int.__add__), type(zip), FunctionType)
        unwrappable_names = ("__str__", "__unicode__", "__repr__", "__getattribute__", "__setattr__")

        for method_name in dir(temp):
            if not type(getattr(temp, method_name)) in wrappable_types: continue
            if method_name in unwrappable_names: continue

            setattr(temp, method_name, wrapper(getattr(temp, method_name), warning))

        output.warned = False

        return output

出力

>>> a=Deprecated(1, "Don't use 1")
Creating Deprecated Object
>>> a+9
Deprecated Warning: Don't use 1
10
>>> a*4
4
>>> 2*a
2

これは明らかに洗練されたものですが、要点はそこにあります。

于 2009-05-29T03:51:55.353 に答える
5

モジュールをクラスにして (たとえば、この SO questionを参照)、非推奨のグローバルをプロパティにすると、アクセス時にコードの一部を実行して、必要な警告を提供できます。ただし、これは少しやり過ぎのようです。

于 2009-05-28T19:08:02.250 に答える