python的高级特性
切片
使用切片可以帮助我们快速地获取想要的范围内的list中的数据。
比如有List L,我想取出其中前三个数据可以这样使用:L[0:3],如果说第一个元素是0,那么0就可以省略,也就是这样写:L[:3]。
所以我们要取索引从X到y范围的数据就应该这样写:L[x:y]。
分片支持使用负数,比如我要取倒数两个元素,可以这样写:L[-2:],使用倒数要注意起始值是-1,也就是倒数第一个元素。取倒数第五到倒数第十:L[-10:-5]。
[]内什么都不写就会取所有的值。
迭代
我们通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。
在python中使用for就要使用for .. in这种形式来实现,而在c或者java中一般是使用这种方式来使用for:for(){...}。
在Python中,只要是一个可迭代的对象,那么就可以使用for循环来实现。
可迭代的对象有:list、dict、字符串等。同时我们可以通过collections.abc模块的Iterable类型判断一个对象是否是可迭代的。
from collections.abc import Iterable
print(isinstance('123',Iterable))
print(isinstance(['a','b','c'],Iterable))
print(isinstance(123,Iterable))
True
True
False
列表生成式
列表生成式是Python内置的用于生成list的生成式。
生成1到10的list:list(range(1,11))
如果要对生成的数进行一些操作,可以这样写:
L=[]
for x in range(1,11):
L.append(x*x)
print(L)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
for x in range(1,11):
L.append(x+100)
[101, 102, 103, 104, 105, 106, 107, 108, 109, 110]
也可以直接使用[]将处理公式和range包起来:
L=[x*x for x in range(1,11)]
print(L)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
我们可以在for循环后面加上if的判断:
L=[x*x for x in range(1,11) if x%2==1]
print(L)
[1, 9, 25, 49, 81]
注意:只能使用if,不能使用if else,if要加在for的后面而不能加在前面,在前面要使用if else才行。
因为在for后面的情况是进行筛选,如果有else就无法进行筛选了。在for前面的情况是因为for前面的部分是表达式它必须根据x计算出一个结果。因此,考察表达式:x if x % 2 == 0,它无法根据x计算出结果,因为缺少else,必须加上else。(这里看不懂了)
[x if x % 2 == 0 else -x for x in range(1, 11)]
[x for x in range(1, 11) if x % 2 == 0]
生成器
我们在使用list的时候可以直接生成一个列表,但计算机的内存是有限的,所以列表的容量也是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
如果列表元素可以按照某种算法推算出来,我们就可以使用生成器(generator),在循环的过程中不断地生成后续的元素,这样就可以节省大量的内存空间。
在python中使用generator,我们可以将生成list时使用的[]改成()就可以了。generator中保存的是算法。它会一直计算下一个该获取的值,直到取到最后一个值。
要想获取generator中的值我们可以使用next()来获取,但使用生成器来生成list不可能只用一两个数,所以一般是使用for循环来遍历获取值,这样就方便多了。
因为generator内部是函数,所以我们也可以直接将一个函数变成generator。比如一个实现斐波那契数列的genertator:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
当函数中有一个yield关键字时,就说明了这个函数是一个generator函数了。
generator的执行流程和一般函数不一样,一般函数是执行到return或者是结尾就会停止执行了,而generator函数则是执行到yield就会返回,再执行会从上次yield处继续执行。
迭代器
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
高阶函数
在Python中,变量可以指向函数,函数的参数也能接收变量。那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
map
map需要接收两个参数:一个是函数,一个是Iterable。map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
reduce
reduce和map一样需要同样的两个参数,只不过reduce要将结果和序列的下一个元素做累积运算。所以reduce的函数要有两个参数。效果如下:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
filter
filter(过滤器)在Python中用于过滤序列。
filter和map一样需要一个函数和一个序列,不同点在于filter将函数依次作用于每个序列元素,然后根据返回值是True还是False丢弃该元素。True留下,False丢弃。
由于filter()使用了惰性计算,所以只有在取filter()结果的时候,才会真正筛选并每次返回下一个筛出的元素。
sorted
Python内置的sorted可以用于对list进行排序,它还可以接收一个key函数来实现自定义的排序。
如按绝对值大小进行排序:
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。
返回函数
将一个函数作为结果返回,在使用时要格外注意。
匿名函数
匿名函数的具体使用如下所示:
list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
lambda x: x * x
这部分就是匿名函数,匿名函数使用lambda表示,冒号前的x表示参数。匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
使用匿名函数的好处就在于不用担心重名的问题。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数,也可以将其作为返回的内容。
装饰器
没看明白
偏函数
固定一些函数的参数,形成偏函数,方便我们的使用。
使用functools.partial帮助我们创建一个偏函数。
比如将数转换成二进制,定义偏函数可以这样定义:
def int2(x, base=2):
return int(x, base)
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
这里只是修改参数的默认值,我们仍可以传参进去。
>>> int2('1000000', base=10)
1000000
模块
随着开发的深入,我们一个文件的代码会越来越多,越来越难以维护。为了代码的可维护性,我们可以将代码分成多组放在不同的文件中,这样一个文件内的维护代码就会减少。在Python中一个.py文件就称为一个模块(Module)。
当一个模块编写完成后其他的模块就可以引用过来直接使用,这样还可以避免方法重名的情况发生。A模块的add函数和B模块的add函数是不一样的。
python同时为了防止模块名相同导致的问题提供了包的机制,我们将.py文件放在包中,只要包名不同,那么两个包中的同名方法也会不同。
每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。__init__.py可以是空文件,也可以有Python代码,因为__init__.py本身就是一个模块,而它的模块名就是mycompany。
作用域
在使用的过程中,我们就会有一些使用范围的需求:这个方法只能在这个包内使用,那个方法谁都能使用。在java中是定义如public、private等修饰词实现的,在Python中是通过_实现的。
正常的函数和变量名都是公开的,可以随意引用。
类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,我们尽量不要使用这种方法命名。
类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用