Python|知识点拾遗(一)
最近阅读《Python工匠:案例、技巧与工程实践》发现一些零零碎碎的之前不知道的知识点,因此总结记录方便以后翻找查阅。
变量与注释
变量解包是python里一种特殊的赋值操作,允许把可迭代的对象所有成员一次性赋值给多个变量。
|
|
此外特殊技巧,比如利用星号表达式贪婪的获取多个数据。
|
|
单下划线在常用的诸多变量名中,单下划线_是比较特殊的一个。它常作为一个无意义的占位符出现在赋值语句中。需要注意的是在Python交互式命令行里,_
变量还有一层特殊含义——默认保存我们输入的上个表达式的返回值。
|
|
数值与字符串
当前的主流Python版本中,至少有三种主要的字符串格式化方式。
- C语言风格的基于百分号%的格式化语句:‘Hello, %s’ % ‘World’。
- 新式字符串格式化(str.format)方式(Python 2.6新增):“Hello,{}".format (‘World’)。
- f-string字符串字面量格式化表达式(Python 3.6新增):name = ‘World’;f’Hello, {name}’。
具体使用方法参考官方文档,日常编码中推荐优先使用f-string,搭配str.format作为补充,想必能满足绝大多数的字符串格式化需求。
广义上的“字符串”概念可分为两类。
- 字符串:我们最常挂在嘴边的“普通字符串”,有时也被称为文本(text),是给人看的,对应Python中的字符串(str)类型。str使用Unicode标准,可通过.encode()方法编码为字节串。
- 字节串:有时也称“二进制字符串”(binary string),是给计算机看的,对应Python中的字节串(bytes)类型。bytes一定包含某种真正的字符串编码格式(默认为UTF-8),可通过.decode()解码为字符串。
|
|
因为字符串面向的是人,而二进制的字节串面向的是计算机,因此,在使用体验方面,前者要好得多。在我们的程序中,应该尽量保证总是操作普通字符串,而非字节串。必须操作处理字节串的场景,一般来说只有两种:
- 程序从文件或其他外部存储读取字节串内容,将其解码为字符串,然后再在内部使用;
- 程序完成处理,要把字符串写入文件或其他外部存储,将其编码为字节串,然后继续执行其他操作。
当把字符串写入文件时,请谨记:普通字符串采用的是文本格式,没法直接存放于外部存储,一定要将其编码为字节串——也就是“二进制字符串”——才行。这个编码工作有时需要显式去做,有时则隐式发生在程序内部。比如在写入文件时,只要通过encoding参数指定字符串编码格式,Python就会自动将写入的字符串编码为字节串。
|
|
如果不指定encoding参数,Python会尝试自动获取当前环境下偏好的编码格式。
|
|
容器
列表推导式把几类操作压缩在了一起,结果就是:代码量更少,并且维持了很高的可读性。因此,列表推导式可以算得上处理列表数据的一把“利器”。
|
|
Python里的内置数据类型,大致上可分为可变与不可变两种。
- 可变(mutable):列表、字典、集合。
- 不可变(immutable):整数、浮点数、字符串、字节串、元组。
Python在进行函数调用传参时,采用的既不是值传递,也不是引用传递,而是传递了“变量所指对象的引用”(pass-by-object-reference)。换个角度说,当我们调用函数将外部变量作为参数传递进来后,Python会新建了一个函数内部变量,然后让它和外部变量指向同一个对象,相当于做了一次变量赋值。而之后的函数内部处理是否会影响参数的数据,则取决于对象的可变性。
字典在范问不存在的键时,会抛出异常,这样便引发很多情景,例如获取、新增、删除等操作都需要考虑键值不存在的情况,接下来我们介绍几种字典方法,避免了冗余的异常捕获,方便操作。
|
|
自python3.6开始字典的底层实现改变了,导致具有了有序性,即当你按照某种顺序把内容存进字典后,可以按照原顺序把它取出来了。
还需要注意的是内容一致而顺序不同的字典被视作相等,因为解释器只对比字典的键和值是否一致。
集合中只能存放可以hash的对象,某种类型是否可哈希遵循下面的规则
- 所有的不可变内置类型,都是可哈希的,比如str、int、tuple、frozenset等;
- 所有的可变内置类型,都是不可哈希的,比如dict、list等;
- 对于不可变容器类型(tuple, frozenset),仅当它的所有成员都不可变时,它自身才是可哈希的;
- 用户定义的类型默认都是可哈希的。谨记,只有可哈希的对象,才能放进集合或作为字典的键使用。
|
|
条件分支
当我们需要判断两个对象是否相等时,通常会使用双等号运算符==
,它会对比两个值是否一致,然后返回一个布尔值结果。
对于自定义对象来说,它们在进行==
运算时行为是可操纵的:只要实现类型的__eq__
魔法方法就行。
如何严格检查某个对象是否为None呢?答案是使用is运算符。虽然二者看上去差不多,但有着本质上的区别:
- ==对比两个对象的值是否相等,行为可被__eq__方法重载。
- is判断两个对象是否是内存里的同一个东西,无法被重载。
因此在执行x is y时,其实就是在判断id(x)和id(y)的结果是否相等,二者是否是同一个对象。
既然is在进行比较时更严格,为什么不把所有相等判断都用is来替代呢?这是因为,除了None、True和False这三个内置对象以外,其他类型的对象在Python中并不是严格以单例模式存在的。
|
|
上面的例子需要注意,如果把23000改成100,则x is y
会判断为True,这是因为Python语言使用了一种名为“整型驻留”(integer interning)的底层优化技术。对于从-5到256的这些常用小整数,Python会将它们缓存在内存里的一个数组中。当你的程序需要用到这些数字时,Python不会创建任何新的整型对象,而是会返回缓存中的对象。这样能为程序节约可观的内存。
装饰器
装饰器是一种通过包装目标函数来修改其行为的特殊高阶函数,绝大多数装饰器是利用函数的闭包原理实现的。
|
|
如果一个类实现了__call__魔法方法,那么它的实例也会变成可调用对象。如果一个类实现了__call__魔法方法,那么它的实例也会变成可调用对象。
|
|
书里面写的内容看着蛮复杂,后期专门整理博客介绍。
面向对象
在Python里,所有的类属性和方法默认都是公开的,不过我们可以通过添加双下划线前缀__的方式把它们标示为私有。
|
|
代码中Foo类的bar就是一个私有属性,如果尝试从外部访问它,程序就会抛出异常。虽然上面是设置私有属性的标准做法,但Python里的私有只是一个“君子协议”。“君子协议”是指,虽然用属性的本名访问不了私有属性,但只要稍微调整一下名字,就可以继续操作__bar
了
|
|
这是因为当我们使用__{var}
的方式定义一个私有属性时,Python解释器只是重新给了它一个包含当前类名的别名_{class}__{var}
,因此你仍然可以在外部用这个别名来访问和修改它。
总结
开始浏览了一遍,其中较多设计修饰器,这个后期再仔细学习一下。