2012-03-08 4 views
3

私は以下のコードについていくつかの質問があります。プロパティPythonでデコレータと設定した機能

1 class Test(object): 
    2  def __init__(self): 
    3   print "Object instance created." 
    4   self._x = raw_input("Initial value of x = ") 
    5   print "Initial value of x set." 
    6 
    7  def Property(func): 
    8   return property(**func()) 
    9 
10  @Property 
11  def x(): 
12   def fget(self): 
13    print 'Getting x' 
14    return self._x 
15   def fset(self, val): 
16    print 'Setting x' 
17    self._x = val 
18   def fdel(self): 
19    print 'Deleting x' 
20    del self._x 
21   doc = "A test case" 
22   return locals() 
  1. なぜProperty()機能が必要なの?
  2. 私はちょうどreturn locals()を入力してから@propertyを直接デコレータに使用できないのはなぜですか?

私がエラーを受けたとき、xは引数を取らず、与えられたもの(おそらくは 'self')を取ると言います。私はPythonが@x.setterオプションを持っていることを知っていますが、私は2.4を定期的に使用することを余儀なくされています。それでも、は、それをすべて1つのブロックに定義するよりもエレガントではないようです。

@propertyを使用してすべてを1つのブロックに定義する方法はありますか?

+0

私は実際にあなたの回避策が好きです - 私はそれを使い始めるかもしれません! :) –

答えて

2

あなたが投稿したコードにデコレータとして直接使用することはできません。そのように使用するように設計されておらず、動作しません。

デコレータとして使用する場合、propertyはゲッターに関数を変換します。関数として使用すると、getter、setter、deleter、およびdocを渡すことができます。

locals()戻りすべて地元の人々、あなたが辞書を持っているでしょうのでfgetfsetfdeldocProperty、および__init__ - それはあまりにも多くの引数を渡されたため、爆破するpropertyの原因となります。

個人的には、私は@x.setter@x.deleterスタイルが好きです。クラス名スペースに不要な関数名がつくことはありません。

あなたは自分自身を転がし、定期的に2.4を使用する必要がある場合(または、私が行ったように2.6から最新のを盗む;):

class property(object): 
     "2.6 properties for 2.5-"  
     def __init__(self, fget=None, fset=None, fdel=None, doc=None): 
      self.fget = fget 
      self.fset = fset 
      self.fdel = fdel 
      self.__doc__ = doc or fget.__doc__ 
     def __call__(self, func): 
      self.fget = func 
      if not self.__doc__: 
       self.__doc__ = fget.__doc__ 
     def __get__(self, obj, objtype=None): 
      if obj is None: 
       return self   
      if self.fget is None: 
       raise AttributeError("unreadable attribute") 
      return self.fget(obj) 
     def __set__(self, obj, value): 
      if self.fset is None: 
       raise AttributeError("can't set attribute") 
      self.fset(obj, value) 
     def __delete__(self, obj): 
      if self.fdel is None: 
       raise AttributeError("can't delete attribute") 
      self.fdel(obj) 
     def setter(self, func): 
      self.fset = func 
      return self 
     def deleter(self, func): 
      self.fdel = func 
      return self 
+0

あなたの返事をありがとう。 '@ x.setter'や' @ x.deleter'のない最良の方法は、デコレータとして 'property'を使わないことです。'x = property(xget、xset、xdel、xdoc)'と言うだけで、クラス内の3つの関数を定義するために、最初の投稿のハックよりも少ない行を使います。私はそれが将来私がやることになると思う。 – Mikey08

2

あなた 1つのブロックにそれをすべて行うことができますない使用して@propertyのクラスを定義してインスタンス化することにより、__get__()__set__()、および__delete__()のメソッドを実装します。詳細はImplementing Descriptorsを参照してください:

class Test(object): 
    def __init__(self): 
     print "Object instance created." 
     self._x = raw_input("Initial value of x = ") 
     print "Initial value of x set." 
    class x(object): 
     def __get__(self, instance, owner): 
      print 'Getting x' 
      return instance._x 
     def __set__(self, instance, value): 
      print 'Setting x' 
      instance._x = value 
     def __delete__(self, instance): 
      print 'Deleting x' 
      del instance._x 
     __doc__ = "A test case" 
    x = x() 

property()は、上記を記述するためのショートカットです、そしてあなたの例のクラスのProperty()方法は別途関数を記述し、property()にそれらを渡すために持つためのショートカットです。代わりに、関数を定義する関数を記述し、それを返して、property()に渡します。

@propertyを使用できないのは、デコレータが1つのオブジェクトを飾るからです。クラスなどのコンテナが必要なので、その時点で直接記述子を書くこともできます。

+0

+1について説明しましたが、私はこのようにはしません: 'x'はインスタンス化されなければなりません。最後にはデコレータが作成され、関数/クラス定義簡単に見落とされることはありません。 –

+0

ええ、私は 'x = x()'と書かれているようです。さらに悪いことに、 'x = X();デルX' ... – kindall