2009-05-07 23 views
16

strをサブクラス化しようとしていますが、その不変性のためにいくつかの問題があります。 derived.lower()などPythonの組み込み関数を拡張する

任意の新しい機能を必要としない継承されたメソッドの場合
class DerivedClass(str): 

    def __new__(cls, string): 
     ob = super(DerivedClass, cls).__new__(cls, string) 
     return ob 

    def upper(self): 
     #overridden, new functionality. Return ob of type DerivedClass. Great. 
     caps = super(DerivedClass, self).upper() 
     return DerivedClass(caps + '123') 

derived = DerivedClass('a') 

print derived.upper() #'A123' 
print type(derived.upper()) #<class '__main__.DerivedClass'> 
print derived.lower() #'a' 
print type(derived.lower()) #<type 'str'> 

、(代わりにstrの)タイプDerivedClassのオブジェクトを返すために、単純な、ニシキヘビの方法は何ですか?あるいは、私はderived.upper()と同じように、各str.method()を手動でオーバーライドしていますか?

編集:

#Any massive flaws in the following? 

class DerivedClass(str): 
    def __new__(cls, string): 
     ob = super(DerivedClass, cls).__new__(cls, string) 
     return ob 

    def upper(self): 
     caps = super(DerivedClass, self).upper() 
     return DerivedClass(caps + '123') 

    def __getattribute__(self, name): 
     att = super(DerivedClass, self).__getattribute__(name) 

     if not callable(att): 
      return att 

     def call_me_later(*args, **kwargs): 
      result = att(*args, **kwargs) 
      if isinstance(result, basestring): 
       return DerivedClass(result) 
      return result 
     return call_me_later 
+0

**関連項目:** http://stackoverflow.com/questions/tagged/python+monkeypatching – dreftymac

+0

**関連項目:** http://stackoverflow.com/questions/tagged/python+method-missing – dreftymac

答えて

5

Zr40が示唆するようにあなたは__getattribute__をオーバーライドすることによってこれを行うことができますが、呼び出し可能な関数を返すのgetAttribute持っている必要があります。以下のサンプルはあなたが望むものを与えるはずです。あなたが好きな場合は、部分的にせずにそれを実装することができても、それは、人生を楽にするためにfunctools.partialラッパーを使用しています。

from functools import partial 

class DerivedClass(str): 

    def __new__(cls, string): 
     ob = super(DerivedClass, cls).__new__(cls, string) 
     return ob 

    def upper(self): 
     #overridden, new functionality. Return ob of type DerivedClass. Great. 
     caps = super(DerivedClass, self).upper() 
     return DerivedClass(caps + '123') 

    def __getattribute__(self, name): 
     func = str.__getattribute__(self, name) 
     if name == 'upper': 
      return func 

     if not callable(func): 
      return func 

     def call_me_later(*args, **kwargs): 
      result = func(*args, **kwargs) 
      # Some str functions return lists, ints, etc 
      if isinstance(result, basestring: 
       return DerivedClass(result) 
      return result 

     return partial(call_me_later) 
-2

あなたは__getattribute__をオーバーライドすることによってこれを行うことができるかもしれません。

+0

str .__ getattribute__を意味しませんか? DerivedClass .__ dict__は、派生クラスにどの名前があるかを示します。 –

+0

これはTypeErrorをスローするようです。 print derived.lower() TypeError: 'DerivedClass'オブジェクトが呼び出し可能ではありません – user102975

+0

はい、str .__ getattribute__とする必要があります。引き続きTypeErrorを取得します。 – user102975

5

あなたは近いが、それぞれが多くのメソッドをオーバーライドによく伸びていないのチェックを両方です。

from functools import partial 

class DerivedClass(str): 
    def __new__(cls, string): 
     ob = super(DerivedClass, cls).__new__(cls, string) 
     return ob 

    def upper(self): 
     caps = super(DerivedClass, self).upper() 
     return DerivedClass(caps + '123') 

    def __getattribute__(self, name): 
     if name in ['__dict__', '__members__', '__methods__', '__class__']: 
      return object.__getattribute__(self, name) 
     func = str.__getattribute__(self, name) 
     if name in self.__dict__.keys() or not callable(func): 
      return func 

     def call_me_later(*args, **kwargs): 
      result = func(*args, **kwargs) 
      # Some str functions return lists, ints, etc 
      if isinstance(result, basestring): 
       return DerivedClass(result) 
      return result 

     return partial(call_me_later) 

(コメントでjarret hardieによって示唆改良。)

+0

nameのためにself .__ dict __。keys()をチェックする必要がありますか? str .__ getattribute __(self、name)の呼び出しは、(オーバーライドされているかどうかにかかわらず)メソッドを期待どおりに呼び出すように見え、 'call_me_later'は必要に応じてサブクラスのインスタンスを返します。私はcallable(func)がデータメンバーにアクセスしようとする試みを捕まえることだと考えます。私は貢献をわずかに修正し、質問を編集しました。簡単にするために、私はまだそれに精通していないので、部分は使用されていません。思考?もう一度ありがとう:) – user102975

+0

@trigue - printステートメントを__getattribute__に入れてください。あなたはそれが毎回呼ばれることがわかります。 – tghw

7

クラスデコレータこだわり使用 - おおよそ(未テストコード):

@do_overrides 
class Myst(str): 
    def upper(self): 
    ...&c... 

def do_overrides(cls): 
    done = set(dir(cls)) 
    base = cls.__bases__[0] 
    def wrap(f): 
    def wrapper(*a, **k): 
     r = f(*a, **k) 
     if isinstance(r, base): 
     r = cls(r) 
     return r 
    for m in dir(base): 
    if m in done or not callable(m): 
     continue 
    setattr(cls, m, wrap(getattr(base, m))) 
関連する問題