8

私は最近、Python で新しいスタイルのクラス (オブジェクトから派生したもの) を使用しようとしていると述べました。それらに慣れるための演習として、属性として多数のクラス インスタンスを持つクラスを定義しようとしています。これらのクラス インスタンスのそれぞれは、1 次元リスト、2 次元配列、スカラーなどの異なるタイプのデータを記述します。本質的に私は書けるようになりたい

some_class.data_type.some_variable

wheredata_typeは、変数のコレクションを記述するクラス インスタンスです。profiles_1d以下は、インスタンスとかなり一般的な名前を使用して、これを実装する最初の試みです。

class profiles_1d(object):
    def __init__(self, x, y1=None, y2=None, y3=None):
        self.x = x
        self.y1 = y1
        self.y2 = y2
        self.y3 = y3

class collection(object):
    def __init__(self):
        self._profiles_1d = None

    def get_profiles(self):
        return self._profiles_1d

    def set_profiles(self, x, *args, **kwargs):
        self._profiles_1d = profiles_1d(x, *args, **kwargs)

    def del_profiles(self):
        self._profiles_1d = None

    profiles1d = property(fget=get_profiles, fset=set_profiles, fdel=del_profiles,
        doc="One dimensional profiles")

上記のコードは、この問題に取り組む適切な方法でしょうか。私が見た使用例はproperty、変数の値を設定するだけです。ここでは、あるクラスのインスタンスを初期化するために set メソッドが必要です。そうでない場合は、これを実装するためのより良い方法の提案があれば大歓迎です。

さらに、 set メソッドを定義する方法は大丈夫ですか? 一般的に、 set メソッドは、私が理解している限り、ユーザーが入力したときに何をすべきかを定義します。この例では、

collection.profiles1d = ...

profiles_1d上記のコードでインスタンスの属性を正しく設定できる唯一の方法は typecollection.set_profiles([...], y1=[...], ...)ですが、このメソッドを直接呼び出すべきではないと思います。理想的には、次のように入力したいと思いcollection.profiles = ([...], y1=[...], ...)ます:これは正しい/可能ですか?

最後に、クラスの新しいスタイルに関して多くのデコレーターが言及されているのを見てきましたが、これについてはほとんど知りません。ここでデコレータの使用は適切ですか? これは、この問題についてもっと知っておくべきことですか?

4

2 に答える 2

10

まず、新しいスタイルの授業を学んでいるのは良いことです。彼らにはたくさんの利点があります。

Python でプロパティを作成する最新の方法は次のとおりです。

class Collection(object):
    def __init__(self):
        self._profiles_1d = None

    @property
    def profiles(self):
        """One dimensional profiles"""
        return self._profiles_1d

    @profiles.setter
    def profiles(self, argtuple):
        args, kwargs = argtuple
        self._profiles_1d = profiles_1d(*args, **kwargs)

    @profiles.deleter
    def profiles(self):
        self._profiles_1d = None

次に、実行して設定profilesします

collection = Collection()
collection.profiles = (arg1, arg2, arg3), {'kwarg1':val1, 'kwarg2':val2}

3 つのメソッドすべてが同じ名前であることに注意してください。

これは通常行われません。属性をコンストラクターに渡すか、自分自身をcollection作成し​​てからコンストラクターに渡すか、コンストラクターに渡します。profiles_1dcollections.profiles = myprofiles1d

属性へのアクセスをクラスで管理するのではなく、属性でそれ自体へのアクセスを管理する場合は、属性を記述子を持つクラスにします。上記のプロパティの例とは異なり、実際にデータを属性内に格納する必要がある場合は、これを行います (別の偽のプライベート インスタンス変数ではなく)。また、同じプロパティを何度も使用する場合にも適しています。これを記述子にすると、コードを何度も記述したり、基底クラスを使用したりする必要がなくなります。

私は実際に @S.Lott のページが好きです -- Building Skills in Python's Attributes, Properties and Descriptors

于 2011-08-11T12:01:41.743 に答える
1

他のインスタンス メソッドを呼び出す必要がある s (または他の記述子) を作成する場合、命名規則はそれらのメソッドpropertyの前に anを追加することです。_したがって、上記の名前は_get_profiles_set_profiles、および になり_del_profilesます。

Python 2.6 以降では、各プロパティはデコレータでもあるため、(そうでなければ役に立たない)_nameメソッドを作成する必要はありません。

@property
def test(self):
    return self._test

@test.setter
def test(self, newvalue):
    # validate newvalue if necessary
    self._test = newvalue

@test.deleter
def test(self):
    del self._test

あなたのコードはprofilesインスタンスではなくクラスに設定しようとしているようです - もしそうなら、クラスのプロパティはオブジェクトでcollections.profiles上書きされるように機能しません、プロパティを上書きしprofiles_1dます...これが本当にあなたが必要に応じて、メタクラスを作成し、代わりにプロパティを配置する必要があります。

うまくいけば、インスタンスについて話しているので、クラスは次のようになります。

class Collection(object):  # notice the capital C in Collection
    def __init__(self):
        self._profiles_1d = None

    @property
    def profiles1d(self):
        "One dimensional profiles"
        return self._profiles_1d

    @profiles1d.setter
    def profiles1d(self, value):
        self._profiles_1d = profiles_1d(*value)

    @profiles1d.deleter
    def profiles1d(self):
        del self._profiles_1d

そして、あなたは次のようなことをします:

collection = Collection()
collection.profiles1d = x, y1, y2, y3

注意すべき点がいくつかあります。メソッドは、 と new のsetter2 つの項目だけで呼び出されます (これが、手動で呼び出さなければならなかった理由です)。代入を行う場合、キーワードの命名はオプションではありません (代入ではない関数呼び出しでのみ機能します)。それがあなたにとって理にかなっているなら、あなたは空想にふけって次のようなことをすることができます:selfvalueset_profiles1d

collection.profiles1d = (x, dict(y1=y1, y2=y2, y3=y3))

を次のように変更setterします。

    @profiles1d.setter
    def profiles1d(self, value):
        x, y = value
        self._profiles_1d = profiles_1d(x, **y)

これはまだかなり読みやすいです(x, y1, y2, y3私自身はこのバージョンの方が好きですが)。

于 2012-01-06T19:54:27.213 に答える