سؤال

وأنا أحاول أن فئة فرعية 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)

<الفرعية> (التحسينات التي اقترحتها جارت هاردي في التعليقات.)

وأنت قد تكون قادرة على القيام بذلك عن طريق تجاوز __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