新样式类比旧样式类运行得更快、更精确。因此,没有更昂贵__getattr__
的 , __getattribute__
,__coerce__
要求任何便宜的理由和有问题的顺序。
旧样式__coerce__
也有问题,即使您已经为某些特殊目的重载了运算符方法,它也会被调用。它要求强制转换为相同的常见类型,并且仅限于某些二进制操作。想想 int / float / string 的所有其他方法和属性 - 以及 pow()。由于coerce
PY3 中缺少所有这些限制。问题示例针对相当广泛的虚拟化。
对于新样式类,它只是一个循环,以提供许多“类似”的方法,只需很少的代码,或者将这些调用路由到虚拟处理程序,然后以正确和细粒度的方式快速、精确地定义和子类化。那不是“Python 语言的回归”。
但是,我不会只为这样的循环或提供简单的基类行为而使用其他答案中所示的元类。那将是用大锤敲碎坚果。
这里是“变体”虚拟化的示例助手:
def Virtual(*methods):
"""Build a (new style) base or mixin class, which routes method or
operator calls to one __virtualmeth__ and attribute lookups to
__virtualget__ and __virtualset__ optionally.
*methods (strings, classes): Providing method names to be routed
"""
class VirtualBase(object):
def __virtualmeth__(self, methname, *args, **kw):
raise NotImplementedError
def _mkmeth(methname, thing):
if not callable(thing):
prop = property(lambda self:self.__virtualget__(methname),
lambda self, v:self.__virtualset__(methname, v))
return prop
def _meth(self, *args, **kw):
return self.__virtualmeth__(methname, *args, **kw)
_meth.__name__ = methname
return _meth
for m in methods:
for name, thing in (isinstance(m, str) and
{m:lambda:None} or m.__dict__).items():
if name not in ('__new__', '__init__', '__setattr__', ##'__cmp__',
'__getattribute__', '__doc__', ): ##'__getattr__',
setattr(VirtualBase, name, _mkmeth(name, thing))
return VirtualBase
这里有一个示例用例:一个照应!(PY2 和 PY3):
import operator
class Anaphor(Virtual(int, float, str)):
"""remember a sub-expression comfortably:
A = Anaphor() # at least per thread / TLS
if re.search(...) >> A:
print(A.groups(), +A)
if A(x % 7) != 0:
print(A, 1 + A, A < 3.0, A.real, '%.2f' % A, +A)
"""
value = 0
def __virtualmeth__(self, methname, *args, **kw):
try: r = getattr(self.value, methname)(*args, **kw)
except AttributeError:
return getattr(operator, methname)(self.value, *args, **kw)
if r is NotImplemented: # simple type -> coerce
try: tcommon = type(self.value + args[0]) # PY2 coerce
except: return NotImplemented
return getattr(tcommon(self.value), methname)(*args, **kw)
return r
def __call__(self, value):
self.value = value
return value
__lshift__ = __rrshift__ = __call__ # A << x; x >> A
def __pos__(self): # real = +A
return self.value
def __getattr__(self, name):
return getattr(self.value, name)
def __repr__(self):
return '<Anaphor:%r>' % self.value
它还无缝处理 3-arg 运算符pow()
:-):
>>> A = Anaphor()
>>> x = 1
>>> if x + 11 >> A:
... print repr(A), A, +A, 'y' * A, 3.0 < A, pow(A, 2, 100)
...
<Anaphor:12> 12 12 yyyyyyyyyyyy True 44