zip
for循环中对多个可迭代对象进行同时访问
A,B=[],[]
for a,b in zip(A,B):
print(a,b)
当可迭代对象长度不等时,zip会以最短长度为标准;如果希望以最长长度为标准,使用itertools.zip_longest(),自动补齐None。
引用,浅拷贝&深拷贝,视图
引用
在Python中,使用 = 赋值时,本质上是创建了一个新的引用指向同一个对象,而非创建新对象。这种机制可以理解为“别名”(aliasing)
- 可变对象(如列表、字典、集合)
修改对象内容时,所有引用都会变化 - 不可变对象(如整数、字符串、元组)
修改时实际是创建新对象,原引用不受影响
浅复制
定义:复制对象本身,但不会递归复制其内部的嵌套对象(如列表中的子列表、字典中的嵌套字典等)。
特点:
新对象和原对象是独立的,但内部的嵌套对象仍共享同一引用。
简单来说就是只有第一维的元素是独立的,内部嵌套的更高维度的元素仍然共享。
a = [1, [2, 3]]
b = a.copy() # 浅复制
深复制
定义:递归复制对象及其所有嵌套对象,生成完全独立的副本。
特点:
新对象与原对象及其内部嵌套对象均无任何引用关联。
import copy
a = [1, [2, 3]]
b = copy.deepcopy(a) # 深复制
不可变对象如整数、字符串):浅复制和深复制效果相同(因不可变性)
视图
是numpy中的概念
特点:
- 是原数组数据的另一种查看方式,与原数组共享同一块内存
- 修改视图会影响原数组
- 创建方式:切片操作、reshape()、transpose()等
Iterator,迭代器
任何继承自Iterator的类,比如常见的list、dict,都可以通过next()依次访问元素,也可以用for循环访问
使用isinstance()判断一个对象是否是Iterator对象:
>>> from collections.abc import Iterator
>>> isinstance((x for x in range(10)), Iterator)
列表表达式
for前面的部分是一个表达式,它必须根据x计算出一个结果。
因此,表达式:x if x % 2 == 0无法根据x计算出结果
>>> [x if x % 2 == 0 else -x for x in range(1, 11)]
[-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]
上述for前面的表达式x if x % 2 == 0 else -x才能根据x计算出确定的结果。
可见,在一个列表生成式中,for前面的if … else是表达式
而for后面的if是过滤条件,不能带else
generator
generator的思想和滚动数组类似:
滚动数组:在递推中保存递推中几个必要的变量,不保存之前的递推数据来节省内存
generator:生成器函数会暂停执行并保存当前状态,下次调用时从停止处继续(惰性计算,需要时生成数据,不保存多余历史数据)、
访问generator,可以调用next(),或者使用for循环,generator也是可迭代对象
要创建一个generator,有很多种方法。
第一种方法
很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
>>> L = [x * x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
<generator object <genexpr> at 0x1022ef630>
另一种方法:
如果一个函数定义中包含yield关键字,那么这个函数是一个generator函数
请务必注意:调用generator函数会创建一个generator对象,多次调用generator函数会创建多个相互独立的generator。
装饰器
假设我们要增强函数的功能,比如在函数调用前后自动打印日志,但又不希望修改函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
本质上,decorator就是一个返回函数的高阶函数。
所以,我们要定义一个能打印日志的decorator,可以定义如下:
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处:
@log
def now():
print('2024-6-1')
调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:
>>> now()
call now():
2024-6-1
面向对象编程
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__
变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的。
self.x=x代表绑定实例的属性,直接声明或定义则是类属性。