ola*_*ndo 13 python operator-overloading
从我从我的C++类记得,教授说,操作符重载是很酷,但因为它需要比较大量的思想和代码覆盖所有终端的情况下(如过载时,+你可能还需要过载++和+=,也使确保处理最终情况,例如向对象添加对象等.),您应该只考虑在此功能会对您的代码产生重大影响的情况下,例如在数学应用程序中重载矩阵类的运算符.
这同样适用于python吗?你会建议在python中覆盖运算符行为吗?你能给我什么经验法则?
Ale*_*lli 25
当您创建一个属于现有"抽象基类"(ABC)的新类时,运算符重载非常有用 - 实际上,标准库模块集合中的许多ABC 依赖于某些特殊方法的存在(和特殊方法)方法,一个名称以双下划线开头和结尾的方式AKA"dunders",正是你在Python中执行运算符重载的方式).这提供了良好的起始指导.
例如,一个Container类必须覆盖特殊方法__contains__,即成员资格检查操作符item in container(如,if item in container:- 不要与for语句混淆for item in container:,依赖于__iter__! - ).同样,Hashable必须覆盖__hash__,Sized必须覆盖__len__,a Sequence或Mapping必须覆盖__getitem__,等等.(此外,基本知识可以提供您类的mixin功能-例如,二者Sequence并Mapping能提供__contains__您提供的基础上__getitem__重写,从而自动让你的类Container).
除此之外collections,如果您的新类"是一个数字",您将希望覆盖特殊方法(即提供运算符重载).其它特殊情况存在,但抵制运算符重载"只是冷静",具有"正常"的含义没有语义关联的诱惑,因为C++的流为做<<和>>和Python字符串(Python中2.*,所幸没有3.*任何更多的;-)做%- 当这些操作员不再意味着"位移"或"除法余数"时,你只会产生混乱.一个语言的标准库可以随意使用它(虽然它不应该;-),但除非你的库像语言的标准库一样广泛,否则混乱会受到伤害! - )
Pet*_*ter 12
我写了大量超载的软件,最近我对这个政策感到遗憾.我会这样说:
只有重载操作符,如果它是自然的,预期的事情,并没有任何副作用.
因此,如果你创建一个新RomanNumeral类,重载加法和减法等是有意义的.但是不要重载它,除非它是自然的:为一个Car或一个Vehicle对象定义加法和减法是没有意义的.
另一个经验法则:不要超负荷==.如果两个对象是相同的,实际测试它会非常困难(尽管不是不可能).我犯了这个错误并付了很长时间.
至于何时过载+=,++等等,其实我说:只有额外的超负荷运营商,如果你有很多关于这个功能的需求.有一种方法比五种方法更容易.当然,这意味着有时你必须写x = x + 1而不是x += 1,但如果它更清楚,更多的代码是可以的.
一般来说,就像许多"花哨"的功能一样,很容易认为你想要的东西,当你没有真正的,实现一堆东西,没有注意到副作用,然后后来弄清楚.Err在保守的一面.
编辑:我想添加一个关于重载的解释性说明==,因为似乎各种评论者误解了这一点,并且它让我感到困惑.是的,is存在,但这是一个不同的操作.假设我有一个对象x,它来自我的自定义类,或者是一个整数.我想看看数字是否x为500.但是如果你设置x = 500,那么稍后测试x is 500,你会得到False,因为Python缓存数字的方式.随着50,它会回来True.但你不能使用is,因为你可能要x == 500返回True,如果x是你的类的实例.混乱?当然.但这是成功超载运营商需要了解的细节.
下面是一个使用按位或操作来模拟unix管道的示例.这是大多数经验法则的反例.
我刚刚发现Lumberjack在实际代码中使用了这种语法
class pipely(object):
def __init__(self, *args, **kw):
self._args = args
self.__dict__.update(kw)
def __ror__(self, other):
return ( self.map(x) for x in other if self.filter(x) )
def map(self, x):
return x
def filter(self, x):
return True
class sieve(pipely):
def filter(self, x):
n = self._args[0]
return x==n or x%n
class strify(pipely):
def map(self, x):
return str(x)
class startswith(pipely):
def filter(self, x):
n=str(self._args[0])
if x.startswith(n):
return x
print"*"*80
for i in xrange(2,100) | sieve(2) | sieve(3) | sieve(5) | sieve(7) | strify() | startswith(5):
print i
print"*"*80
for i in xrange(2,100) | sieve(2) | sieve(3) | sieve(5) | sieve(7) | pipely(map=str) | startswith(5):
print i
print"*"*80
for i in xrange(2,100) | sieve(2) | sieve(3) | sieve(5) | sieve(7) | pipely(map=str) | pipely(filter=lambda x: x.startswith('5')):
print i
Run Code Online (Sandbox Code Playgroud)