生成器和迭代器
type
status
date
slug
summary
tags
category
icon
password
Property

 

生成器

通过列表生成式,可以直接创建一个列表。但是受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator
 

用列表生成式创建

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator
高阶函数
type
status
date
slug
summary
tags
category
icon
password
Property

 

变量可以指向函数

Python内置的求绝对值的函数abs()为例:
函数本身也可以赋值给变量,即变量可以指向函数
 
 

函数名也是变量

返回函数
type
status
date
slug
summary
tags
category
icon
password
Property

函数作为返回值

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。实现一个可变参数的求和,通常情况下,求和的函数是这样定义的:
 
但是,如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数:
在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。
 
匿名函数
type
status
date
slug
summary
tags
category
icon
password
Property
 
在传入函数时,有些时候不需要显式地定义函数,直接传入匿名函数更方便,Python对匿名函数提供了有限支持。
map()函数为例,计算 时,除了定义一个f(x)的函数外,还可以直接传入匿名函数:
 
匿名函数lambda x: x * x实际上就是:
关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
 
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:
装饰器
type
status
date
slug
summary
tags
category
icon
password
Property
 
 
作用:装饰器的作用就是为已经存在的对象添加额外的功能
本质:本质上是一个Python函数或类,可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能
应用场景:经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用
 
由于函数也是一个对象,而且函数对象可以被赋值给变量,所以通过变量也能调用该函数:
 
假设要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为装饰器(Decorator)
 
本质上,decorator就是一个返回函数的高阶函数。所以定义一个能打印日志的decorator,可以如下:
偏函数
type
status
date
slug
summary
tags
category
icon
password
Property
 
 
Pythonfunctools模块提供了很多有用的功能,其中一个就是偏函数(Partial function),这里的偏函数和数学意义上的偏函数不一样。
通过设定函数参数的默认值,可以降低函数调用的难度,偏函数也可以做到这一点:
int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:int('12345')
int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换:
 
假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,可以定义一个int2()的函数,默认把base=2传进去:
 
functools.partial就是帮助我们创建一个偏函数的,不需要自己定义int2(),可以直接创建一个新的函数int2
类和实例
type
status
date
slug
summary
tags
category
icon
password
Property

 

类和实例

面向对象最重要的概念就是类(Class)和实例(Instance)
  • 类是抽象的模板,比如Student
  • 实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同
 
Student类为例,在Python中定义类是通过class关键字:
封装、继承和多态
type
status
date
slug
summary
tags
category
icon
password
Property

 

访问限制

Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样就隐藏了内部的复杂逻辑。
但是从前面Student类的定义来看,外部代码还是可以自由地修改一个实例的namescore属性:
 
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问:
获取对象信息
type
status
date
slug
summary
tags
category
icon
password
Property
目录
目录

 
拿到一个对象的引用时,如何知道这个对象是什么类型、有哪些方法呢?

type()

首先,来判断对象类型,使用type()函数:
 
如果一个变量指向函数或者类,也可以用type()判断:
定制类
type
status
date
slug
summary
tags
category
icon
password
Property
目录
目录

 
类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的。Pythonclass中还有许多有特殊用途的函数,可以帮助我们定制类。

__str__

先定义一个Student类,打印一个实例:
打印出一堆<__main__.Student object at 0x000001FA2FF374C0>,不好看
 
怎么才能打印得好看呢?只需要定义好__str__()方法,返回一个好看的字符串就可以了:
元类
type
status
date
slug
summary
tags
category
icon
password
Property
目录
目录

 

type()

动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。
比方说要定义一个Hello的class,就写一个hello.py模块:
当Python解释器载入hello模块时,就会依次执行该模块的所有语句,执行结果就是动态创建出一个Hello的class对象,测试如下:
type()函数可以查看一个类型或变量的类型,Hello是一个class,它的类型就是type,而h是一个实例,它的类型就是class Hello
枚举类
type
status
date
slug
summary
tags
category
icon
password
Property
 
当需要定义常量时,一个办法是用大写变量通过整数来定义,例如月份:
好处是简单,缺点是类型是int,并且仍然是变量
 
更好的方法是为这样的枚举类型定义一个class类型,每个常量都是class的一个唯一实例,Python提供了Enum类来实现这个功能:
这样就获得了Month类型的枚举类,可以直接使用Month.Jan来引用一个常量,或者枚举它的所有成员:
value属性则是自动赋给成员的int常量,默认从1开始计数。
 
如果需要更精确地控制枚举类型,可以从Enum派生出自定义类: