我是新手,请原谅非标准术语,如果我应该添加代码以便让这个问题更清楚,请告诉我。
让我们说我们尝试上课#34; Rational"在Python中。 (我知道其中一个已经内置,但为了这个问题的目的而忽略了它。)
例如,我们可以使用__add__
和__mul__
来教授Python如何解释a + b
或a * b
形式的代码,
其中a
和b
是Rational。
现在,可能会发生这样的情况,在其他地方,人们想要计算a + b
,其中a
是理性的,但b
是整数。我们可以通过修改Rational类中的__add__
代码来包含if语句,例如,
def __add__(self, b):
if isinstance(b, int):
brat = rational(b, 1)
return self + brat
else:
y = rational(self.num*b.den + b.num*self.den , b.den*self.den)
y = y.lowest_terms()
return y
我们可以类似地修改我们的__mul__
代码,我们的__div__
代码等。但是这种解决方案至少存在两个问题:
int
时才有效。首先
论证仍然必须是理性的;没有办法写一个
Rational类中允许我们在其中添加a + b
的方法
一个int和be是一个Rational。这种技术存在吗? (我已经标记了这种强制,因为我认为这就是其他语境中的强制行为,但我的理解是在Python中不推荐使用强制行为。)
答案 0 :(得分:2)
您可以通过在类初始化程序中进行映射来避免重复。这是一个处理整数的简单演示。正确处理float
将留给读者练习。 :)但是,我已经展示了如何轻松实现__radd__
和__iadd__
,这是处理{{1}的神奇方法(又名dunder方法) }}
我的代码保留代码中的+=
作为类名,即使Python中的类名通常是CamelCase。
rational
<强>输出强>
def gcd(a, b):
while b > 0:
a, b = b, a%b
return a
class rational(object):
def __init__(self, num, den=1):
if isinstance(num, rational):
self.copy(num)
else:
self.num = num
self.den = den
def copy(self, other):
self.num = other.num
self.den = other.den
def __str__(self):
return '{0} / {1}'.format(self.num, self.den)
def lowest_terms(self):
g = gcd(self.num, self.den)
return rational(self.num // g, self.den // g)
def __add__(self, other):
other = rational(other)
y = rational(self.num*other.den + other.num*self.den, other.den*self.den)
return y.lowest_terms()
def __radd__(self, other):
return rational(other) + self
def __iadd__(self, other):
self.copy(self + rational(other))
return self
a = rational(1, 4)
b = rational(2, 5)
c = a + b
print a
print b
print c
print c + 5
print 10 + c
c += 10
print c
您可能希望保留1 / 4
2 / 5
13 / 20
113 / 20
213 / 20
213 / 20
方法供内部使用;通常的惯例是在单个下划线前加上这些名称。
答案 1 :(得分:1)
不是强制参数,而是一种更通用的方法,你可以创建自己的 multimethods 模块,类似于几年前写的标题为Five-minute Multimethods in Python的文章中描述的模块。 Guido van Rossum。这样可以避免大量重复代码。这是一个增强版本,支持“associative_multimethod”函数,它们以相反的顺序接受它们的参数:
# This is in the 'mm' module
_registry = {}
class MultiMethod(object):
def __init__(self, name):
self.name = name
self.typemap = {}
def __call__(self, *args):
types = tuple(arg.__class__ for arg in args)
function = self.typemap.get(types)
if function is None:
raise TypeError("no match")
return function(*args)
def register(self, types, function):
if types in self.typemap:
raise TypeError("duplicate registration")
print('registering: {!r} for args: {}'.format(function.__name__, types))
self.typemap[types] = function
def multimethod(*types):
def register(function):
name = function.__name__
mm = _registry.get(name)
if mm is None:
mm = _registry[name] = MultiMethod(name)
mm.register(types, function)
return mm
return register
def associative_multimethod(*types):
def register(function):
name = function.__name__
mm = _registry.get(name)
if mm is None:
mm = _registry[name] = MultiMethod(name)
mm.register(types[::-1], lambda a, b: function(b, a))
mm.register(types, function)
return mm
return register
这将允许您编写如下代码:
from mm import associative_multimethod, multimethod
class Rational(object):
pass
@multimethod(int, int)
def foo(a, b):
print('...code for two ints...')
@associative_multimethod(int, Rational)
def foo(a, b):
print('...code for int and Rational...')
@multimethod(Rational, Rational)
def foo(a, b):
print('...code two Rationals...')
a, b, c, d = 1, 2, Rational(), Rational()
foo(a, b)
foo(a, c)
foo(c, a)
foo(c, d)