开学以后,我终日与腾讯课堂、Zoom为伍,抑郁温柔地向我的生命靠近,蓝光的照射使少女花容失色。于是我又回到了我的小窝。
开学第三天了,终于迎来了我的第一节面向对象程序设计课。杂乱的记录一下开学第一课学到的东西。
Python 中的运算符重载
先来看一个案例
a = int(1.2)
b = int(2.1314)
c = a + b
print(c)
输出会和你想象的一样么?当然不
3.3314000000000004
你以为有什么奥妙么?并没有,只是我没有给出完整的代码……
1 | class int: |
首先,值得一提的是,在py文件中定义了一个名为int的类,程序执行过程中会优先使用这个类,而不是直接调用Python的整型函数int,推而广之,即便py文档中没有int这个类的定义,程序执行时也会先搜寻引用的包中是否存在对int的定义,最后再使用内置函数。
这一步实现了 + 的运算符重载
1 | def __add__(self, other): |
应当注意的是,需要两个自定义类型的对象做相关运算时,此处应写为:
1 | self.num + other.num |
需要自定义类型与整型数一起做运算时(如:c = a + 1)应写为:
1 | self.num + other |
浮点数的计算误差
不知道你有没有好奇,为什么给出的枯燥的案例中输出结果不是3.3314,而是在小数点n多位后发生了漂移……
是的,因为蒟蒻的我提出了这个困惑,正好踩在老师要讲的浮点数计算误差上,我的后半节网课“出镜率”飙升,不知道有没有小哥哥因此会多注意我一下:)我真是个野心家!
我们知道,计算机中保存数字的寄存器是使用二进制来保存数字的。好了,为了解答这个问题,让我们先看看将十进制小数转换为二进制的过程为:
1 | 将小数乘以2,取出整数部分作为二进制表示的第1位;然后再将小数部分乘以2,将得到的整数部分作为二进制表示的第2位;以此类推,直到小数部分为0。 |
例如, 5.20 - 5 的结果是0.2时,使用二进制表示就是:0.0011 0011 0011…
是个无限循环小数。
而内存只会划分有限的空间来保存一个小数,所以当我们想要保存这个0.2的数字时,只会截取二进制数字中的一部分来保存,而当我们重新通过被截取的二进制数字来计算对应的十进制数字,就会产生误差。
这里附上大佬的原文
所以
1 | print(0.1 * 0.1 == 0.01) |
的输出结果是False
Python中的LEGB规则
如果你问我,那魔幻主义小清新背景是什么?
我将告诉你,那是让我思念成疾的校园。
Local, Enclosing, Global, Built-in是什么?先来一篇干货帮助我们理解一下这四个变量范围
1 | num = 1 |
num = 123 属于local scope, 输出为
1 | 123 |
运用global改写
1 | num = 1 |
输出为
1 | 123 |
1 | def outer(): |
输出
1 | 100 |
取消注释后
1 | def outer(): |
输出
1 | 100 |
此处,num = 10就存在于这个”E”,enclosing中,可以理解为local与global之间的“直接外围作用域”,它们捆绑起来就是一个闭包。