Новые классы стиля работают быстрее и точнее, чем классы старого стиля. Таким образом, не более дорогие __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-аргументный оператор 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