0

記述子クラスは次のとおりです。

class Des(object):
    def __get__(self, instance, owner): ...
    def __set__(self, instance, value): ...
    def __delete__(self, instance): ...

class Sub(object):
    attr = Des()

X = sub()

質問

  1. 存在のポイントがわかりませんがowner、どうすれば使えますか?

  2. attrを読み取り専用にするには、省略せず__set__に、割り当てをキャッチして例外を発生させるように定義する必要があります。したがってX.attr = 123、失敗しますが、__set__の引数にが含まれていませんowner。つまり、まだ実行できSub.attr = 123ますよね?

4

6 に答える 6

4

http://docs.python.org/reference/datamodel.html#implementing-descriptorsを参照してください:

ownerは常に所有者クラスinstanceですが、は属性がアクセスされたインスタンスであり、属性が所有者を介してアクセスされた場合はNoneです。

使用するケースは、クラスプロパティownerを作成することです。

class _ContentQueryProperty(object):
    def __get__(self, inst, cls):
        return Content.query.filter_by(type=cls.TYPE)
于 2012-05-12T09:24:15.310 に答える
2

次の例を試すことができます。

# the descriptor protocol defines 3 methods:
#    __get__()
#    __set__()
#    __delete__()

# any class implementing any of the above methods is a descriptor
# as in this class
class Trace(object):
    def __init__(self, name):
        self.name = name

    def __get__(self, obj, objtype):
        print "GET:" + self.name + " = " + str(obj.__dict__[self.name])
        return obj.__dict__[self.name]

    def __set__(self, obj, value):
        obj.__dict__[self.name] = value
        print "SET:" + self.name + " = " + str(obj.__dict__[self.name])

# define the attributes of your class (must derive from object)
#  to be references to instances of a descriptor

class Point(object):
# NOTES:
# 1. descriptor invoked by dotted attribute access:  A.x or a.x
# 2. descripor reference must be stored in the class dict, not the instance dict
# 3. descriptor not invoked by dictionary access: Point.__dict__['x']

    x = Trace("x")
    y = Trace("y")

    def __init__(self, x0, y0):
        self.x = x0
        self.y = y0

    def moveBy(self, dx, dy):
        self.x = self.x + dx     # attribute access does trigger descriptor
        self.y = self.y + dy


# trace all getters and setters    
p1 = Point(15, 25)
p1.x = 20
p1.y = 35
result = p1.x
p2 = Point(16, 26)
p2.x = 30
p2.moveBy(1, 1)
于 2013-06-08T21:41:02.550 に答える
1

私は同様の混乱でこの質問に出くわしました.自分で答えた後、繁栄のためにここで私の発見を報告するのが賢明だと思われました.

ThiefMaster が既に指摘したように、「所有者」パラメーターはclassproperty. クラスに非メソッド属性としてマスクされたメソッドが必要な場合があり、ownerパラメーターを使用すると、通常の記述子でそれを行うことができます。

しかし、それは問題の半分にすぎません。「読み取り専用」の問題については、次のことがわかりました。

ここで最初に答えを見つけました: http://martyalchin.com/2007/nov/23/python-descriptors-part-1-of-2/。最初は理解できず、理解するのに5分ほどかかりました。最終的に私を納得させたのは、例を考え出すことでした。

最も一般的な記述子を考えてみましょう: property. 変数 count がアクセスされた回数であるプロパティ count を持つ簡単なサンプル クラスを使用してみましょう。

class MyClass(object):
    def __init__(self):
        self._count = 0
    @property
    def count(self):
        tmp = self._count
        self._count += 1
        return tmp
    @count.setter
    def setcount(self):
        raise AttributeError('read-only attribute')
    @count.deleter
    def delcount(self):
        raise AttributeError('read-only attribute')

既に確立したように、関数のownerパラメーターは__get__、クラス レベルで属性にアクセスするときに、__get__関数が getattr 呼び出しをインターセプトすることを意味します。たまたま、 のコードは、クラス レベルでアクセスされたときにプロパティ自体を返すpropertyだけですが、何でもできます (静的な値を返すなど)。

とが同じように機能する__set__とどうなるか想像してみてください。andメソッドは、インスタンス レベルに加えて、クラス レベルですべての and 呼び出しを__del__インターセプトします。__set____del__setattrdelattr

結果として、これは の "count" 属性MyClassが事実上変更不可能であることを意味します。Java のような静的でコンパイルされた言語でのプログラミングに慣れている場合、アプリケーション コードでクラスを変更できないため、これはあまり興味深いものではないように思われます。しかし、Python ではそれが可能です。クラスはオブジェクトと見なされ、それらの属性を動的に割り当てることができます。たとえば、MyClassがサードパーティ モジュールの一部であり、MyClassアプリケーションにとってほぼ完全に完璧であるとしましょう ( のコード以外に他のコードがあると仮定しましょうcount)。代わりに、インスタンスごとに常に 10 を返すようにします。次のことができます。

>>> MyClass.count = 10
>>> myinstance = MyClass()
>>> myinstance.count
10

__set__への呼び出しが傍受された場合setattr(MyClass, 'count')、実際に MyClass を変更する方法はありません。代わりに、コードはsetcountそれを傍受し、何もできませんでした。唯一の解決策は、MyClass のソース コードを編集することです。(サブクラスでそれを定義してもコードが呼び出されると思うので、サブクラスで上書きできるかどうかさえsetattrわかりません。しかし、確信が持てません。ここではすでに反事実を扱っているので、私はしません。実際にテストする方法はありません。)

さて、あなたは「まさにそれが私の望みです! 私は自分のクラスの属性を意図的にユーザーに再割り当てさせたくなかったのです!」と言っているかもしれません。それに対して、私が言えることは、単純な記述子を使用してあなたが望んでいたことは不可能であるということだけです。私はあなたに上記の理由を説明します. クラス属性の再割り当てを許可することは、現在の Python のイディオムに沿ったものです。

あなたが本当に本当に読み取り専用のクラス属性を作りたいのなら、その方法を教えてくれるとは思いません。しかし、解決策がある場合、おそらくメタクラスを使用し、メタクラスを作成するかpropertysetattrおよびdelattrメタクラスのコードを変更する必要があります。しかし、これはディープ マジックであり、この回答 (および Python に関する私自身の能力) の範囲をはるかに超えています。

于 2012-12-14T19:32:17.050 に答える
0
  1. この__set__メソッドは、インスタンスの属性を変更することになっています。しかし、すべてのインスタンスで共有され、そのためにクラス内に存在する属性を変更したい場合はどうすればよいでしょうか? たとえば、クラス属性です。これは、クラスにアクセスできる場合にのみ実行できるため、所有者の引数です。

  2. はい、クラスを介して属性に割り当てる場合、プロパティ/記述子を上書きできます。Python は動的言語であるため、これは設計によるものです。

ずっと前に尋ねられましたが、質問に答えてくれることを願っています。

于 2017-03-20T11:54:25.140 に答える