python总结
字符串与字节
python 3 中只有一种能保存文本信息的数据类型——str,它是不可变序列,保存的是Unicode code point。
python 2中用str表示字节字符串。这种类型在python 3中用bytes对象来处理。
bytes以及可变的bytearray与str不同,只能用字节值作为序列值。即0<=x<=255。
将字符串对象编码为字节序列的方法有两种:
a. 利用str.encode(encoding, errors)方法,利用registered codec对字符串进行编码。
b. 利用bytes(source, encoding, errors)构造函数,创造一个新的字节序列。
类似的反向转换:
bytes.decode(encoding, errors)&str(source, encoding, errors)
因为python字符串与字节序列是不可变的,故每次合并字符串(“+”)都需要创建新的字符串实例,效率低下。
替代 “”.join(substrs)
性能提升视实际情况而定,一般而言对于大型列表来说采用join方法性能提升显著。
集合类型
Tuple:
Tuple是不可变的(immutable),因此也是可哈希的(hashable)。
List:
List在CPython中实现为长度可变的数组,并不是“链表”。在需要真正使用链表的地方可以使用collections中的deque,它是栈和队列的一般化。
列表推导(list comprehension)要比用循环更快速。
enumerate()的使用,同时返回index和item。
zip()列表合并,对两个等大小的可迭代对象同时进行均匀遍历。对其返回值再次使用zip会恢复原状。
序列解包(sequence unpacking),等号两侧对应赋值,*解包,嵌套解包(tuple),详见python cookbook。
Dictionary:
字典推导的使用:
1 | squares = {number: numbers**2 for number in range(100)} |
python 3中,keys(), values(), items()中返回的是视图对象(可以动态改变,与获取时间无关)。
另外,keys()和values()调用后的值是完全对应的,实时动态调整。
如果一个对象在整个生命周期都有不变的散列值,而且这个对象可以与其它对象进行比较,那么这个对象就是可哈希的。python中所有不可变的内置类型都是可以哈希的。可变类型(list, dic, set等)是不可哈希的,因此不能做为字典的键。CPython使用开放定址法(open addressing)来解决散列冲突问题。
如果一个字典曾经有很多元素,后又大大减少,那么遍历这个字典可能要花费相当长时间(guess:标记删除)。因此,某些情况下,最好创建一个新的字典对象。
字典中的key的顺序是无序的,与散列方法和添加顺序无关。解决方法可以采用collections中的OrderedDict(),用法类似。
Set:
元素唯一性,测试元素是否在集合中效率高。其内部实现与dic类似,实现为带有空值的字典,上古时期由dic实现,后废弃。
set(): 一种可变的,无序的,有限的集合,其元素是唯一的,不可变的(可哈希)的对象。
frozenset(): 一种不可变的,可哈希的,无序的结果,其元素是唯一的,不可变的(可哈希)的对象。可用作dic,set的键。
创建方法:
- 接受可迭代对象set([1, 2, 3])
- 集合推导{elem for elem in range(3)}
- 集合字面值{1, 2, 3},空集合无字面值,{}为空dic字面值。
collection model:
nametuple, deque, ChainMap, Counter, OrderedDict, defaultdict, etc…
iterator:
迭代器是一个实现了迭代器协议的容器对象,基于以下两个方法:
_next_
_iter_
迭代器是个底层概念,可以不用,为生成器提供基础。
generator:
基于yield语句,生成器可以暂停函数并返回一个中间结果。该函数会保存上下文,稍后恢复。
常见使用场景数据流生成(机器学习数据生成)
最好编写多个处理序列值的简单可迭代函数,将生成器链接起来使用,而不要编写一个复杂函数同时计算出整个集合的结果。保持代码简单而不是保持数据简单。
send向yield传值。
decorator:
使函数包装与方法包装(一个函数接受函数并返回其增强版本),变得更加容易阅读和理解。
任何可调用对象(任何实现了__call__方法的对象都是可调用的)都可以用做装饰器。
装饰器语法只是语法糖而已,同显式装饰器效果相同。
最初使用场景是在方法定义的开头能够将其定义为类方法或静态方法:
@staticmethod与@classmethod的区别:
1 | class A(object): |
m1是实例方法,第一个参数必须是self(约定)。
m2是类方法,第一个参数必须是cls(约定)。
m3是静态方法,参数可有可无,看需要。
执行过程:
- 第一步:代码从第一行开始执行 class 命令,此时会创建一个类 A 对象(没错,类也是对象,一切皆对象嘛)同时初始化类里面的属性和方法,记住,此刻实例对象还没创建出来。
- 第二、三步:接着执行 a=A(),系统自动调用类的构造器,构造出实例对象 a
- 第四步:接着调用 a.m1(1) ,m1 是实例方法,内部会自动把实例对象传递给 self 参数进行绑定,也就是说, self 和 a 指向的都是同一个实例对象。
- 第五步:调用A.m2(1)时,python内部隐式地把类对象传递给 cls 参数,cls 和 A 都指向类对象。
对于实例方法m1(类对象需要绑定实例对象,否则报参数错误)
A.m1(a, 1) 等价于 a.m1(1)
对于类方法m2,不管是 A.m2 还是 a.m2,都是已经自动绑定了类对象A的方法,对于后者,因为python可以通过实例对象a找到它所属的类是A,找到A之后自动绑定到 cls。
A.m2(1) 等价于 a.m2(1)
对于静态方法m3,跟普通函数没区别,与类和实例都没有绑定关系。
A.m3(1) 等价于 a.m3(1)
1 | def mydecorator(function): |
1 | #非参数化装饰器用作类的通用模式 |
1 | #参数化装饰器需要用两层包装 |
1 | #函数元数据被覆盖了 |
上下文管理器——with语句
一般语法:
1 | with context_manager: |
- 作为一个类
任何实现了上下文管理协议(context manager protocol)的对象都可以用作上下文管理器,该协议包含两个特殊的方法:
_enter_(self)
_exit_(self, exc_type, exc_value, traceback)
with调用过程:
- 调用__enter__方法。任何返回值都会绑定到指定的as语句
- 执行内部代码块
- 调用__exit__方法
__exit__接受代码块中出现错误时填入的3个参数。如果没有错误,参数都设置为None。出现错误时,__exit__不应该重新引发这个错误,因为这事调用者(caller)的责任。但它可以通过返回True来避免引发异常。类似于finally子句的行为。
1 | class ContextIllustration: |
- 作为一个函数——contextlib模块
1 | from contextlib import contextmanager |
for…else…语句
1 | for i in range(1): |
函数注解
函数注解时关于用户自定义函数的类型的完全可选的元信息。//leetcode 有相关使用
1 | >>>def f(ham: str, eggs: str = "eggs") -> str: |
参数注解为冒号后计算注解值的表达式。返回值注解为函数名结尾冒号与参数列表之后的->之间的表达式。
- Blog Link: http://songjingrui.github.io/2019/11/08/python%E6%80%BB%E7%BB%93/
- Copyright Declaration: The author owns the copyright, please indicate the source reproduced.