5

class String()with __get__()__set__()、および methodを作成しましたto_db()。ただし、オブジェクト " " ではなく、によって返された値を呼び出しているため、name = String()実行できません。self.name.to_db()to_db()__get__()name

class String(object):

    def __init__(self, value=None):
        if value:
            self.value = str(value)

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        self.value = str(value)

    def to_db(self):
        return {'type':'string', 'value': self.value}

class Example(object):

    name = String()
    age = Integer()

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def save():
        data = dict(name=self.name.to_db(), age=self.age.to_db())
        db.save(data)

これに対処する 1 つの方法は、self.name.to_db()直接呼び出すのではなく、フラグを設定しinstanceて条件付きを作成し、__get__()それをチェックしてそれが でto_db()あるかどうかを呼び出すことですTrueが、これは扱いにくいようです。より良い方法はありますか?

また、私は記述子に不慣れです-状態を使用instanceおよび/またはinstance.__dict__保存することと、状態を保存することの長所/短所はself何ですか?

4

4 に答える 4

8

それは非常に簡単です - あなたのディスクリプタが必要な追加のメソッドを持つ文字列のサブクラスを返すようにするだけです。

def __get__(self, instance, owner):
    class TaggedString(str):
        def to_db(self):
            return {'type':'string', 'value': self}
    return TaggedString(self.value)`
于 2011-08-09T11:15:54.377 に答える
0

クラスで定義されている記述子をバイパスできるようにするソリューションは次のとおりです。

class BypassableDescriptor(object):
    pass

class String(BypassableDescriptor):
    def __init__(self, value=None):
        if value:
            self.value = str(value)

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        self.value = str(value)

    def to_db(self):
        return {'type': 'string', 'value': self.value}

class Integer(BypassableDescriptor):
    def __init__(self, value=None):
        if value:
            self.value = str(value)

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        self.value = int(value)

    def to_db(self):
        return {'type': 'integer', 'value': self.value}

class BypassDescriptor(object):
    def __init__(self, descriptor):
        self.descriptor = descriptor

    def __getattr__(self, name):
        return getattr(self.descriptor, name)

class AllowBypassableDescriptors(type):
    def __new__(cls, name, bases, members):
        new_members = {}
        for name, value in members.iteritems():
            if isinstance(value, BypassableDescriptor):
                new_members['real_' + name] = BypassDescriptor(value)
        members.update(new_members)
        return type.__new__(cls, name, bases, members)

class Example(object):
    __metaclass__ = AllowBypassableDescriptors

    name = String()
    age  = Integer()

    def __init__(self,name,age):
        self.name = name
        self.age  = age

    def save(self):
        data = dict(name = self.real_name.to_db(), age = self.real_age.to_db())

完全ではないことに注意してください。real_fieldname.method()代わりに常に呼び出すfieldname.method()必要があり、このフィールドにアクセスする必要があるすべてのクラスにメタクラスAllowBypassableDescriptorsを使用する必要があります。繰り返しになりますが、これは、記述子によってラップされたオブジェクトにモンキーパッチを適用することを回避する、かなり互換性のあるソリューションです。

とはいえ、記述子があなたがやろうとしていること(データベースへの書き込み?)に最適なソリューションであるかどうかはわかりません。

于 2011-05-16T22:52:02.257 に答える
-1

メソッドto_db内では、値に直接アクセスできます。

self.__dict__['value'] # value as key is not ideal, but that's what OP used

または、新しいスタイル クラスのみを使用している場合は、

object.__set__(self, name, value)

魔法の属性を使用しているため、魔法へのアクセス__dict__は完全に合理的です。

これは、[1] のドキュメントでも参照されています(申し訳ありませんが、 in__setattr__への直接の参照はありませんが、同じ問題ドメインです)。__dict____set__

If __setattr__() wants to assign to an instance attribute, it should not 
simply execute   self.name = value — this would cause a recursive call to itself. 
Instead, it should insert the value in the dictionary of instance attributes, e.g., 
self.__dict__[name] = value. For new-style classes, rather than accessing the instance 
dictionary, it should call the base class method with the same name, for example, 
object.__setattr__(self, name, value).

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

于 2011-05-16T21:33:08.143 に答える