Python中的奇奇怪怪
本文主要记录python中的一些零散琐碎的知识点,便于之后整理成系统性的学习笔记~
在个人的角度来看,Python作为一门被深度学习、数据处理等领域大力推广的编程语言,其很多语法糖都是很有意思的,特此记录~
python中的奇奇怪怪
1. a+=b和a=a+b的区别
二者的区别与否,取决于a和b的对象类型,如果是不可变对象,这两种表达相同;如果是可变对象,两种表达不同,不同之处在于:
- a+=b 会调用
__iadd__
方法,没有该方法时,再尝试调用__add__
方法 - a=a+b 会调用
__add__
方法
对于两种内置的方法接口,不同在于:
__iadd__
返回值是None,直接在原对象上进行更新,也就是说,原有的变量a和对象之间的引用并没有被打破__add__
会返回一个新的对象,原对象不做修改,但是这里会将变量a的引用破坏,将返回的新的对象与变量a建立引用
2. Python中的幂运算
Python 中常见有三种幂计算函数: * 和 pow() 的时间复杂度均为 O(\log a)O(loga) ;而 math.pow() 始终调用 C 库的 pow() 函数,其执行浮点取幂,时间复杂度为 O(1)O(1) 。
3. Python中变量的作用域(变量的查找顺序)
Python中的变量名可以指代变量、函数、类、对象等
python解释器查找变量的顺序,总结起来可以分为LEGB四种,分别是 Local -> Enclosed -> Global -> Built-in
- Local 定义在函数内部的变量、定义在函数声明中的形式参数,视为局部变量。
- Enclosed 定义在函数中,嵌套函数外,且被嵌套函数引用的变量,视为自由变量。
- Global 定义在
.py
文件内的,且函数、类之外的变量,视为全局变量。 - Built-in 定义在
built in
中的变量,视为内置变量。
定义变量的位置决定了变量的作用域;
为了在局部作用域中修改全局变量和自由变量,引入了 global 关键字和 nonlocal 关键字
- global用于调用全局变量
- nonlocal用于调用 闭包变量,也就是自由变量
此外,对于函数内部再定义一个函数,以形成闭包的情况,在内部函数中调用内部函数外的变量时,是否修改也是一个值得注意的问题
- 内部函数,不修改全局变量可以访问全局变量,不需要nonlocal或global
- 内部函数,修改同名全局变量,则python会认为它是一个局部变量
- 在内部函数修改同名全局变量之前调用变量名称(如print sum),则引发Unbound-LocalError,解决办法就是,加上nonlocal或者global关键字,具体用哪个视情况而定。
4. Python的加速运行
参考:https://zhuanlan.zhihu.com/p/143052860
5. Python中的闭包
需要明确的是,闭包是一个函数,可以理解为特殊的函数,并且闭包的说法并不是Python特有的,javascript等语言也涉及闭包的概念。
具体地,参考Wiki上对闭包的解释:
在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
总的来看就是,闭包等同于函数引用了函数外定义地变量,并且该函数可以在其定义环境外被执行。这样地函数叫做闭包,类似地,C++中地static关键字定义的就是一个独立函数外地变量,二者有异曲同工之妙。
闭包的一些特性
- 闭包中的引用的自由变量只和具体的闭包有关联,闭包的每个实例引用的自由变量互不干扰。
- 一个闭包实例对其自由变量的修改会被传递到下一次该闭包实例的调用。
具体见:https://www.cnblogs.com/yssjun/p/9887239.html
6. Python中的__new__
与__init_
__new__(cls[, ...])
是在一个对象实例化的时候所调用的第一个方法,在调用__init__
初始化前,先调用__new__
。
__new__
至少要有一个参数cls
,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供,后面的参数直接传递给__init__
。
__new__
对当前类进行了实例化,并将实例返回,传给__init__
的self
。但是,执行了__new__
,并不一定会进入__init__
,只有__new__
返回了,当前类cls
的实例,当前类的__init__
才会进入。
若__new__
没有正确返回当前类cls
的实例,那__init__
是不会被调用的,即使是父类的实例也不行,将没有__init__
被调用。
__new__
方法主要是当你继承一些不可变的 class 时(比如int, str, tuple
), 提供给你一个自定义这些类的实例化过程的途径。