문제

나는 서브 클래스를하려고합니다 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'>  

새로운 기능이 필요하지 않은 상속 메소드의 경우 derived.lower(), 유형의 객체를 반환하는 간단하고 pythonic 방법이 있습니까? DerivedClass (대신에 str)? 아니면 내가했던 것처럼 각 str.method ()를 수동으로 재정의 했습니까? derived.upper()?

편집하다:

#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
도움이 되었습니까?

해결책

당신은 재정의하여 이것을 할 수 있습니다 __getattribute__ Zr40에서 알 수 있듯이, 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)

다른 팁

클래스 데코레이터에 잘 사용 - 대략적으로 (테스트되지 않은 코드) :

@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)))

둘 다 가깝지만 각각을 확인하는 것은 많은 방법을 무시하는 데 잘 확장되지 않습니다.

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 의견에.)

당신은 재정의함으로써 이것을 할 수 있습니다 __getattribute__.

def __getattribute__(self, name):
    # Simple hardcoded check for upper.
    # I'm sure there are better ways to get the list of defined methods in
    # your class and see if name is contained in it.
    if name == 'upper':
        return object.__getattribute__(self, name)

    return DerivedClass(object.__getattribute__(self, name))
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top