Python:强制新的类类型
我希望这段代码能“正常工作”:
def main():
c = Castable()
print c/3
print 2-c
print c%7
print c**2
print "%s" % c
print "%i" % c
print "%f" % c
当然,简单的方法是写 int(c)/3
,但我想为一个配置的小语言启用更简单的类似perl的语法。
值得注意的是,如果我使用“旧式”类(不从对象继承),我可以通过定义一个 __coerce__
方法来很简单地做到这一点,但旧式类已经不推荐使用,并将在python3中被移除。
当我用新式类做同样的事情时,我得到了这个错误:
TypeError: unsupported operand type(s) for /: 'Castable' and 'int'
我认为这是设计使然,但那我该如何用新式类模拟旧式的 __coerce__
行为呢?你可以在下面找到我当前的解决方案,但它看起来相当丑陋且冗长。
这是相关的文档:(我想)
额外加分:
print pow(c, 2, 100)
5 个回答
3
class MetaCastable(type):
__binary_ops = (
'add', 'sub', 'mul', 'floordiv', 'mod', 'divmod', 'pow', 'lshift',
'rshift', 'and', 'xor', 'or', 'div', 'truediv',
)
__unary_ops = ( 'neg', 'pos', 'abs', 'invert', )
def __new__(mcs, name, bases, dict):
def make_binary_op(op):
fn = lambda self, other: self.__op__(op, other)
fn.__name__ = op
return fn
for opname in mcs.__binary_ops:
for op in ( '__%s__', '__r%s__' ):
op %= opname
if op in dict:
continue
dict[op] = make_binary_op(op)
def make_unary_op(op):
fn = lambda self: self.__op__(op, None)
fn.__name__ = op
return fn
for opname in mcs.__unary_ops:
op = '__%s__' % opname
if op in dict:
continue
dict[op] = make_unary_op(op)
return type.__new__(mcs, name, bases, dict)
class Castable(object):
__metaclass__ = MetaCastable
def __str__(self):
print "str!"
return "<Castable>"
def __int__(self):
print "int!"
return 42
def __float__(self):
print "float!"
return 2.718281828459045
def __op__(self, op, other):
if other is None:
print "%s(%s)" % (op, self)
self, other = coerce(self, 0.0)
return getattr(self, op)()
else:
print "%s %s %s" % (self, op, other)
self, other = coerce(self, other)
return getattr(self, op)(other)
def __coerce__(self, other):
print "coercing like %r!" % other
return (type(other)(self), other)
当然可以!请把你想要翻译的内容发给我,我会帮你把它变得更简单易懂。
8
如果你想让 c/3
这个操作能正常工作,你需要定义一个叫做 __div__
的东西。Python 不会自动把你的对象转换成数字。
5
这个方法可以用,而且经过几次改进后看起来好一些(感谢@jchl),但我觉得这还是有点多余,特别是考虑到用“老式”类时你可以免费得到这些功能。
我仍在寻找更好的解决方案。如果没有更好的方法,我觉得这在Python语言上算是退步。
def ops_list():
"calculate the list of overloadable operators"
#<type 'object'> has functions but no operations
not_ops = dir(object)
#calculate the list of operation names
ops = set()
for mytype in (int, float, str):
for op in dir(mytype):
if op.endswith("__") and op not in not_ops:
ops.add(op)
return sorted(ops)
class MetaCastable(type):
__ops = ops_list()
def __new__(mcs, name, bases, dict):
#pass any undefined ops to self.__op__
def add_op(op):
if op in dict:
return
fn = lambda self, *args: self.__op__(op, args)
fn.__name__ = op
dict[op] = fn
for op in mcs.__ops:
add_op( op )
return type.__new__(mcs, name, bases, dict)
class Castable(object):
__metaclass__ = MetaCastable
def __str__(self):
print "str!"
return "<Castable>"
def __int__(self):
print "int!"
return 42
def __float__(self):
print "float!"
return 2.718281828459045
def __op__(self, op, args):
try:
other = args[0]
except IndexError:
other = None
print "%s %s %s" % (self, op, other)
self, other = coerce(self, other)
return getattr(self, op)(*args)
def __coerce__(self, other):
print "coercing like %r!" % other
if other is None: other = 0.0
return (type(other)(self), other)