15

TL;DR: property() された変数ごとに一意のゲッターとセッターのセットを定義する必要があるのは面倒です。一般的なゲッターとセッターを定義して、必要な変数で使用できますか?

いくつかの素敵なゲッターとセッターでクラスを作成するとしましょう:

class Foo
    def getter(self):
        return _bar+' sasquatch'

    def setter(self, value):
        _bar = value+' unicorns'

    bar = property(getter, setter)

かなりいいですよね?

ここで、「baz」という別の変数を入れて、このサスカッチ/ユニコーンの楽しみから除外したくないとしましょう。さて、ゲッターとセッターの別のセットを作成できると思います。

class Foo
    def bar_getter(self):
        return _bar+' sasquatch'

    def bar_setter(self, value):
        _bar = value+' unicorns'

    bar = property(bar_getter, bar_setter)

    def baz_getter(self):
        return _baz+' sasquatch'

    def baz_setter(self, value):
        _baz = value+' unicorns'

    baz = property(baz_getter, baz_setter)

しかし、それはあまり DRY ではなく、私のコードを不必要に混乱させます。私はそれを少しDRYerにすることができると思います:

class Foo
    def unicornify(self, value):
        return value+' unicorns'

    def sasquatchify(self, value):
        return value+' sasquatch'

    def bar_getter(self):
        return self.sasquatchify(_bar)

    def bar_setter(self, value):
        _bar = self.unicornify(_bar)

    bar = property(bar_getter, bar_setter)

    def baz_getter(self):
        return self.sasquatchify(_baz)

    def baz_setter(self, value):
        _baz = self.unicornify(_baz)

    baz = property(baz_getter, baz_setter)

それは私のコードを DRYer にするかもしれませんが、理想的ではありません。さらに 2 つの変数を unicornify して sasquatchify したい場合は、さらに 4 つの関数を追加する必要があります。

これを行うためのより良い方法があるはずです。複数の変数に対して単一のジェネリック getter および/または setter を使用できますか?

ユニコーンとサスカッチのない現実世界の実装: 私は SQLAlchemy ORM を使用しており、データベースからデータを保存および取得するときにデータの一部を変換したいと考えています。一部の変換は複数の変数に適用できますが、クラスを getter と setter で混乱させたくありません。

4

5 に答える 5

15

ちょうどどうですか:

def sasquatchicorn(name):
    return property(lambda self: getattr(self, name) + ' sasquatch',
                    lambda self, val: setattr(self, name, val + ' unicorns'))

class Foo(object):
    bar = sasquatchicorn('_bar')
    baz = sasquatchicorn('_baz')

もう少し一般的に:

def sasquatchify(val):
    return val + ' sasquatch'

def unicornify(val):
    return val + ' unicorns'

def getset(name, getting, setting):
    return property(lambda self: getting(getattr(self, name)),
                    lambda self, val: setattr(self, name, setting(val)))

class Foo(object):
    bar = getset('_bar', sasquatchify, unicornify)
    baz = getset('_baz', sasquatchify, unicornify)

または、 agfの回答で説明されているように、ほとんど作業を行わなくても、完全な記述子プロトコルを使用できます。

于 2012-04-13T23:04:03.313 に答える
6

これは、記述子プロトコル propertyが基づいているものです。

class Sasicorn(object):                              
    def __init__(self, attr):                        
        self.attr = "_" + attr                       
    def __get__(self, obj, objtype):                 
        return getattr(obj, self.attr) + ' sasquatch'
    def __set__(self, obj, value):                   
        setattr(obj, self.attr, value + ' unicorns') 

class Foo(object):                                   
    def __init__(self, value = "bar"):               
        self.bar = value                             
        self.baz = "baz"                             
    bar = Sasicorn('bar')                            
    baz = Sasicorn('baz')                            

foo = Foo()                                          
foo2 = Foo('other')                                  
print foo.bar                                        
# prints bar unicorns sasquatch
print foo.baz                                        
# prints baz unicorns sasquatch
print foo2.bar                                       
# prints other unicorns sasquatch

おもちゃの例では、工場出荷時propertyの機能で問題ないかもしれませんが、実際のユースケースではさらに制御が必要なようです。

于 2012-04-13T23:11:56.630 に答える
3

私の同僚は、クロージャーを使用してゲッター関数とセッター関数を返すことを提案しました。これを使用することにしました。

class Foo(object):
    def setter(var):
        def set(self, value):
            setattr(self, var, value+' unicorn')
        return set

    def getter(var):
        def get(self):
            return getattr(self, var)+' sasquatch'
        return get

    bar = property(getter('_bar'), setter('_bar'))

f = Foo()
f.foo = 'hi'
print f.foo

しかし、あなたの答えをありがとうございました:)

于 2012-04-14T03:05:56.003 に答える
-1
# coding=utf-8
__author__ = 'Ahmed Şeref GÜNEYSU'


class Student(object):
    def __init__(self, **kwargs):
        for k, v in kwargs.iteritems():
            self.__setattr__(k, v)

if __name__ == '__main__':
    o = Student(first_name='Ahmed Şeref', last_name='GÜNEYSU')
    print "{0} {1}".format(o.first_name, o.last_name)
    print o.email

与える

Ahmed Şeref GÜNEYSU
  File "/Users/ahmed/PycharmProjects/sanbox/abstract_classes/object_initializer/__init__.py", line 13, in <module>
    print o.email
AttributeError: 'Student' object has no attribute 'email'

Process finished with exit code 137
于 2015-12-05T18:56:29.100 に答える