在Python里重载操作符这事儿,说大了其实不大,说小也不小,毕竟这玩意儿是Python语言优雅灵活的一大体现。但我第一次面试被问到“你写个类,让它尽可能多地支持各种操作符”,我是真的愣了三秒,脑袋里瞬间蹦出一个词:“这谁记得住啊?”不过回过味儿来,其实这题不难,它不是考你死记硬背每个魔法方法的名字,而是考你对Python对象模型理解的深度。
操作符重载,说白了就是你让你自定义的类,也能像int、list那样用“+”、用“==”、用“[]”,甚至还能当函数调用,甚至还能像bool那样参与if判断。这玩意儿要是玩得花一点,确实可以搞出很多骚操作。
我当时给面试官写了个叫“万能盒子”的类,基本能支持你想到的大部分操作,后来项目里还真有用到类似的场景,就当复习复用了。
我们先从最常见的说起,算术运算符。你要支持+、-、*、/这些操作,只要重载__add__、__sub__、__mul__、__truediv__这些魔法方法就行了。比如:
你看起来像在玩对象,其实内部就是在调方法。Python的操作符就是这么“人狠话不多”。
不过这还只是皮毛,你如果真的想“尽可能多地支持操作符”,那得连比较运算、位运算、下标访问、长度判断、字符串表示、布尔判断这些都得安排上。
比如你可以让你的对象支持大小比较:
支持完这些,Python的sorted()、min()、max()这些函数也能直接用上你这个类。
要是你再卷一点,还可以搞点骚的,比如实现__getitem__和__setitem__,让这个对象也能像list那样支持下标访问。
这个得看你传进去的self.value到底是个啥,如果是个list、dict,直接支持这些操作简直不要太自然。
甚至你还可以支持函数调用,就像这样:
这样你实例化完这个对象之后,还能直接像函数一样调用它,这不就是“对象即服务”的Python实现吗?
还有一些更边缘但也常见的重载操作,比如__contains__可以让你支持in操作,__len__可以让你对象支持len(),甚至你可以定义__bool__来控制这个对象在布尔上下文下的表现:
讲真,这些魔法方法看着是语法糖,背后其实是Python一整套对象协议的体现。你只要实现了这些“钩子”,Python解释器就能自动帮你完成大部分“魔法”。
我觉得啊,这种题目面试官拿出来,一方面是想看看你对Python的底层理解有多深,另一方面也想考你有没有实际使用这些东西的场景。就比如我之前做过一个通用配置类,用dict存数据,但是外面用点语法访问,比如config.db.host。那时候我就用到了__getattr__和__setattr__,甚至还玩了点元编程的小技巧。
当然也不是说这些魔法方法都要乱用,有时候用太多反而让代码变得晦涩。特别是那些你实现了加法、减法,但是你忘了实现__repr__,然后一print对象看到的全是<__main__.MagicBox object at 0x...>,这就很尴尬。print出来好看点的做法是:
对,就是这个!r,它其实是调用repr()而不是str(),这点细节也能看出你是不是个细心的程序员。
后来我这个“万能盒子”类被我用在了一个简单的数据追踪工具里,每次加减乘除都记录一下调用的操作和参数,回头做个log或者debug展示挺方便。甚至可以加个装饰器风格的功能,比如你加个__enter__和__exit__,配合with语句,还能支持上下文管理。要是你再疯一点,加上__iter__和__next__,它还能当迭代器用,配上异步魔法方法__await__,还能参与async语法块。
但说到底,这题的精髓不是“你能实现多少操作符”,而是“你能让Python语言的语法和你自己的类优雅地融合在一起”。这不就是Python所谓“优雅之道”的最好体现吗?
最后说个题外话,有时候我们太强调“重载操作符”这种技巧,反而忽略了“代码可读性”和“团队维护成本”。我见过有人疯狂重载__add__、__or__这些操作符搞DSL(领域特定语言),看着像写诗,实际上谁都不愿维护。所以说,适当的时候玩点魔法是加分项,但别上头。Python给你这些自由,是希望你更优雅,不是让你装逼。
好了,写到这我自己都有点想回去翻一翻我之前写的那些“魔法类”了。你们要是也写过啥骚操作的类,不妨拿出来交流交流,没准还能互相启发。写代码这事儿,最怕闭门造车,多交流才有火花。
以上就是“写一个Python类,并让它尽可能多的支持操作符?”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。
扫码二维码 获取免费视频学习资料
- 本文固定链接: http://phpxs.com/post/13295/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料