2009-05-07 15 views
16

Ich versuche, str Unterklasse, aber einige Schwierigkeiten aufgrund seiner Unveränderlichkeit.Erweitern Python eingebaute Str

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'> 

für geerbte Methoden, die, wie derived.lower() keine neue Funktionalität erfordern, gibt es eine einfache, pythonic Weise ein Objekt vom Typ zurückzukehren DerivedClass (statt str)? Oder stehe ich fest, manuell jede str.method() überschreiben, wie ich es mit derived.upper() getan habe?

Edit:

#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

** Siehe auch: ** http://stackoverflow.com/questions/tagged/python+monkeypatching – dreftymac

+0

** Siehe auch: ** http://stackoverflow.com/questions/tagged/python+method-missing – dreftymac

Antwort

5

Sie können dies durch zwingende __getattribute__ als ZR40 vermuten lässt, aber Sie werden eine aufrufbare Funktion getAttribute zurückkehren müssen haben. Das folgende Beispiel sollte Ihnen geben, was Sie wollen; es nutzt die functools.partial Wrapper das Leben leichter zu machen, wenn Sie es ohne Teil implementieren können, wenn Sie mögen:

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

Sie könnten in der Lage sein, diese __getattribute__ durch zwingende zu tun.

+0

Meinst du nicht str .__ getattribute__? Und DerivedClass .__ dict__ würde Ihnen sagen, welche Namen in der abgeleiteten Klasse sind. –

+0

Dies scheint einen TypeError zu werfen. print abgeleitete.lower() TypeError: 'DerivedClass' Objekt ist nicht aufrufbar – user102975

+0

Ja, ich glaube, es sollte str .__ getattribute__ sein. Immer noch den TypeError. – user102975

5

Sie sind beide in der Nähe, aber für jede Prüfung erstreckt sich nicht gut an viele Methoden überschreiben.

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) 

(Verbesserungen von jarret hardie in Kommentaren vorgeschlagen.)

+0

Ist es notwendig, self .__ dict __. Keys() nach Namen zu überprüfen? Der Aufruf von str .__ getattribute __ (self, name) scheint Methoden wie erwartet aufzurufen (überschrieben oder nicht) und 'call_me_later' gibt ggf. Instanzen der Unterklasse zurück. Ich nehme an, callable (func) ist es, alle Versuche zu versuchen, auf Datenmitglieder zuzugreifen. Ich habe die Beiträge etwas modifiziert und die Frage bearbeitet. Aus Gründen der Einfachheit wird partiell nicht verwendet, da ich es noch nicht kenne. Gedanken? Nochmals vielen Dank :) – user102975

+0

@trigue - Setzen Sie eine Druckanweisung in __getattribute__. Du wirst sehen, dass es jedes Mal aufgerufen wird. – tghw

7

Gute Verwendung für eine Klasse Dekorateur - grob (ungetestet Code):

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

und

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))) 
Verwandte Themen