1

特定のプロパティが設定されるたびにカスタム エスケープを実行する方法と、それらのプロパティがオブジェクトの 1 つから取得されたときに対応するエスケープ解除コードを実行する方法を探しています。__setattr__、__getattr__、および __getattribute__ を見てきましたが、プロパティとの関係がわかりません。

たとえば、次のようなクラスがあります。

class Bundle(object):
    def __init__(self):
        self.storage = Storage()

    @property
    def users_name(self):
        """
        Get the user's name
        """
        return self.storage.users_name

    @users_name.setter
    def users_name(self, users_name):
        """
        Set the user's name
        """
        # only permit letters and spaces. 
        if not re.match('^[A-Za-z ]+$', users_name):
            msg = "'%s' is not a valid users_name. It must only contain letters and spaces" % users_name
            log.fatal(msg)
            raise ConfigurationError(msg)

        self.storage.users_name = users_name
    ...

オブジェクトには、そのようなプロパティがいくつかあります。

私が欲しいのは、一部のプロパティ (users_name など、「storage」など) にのみ影響し、設定/取得時に値をエスケープ/エスケープ解除するメソッドです。

  1. __getattr__ は、このコードが新規および既存のプロパティに対して呼び出される必要があるため、正しくないようです。
  2. __setattr__ は機能するかもしれませんが、@property メソッドにどのように適合するかわかりません。たとえば、__setattr__ はカスタム メソッドの代わりに常に呼び出されますか? __setattr__ 内からカスタム メソッドを呼び出すにはどうすればよいですか? 作業するプロパティのリストを保存せずに @property プロパティのみに影響を与える簡単な方法はありますか?
  3. __getattribute__ これを使ってみたのですが、無限ループになってしまいました。それはさておき、私の質問は __setattr__ とほぼ同じです @property で宣言されたメソッドに委譲することが可能かどうか (およびその方法は?)、および「プロパティだけではなく、これらのプロパティに対してのみ機能する」と言うのが最善の方法ですこのクラスの。

これにアプローチする最良の方法は何ですか?

- アップデート -

詳しく説明すると、この特定の 'Bundle' クラスはプロキシとして機能し、さまざまなバックエンド (この場合は ConfigParser をラップする FileConfigBackend) に構成値を格納します。ConfigParser は補間に「%」記号を使用します。ただし、設定したい値の一部には正当にパーセント記号が含まれている可能性があるため、それらをエスケープする必要があります。ただし、プロパティごとに明示的にエスケープするのではなく、プロパティが設定されるたびに呼び出されるある種の魔法のメソッドが必要です。次に、文字列で実行replace('%', '%%')されます。同様に、プロパティが取得されるたびreplace('%%', '%')に、値を返す前に値に対して実行されるメソッドが必要です。

また、「Bundle」内のプロパティの大部分は単純にバックエンド ストレージにプロキシされるため、「プロパティがこのリストにある場合は呼び出すだけ」という方法があればいいと思いますself.storage.PROPERTY_NAME = VALUE。たとえば、設定する値に対して正規表現を実行するなど、その割り当てをオーバーライドできるようにしたい場合もあります。

本当に、「プロパティが設定されているときは、常にこのメソッドを呼び出す」という方法を探しています。次に、具体的な @property.setter が存在する場合は、self.storage.key = value'.

(doh! 私は __getattr__ & __setattr__ ではなく __get__ と __set__ を意味していました - それを反映するために私の質問を更新しました)

4

3 に答える 3

2

デコレーターは、記述子プロトコル@propertyに従ってオブジェクトを作成します。これは、メソッドが存在する場所です。__get____set__

いくつかのプロパティに追加の動作を追加する最善の方法は、独自のデコレータを作成することです。このデコレーターは同じプロトコルに従い、Python によって最初に作成されたプロパティをラップし、目的のエスケープ/エスケープ解除動作を追加します。これにより、「特別な」エスケープされたプロパティを次のようにマークできます。

@escaped
@property
def users_name(self):
  ...

これらのプロパティのみが特別な扱いを受けます。これを実装する方法の簡単な例を次に示します。

class escaped:
  def __init__(self, property_to_wrap):
    # we wrap the property object created by the other decorator
    self.property = property_to_wrap

  def __get__(self, instance, objtype=None):
    # delegate to the original property
    original_value = self.property_to_wrap.__get__(instance, objtype)
    # ... change the data however you like
    return frotz(original_value)

  def __set__(self, instance, new_value):
    actual_value = frob(new_value)
    self.property.__set__(instance, actual_value)

  ...

すべての記述子メソッドに対して同じことを繰り返す必要があります。getterまた、それ自体の, setter,deleterメソッドを委任する必要があります (ラップされたプロパティとproperty同様の構文を使用できるようにするためです。ヘルプについては、記述子ガイドを参照してください。@users_name.setter

詳細については、こちらにもあります: How do Python properties work? .

于 2013-06-26T13:00:16.617 に答える
0

デコレータを使用して別の回答を提供しましたが、魔法の方法を使用したい場合は、次の方法があります。

class Magic(object):
    @staticmethod
    def should_be_escaped(property_name):
        return not "__" in property_name

    def __getattribute__(self, property):
        value = object.__getattribute__(self, property)
        if Magic.should_be_escaped(property):
            value = value.replace("%%", "%")
        return value

    def __setattr__(self, property, value):
        if Magic.should_be_escaped(property):
            value = value.replace("%", "%%")
        object.__setattr__(self, property, value)

and を呼び出すobject.__getattribute__object.__setattr__、魔法のメソッドから標準の動作に到達できます。これには、プロパティの解決が含まれる必要があります。それらを使用することは、あなたが言及した無限ループを回避する方法です。

これが悪い解決策である理由はshould_be_escaped、名前に基づいてプロパティをエスケープするかどうかを決定する必要がある にあります。これを正しく行うのは難しく、特別な名前やstorage変数などに注意する必要があります。

たとえば、上記の実装は不完全であるため、オブジェクトのメソッドshould_be_escapedを呼び出そうとするため、プロパティ タイプのチェックを追加する必要があります。それらのコーナーケースがたくさんあります。これが、私がデコレーター ソリューションをよりクリーンなものとして提案した理由です。これは、誰が特別な動作を受け取るかを明示的にマークし、将来的に予期しない厄介な結果をもたらすことはありません。replace

于 2013-06-26T13:39:52.603 に答える
0

Googleおじさんがこの分野で提案していることを読んで、試行錯誤によってすべてが非常に明確になります. あなたの場合、__getatribute__obect を調べるのではなく、アクセス時に呼び出されるため、おそらく必要ありません__dict__

property()ビルトインを使用するとより明確になるため、デコレーターには慣れていませんでした。

http://docs.python.org/2/library/functions.html#property


メソッド__set__()__get__()は記述子クラス用です。これは、プロパティ/-ies 用にクラスを定義する必要があることを意味します。良い例え:

http://docs.python.org/2/howto/descriptor.html#descriptor-example


実際に探しているのは、クラスのオーバーライドとメソッドによって利用可能な属性アクセスです ( 2.7.xから派生した場合に利用可能):__setattr__()__getattr()__object

http://docs.python.org/2/reference/datamodel.html#customizing-attribute-access

于 2013-06-26T12:58:59.347 に答える