我正在尝试继承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
答案 0 :(得分: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)))
答案 1 :(得分:5)
你可以通过覆盖__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)
答案 2 :(得分: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建议的改进。)
答案 3 :(得分:-2)
您可以通过覆盖__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))