2012-04-13 2 views
13

TL; DR:プロパティごとにゲッターとセッターの固有のセットを定義する必要があります。ジェネリックゲッターとセッターを定義し、必要な変数でそれらを使用できますか?Python:ジェネリックゲッターとセッター

はのは、私はいくつかの素晴らしいgetterとsetterを持つクラスを作りましょう:

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) 

をしかし、それは非常に乾燥し、不クラッタ私のコードではありません。 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つの変数を統一してsasquatchifyしたい場合は、さらに4つの関数を追加する必要があります。

これを行うには良い方法があるに違いありません。複数の変数にわたって単一のジェネレータまたはセッタを使用できますか?

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

答えて

12

方法についてちょうど:

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's answerで説明したようにかろうじてより多くの仕事で、あなたは、完全な記述プロトコルを使用することができます。

+1

を与えるが、ラムダは私が必要なものには適していませんこれは、単一の表現にセッターとゲッターを制限行う。 –

+0

@TheronLuhn同じことをしますが、一般的な関数( 'sasquatchicorn'の内部関数として定義されているか、引数として名前を取る)を使用します。または、[agf](http://stackoverflow.com/a/10149431/344821)の回答のように完全な記述子を処理してください。 – Dougal

+0

また、私の編集では、完全な記述子を行うよりも多少作業が少なくて済みますか?多分? :) – Dougal

5

これはdescriptor protocolpropertyが基づいているものであるためです:ファクトリ関数で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 

+0

私はしばらくこの問題に取り組んできましたが、間違っているかもしれませんが、実際にクラスのすべてのインスタンスで共有されるクラスレベルの「プロパティ」を実際に定義するように見えます。この回答は役に立ちますが、その行動は確かに私にとってはありません。 – krs013

+1

@ krs013あなたが正しいです、それは記述子プロトコルを示していましたが、あまり有用ではありませんでした。私はクラスではなくインスタンスに値を格納するように更新しました。 – agf

+0

ありがとう、これは私が探していた動作です。他の場所では、記述子がオブジェクトの '__dict__'に直接アクセスする場所を見たことがありますが、これはよりきれいに見えます。 – krs013

1

私の同僚は、私が使用することを決めたものであるgetterとsetter関数を返すためにクロージャを使用することを提案しました。

あなたは過去と未来のすべての属性のためにこれを定義することができます
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 

しかし、あなたの答えのためのあなたのすべてに感謝:)

+1

これは基本的にDougalの答えと同じですが、lambdasではなく関数を使用しています。 – Darthfett

+0

それは?申し訳ありませんが、私はPythonの新しさです。私はドゥガルを受け入れます。 –

1

getattributeを使用してsetattr

class Foo(object):                               

    x = 3 

    def __getattribute__(self, attr): 
    return str(object.__getattribute__(self, attr)) + ' sasquatch' 

    def __setattr__(self, attr, value): 
    object.__setattr__(self, attr, str(value) + ' unicorn') 

print Foo.x 
f = Foo() 
print f.x 
f.y = 4 
print f.y 

この版画:

3 
3 sasquatch 
4 unicorn sasquatch 
-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 
関連する問題