Python 常用基础知识

本篇博客介绍些 Python 常用的基础知识。

生成器和迭代器

生成器

带有yield关键字的函数在python中被称为generator(生成器)。python解释器会将带有yield关键字的函数视为一个生成器来处理。一个函数或者子程序都只能return一次,但是一个生成器能暂停执行并返回一个中间的结果,这是yield语句的功能:返回一个中间值给调用者并暂停执行。

优点

生成器的一个优点是它不要求事先准备好整个迭代过程中所有的元素,即无须将对象的所有元素都存入内存之后,才开始进行操作。生成器仅在迭代至某个元素时才会将该元素放入内存,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或者无限的类序列对象,例如大文件、大集合、大字典或者斐波那契数列等。这个特点被称为延迟计算或者惰性求值,可以有效地节省内存。惰性求值实际上是实现了协同程序的思想。

协同程序:是一个可以独立运行的函数调用,该调用可以被暂停或者挂起,之后还能够从程序流挂起的地方继续或重新开始。当协同程序被挂起时,Python就能够从该协同程序中获取一个处于中间状态的属性的返回值(由yield返回),当调用next()方法使得程序流回到协同程序中时,能够为其传入额外的或者是被改变了的参数,并且从上次挂起的下一条语句继续执行。这是一种类似于进程中断的函数调用方式。

这种挂起函数调用并在返回属性中间值后,仍然能够多次继续执行的协同程序被称之为生成器。

使用场景:当需要以迭代的方式去处理一个巨大的数据集合,比如一个巨大的文件或者一个复杂的数据库查询时,就需要使用生成器。

迭代器

任何实现了__iter__()和__next__()(python 2中实现next())方法的对象都是迭代器,__iter__返回迭代器本身,__next__返回容器中的下一个值,如果容器中没有更多元素了,则抛出StopIteration异常。

  • 容器是一系列元素的集合,string、list、set、dict、file、socket对象都可以看做容器,容器都可以被迭代(用在for、while等语句中),因此他们被称为可迭代对象。
  • 可迭代对象实现了__iter__()方法,该方法返回一个迭代器对象。
  • 迭代器持有一个内部状态的字段,用于记录下次迭代返回值,实现了__next__()和__iter__()方法,迭代器不会一次性把所有元素加载到内存,而是需要的时候才生成返回结果。
  • 生成器是一种特殊的迭代器,它的返回值不是通过return,而是用yield。

容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in, not in关键字判断元素是否包含在容器中。通常这类数据结构把所有的元素存储在内存中(也有一些特例,并不是所有的元素都放在内存,比如迭代器和生成器对象)。

凡是可以返回一个迭代器的对象都可称之为可迭代对象,

下划线问题

单下划线开头

Python 中没有真正的私有属性或方法,可以在声明为私有的方法和属性前加上单下划线,以提示该属性和方法不应在外部调用。如果真的调用了,也不会出错,但不符合规范。

带有单下划线的特性不会被 from module_name import *导入。

双下划线开头

双下划线开头,是为了不让子类重写该属性方法,通过类的实例化时自动转换,在类中的双下划线开头的属性方法前加上 _类名 实现

双下划线开头和双下划线结尾

此种写法为 python内建属性方法,最好不要在外部调用。

以单下划线开头 _foo 的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用 from xxx import * 而导入;

以双下划线开头的 __foo 代表类的私有成员;

以双下划线开头和结尾的 foo 代表 Python 里特殊方法专用的标识,如 init() 代表类的构造函数。

*args**kwargs

*args 表示非键值对的不确定个数的变量列表,其中args可以换成别的合法变量名,比如*vars,但是那个 * 是必须的。

**kwargs 表示带键值对的不确定个数的参数列表,同样,kwargs也可以换成别的合法变量名。

当不知道函数中传递参数的个数时,就可以使用这两个参数。

对象销毁(垃圾回收)

Python 使用了引用计数这一简单技术来跟踪和回收垃圾。 在 Python 内部记录着所有使用中的对象各有多少引用。 一个内部跟踪变量,称为一个引用计数器。 当对象被创建时, 就创建了一个引用计数, 当这个对象不再需要时, 也就是说, 这个对象的引用计数变为0 时, 它被垃圾回收。但是回收不是"立即"的, 由解释器在适当的时机,将垃圾对象占用的内存空间回收。

垃圾回收机制不仅针对引用计数为0的对象,同样也可以处理循环引用的情况。循环引用指的是,两个对象相互引用,但是没有其他变量引用他们。这种情况下,仅使用引用计数是不够的。Python 的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。作为引用计数的补充, 循环垃圾收集器也会留心被分配的总量很大(及未通过引用计数销毁的那些)的对象。 在这种情况下, 解释器会暂停下来, 试图清理所有未引用的循环。

析构函数 del ,__del__在对象销毁的时候被调用,当对象不再被使用时,__del__方法运行。

is 与 == 的区别

Python 中的对象包含三个要素:id,type,value 其中,id 用来唯一标识一个对象,type标识对象的类型,value是对象的值。

is 判断的是 a 对象是否就是 b 对象,是通过 id 来判断的。

== 判断的是 a 对象的值是否和 b 对象的值相等,是通过 value 来判断的。

with 的一般执行过程

一段基本的 with 表达式,其结构是这样的:

with expression as variable:
    code_block

其中,expression可以是任意表达式,as variable 是可选的,其一般的执行过程是这样的:

  • 计算 expression,并获取一个上下文管理器。
  • 上下文管理器的__exit()__方法被保存起来用于之后的调用。
  • 调用上下文管理器的__enter()__方法。
  • 如果 with 表达式包含 as variable,那么 expression 的返回值被赋值给 variable。
  • 执行 code_block 中的表达式。
  • 调用上下文管理器的__exit()__方法。如果code block的执行过程中发生了一个异常导致程序退出,那么异常的type、value和traceback(即sys.exc_info()的返回值)将作为参数传递给__exit()__方法,否则,将传递三个None。

注意:

如果上下文管理器中没有 enter() 或者 exit() 中的任意一个方法,那么解释器会抛出一个 AttributeError 。

在 code_block 中发生异常后,如果 exit() 方法返回一个可被看成是 True 的值,那么这个异常就不会被抛出,后面的代码会继续执行。

updatedupdated2018-08-082018-08-08
加载评论