python第二版知识点_python重要知识点总结二

目录

1、生成器

2、列表解析

3、函数式编程

4、描述器

5、迭代器

1、生成器

参考学习

为什么要使用生成器?很多时候,通过列表生成的可迭代对象占用内存会很大,而且若只是要访问前面几个元素,那后面的内存空间就会被浪费。若迭代器的构建是通过一个函数,也就是说有规律的,则可以使用生成器,在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。

生成器的构造方式一

L = [x * x for x in range(10)]

print L

print type(L)

L = (x * x for x in range(10))

print L

print L.next()

print next(L)

print type(L)

for item in L:

print item

输出为:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

at 0x027F3A30>

0

1

4

9

16

25

36

49

64

81

上面可以看出,最大的不同就是[]和(),回忆(1,2,3)类型其实是一个元祖,元祖的特点就是元素不可变。但为什么这里却变成了一个生成器呢,深层次原理不考究,简单来说这里包含了元素计算的算法,生成器保存的实际上是该算法。注意,生成器也是可迭代对象,能进行for操作。

通过 yield关键字

def fib(max):

n, a, b = 0, 0, 1

while n < max:

yield b

a, b = b, a + b

n = n + 1

print type(fib)

print fib(5)

gen = fib(5)

print gen.next()

for item in gen:

print item

输出结果:

1

1

2

3

5

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator.

generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。这也隐藏了一个问题,获取第一个元素的值也是要通过next调用。

生成器还有一些高级用法,如send()函数可以向生成器传入一个值。更多可以参考generator send

列表解析式是将一个列表(实际上适用于任何可迭代对象(iterable))转换成另一个列表的工具。在转换过程中,可以指定元素必须符合一定的条件,才能添加至新的列表中,这样每个元素都可以按需要进行转换

new_things = []

for ITEM in old_things:

if condition_based_on(ITEM):

new_things.append("something with " + ITEM)

你可以将上面的for循环改写成这样的列表解析式:

new_things = ["something with " + ITEM for ITEM in old_things if condition_based_on(ITEM)]

再例如:

numbers = [1, 2, 3, 4, 5]

doubled_odds = []

for n in numbers:

if n % 2 == 1:

doubled_odds.append(n * 2)

转换成了这两行代码:

numbers = [1, 2, 3, 4, 5]

doubled_odds = [n * 2 for n in numbers if n % 2 == 1]

上面的其实也比较简单,需要自己有这个意识主动使用列表解析。而什么时候需要用到列表解析呢?在创建一个列表或其他的可迭代对象时,对其中的元素需要判断后再添加进去,或者判断后进行适当操作再添加,就需要用到列表解析。

再看几个其他的列表解析:

循环嵌套

flattened = []

for row in matrix:

for n in row:

flattened.append(n)

可以写为:

matrix = [(1,2,3),(4,5,6)]

# for row in matrix:

# for n in row:

# flattened.append(n)

flattened = [n for row in matrix for n in row]

print flattened

这样写是错误的,flattened = [n for n in row for row in matrix],for循环的顺序和之前的顺序是一样的。

注意可读性

长长的一行读起来很费力,可适当分行如下:

flattened = [

n

for row in matrix

for n in row

]

3、函数式编程基础 map filter

map

map(function,iterable),对iterable中每个元素应用function。

version_info = (4, 8)

version = '.'.join(map(str, version_info))

>>> map(lambda x: x + "bzz!",["I think","I'm good"])

['I thinkbzz!', "I'm goodbzz!"]

第一个,返回值是4.8,很简单,map将version_info中的整形转换为字符,然后各个字符之间用‘.’连接。

第二个要注意,Python2中返回的是一个列表,而在Python3中是返回可迭代的对象。

map在一定程度上也可以用列表解析替换如:

[x + 'bzz' for x in ["I think","I'm good"]]

filter

对所给的可迭代对象进行过滤

>>> def f(x): return x % 2 != 0 and x % 3 != 0

>>> filter(f, range(2, 25))

[5, 7, 11, 13, 17, 19, 23]

enumerate(iterable[,start])

该函数返回可迭代的enumerate对象,生成一个元组序列,每个元组包含一个整形索引(默认从0开始,也可以指定start)和迭代对象中对应的元素。

mylist = ['hello','how','are','you']

for i, item in enumerate(mylist):

print "Item %d: %s" % (i, item)

输出为:

Item 0: hello

Item 1: how

Item 2: are

Item 3: you

>>> mylist = [1,2,4]

>>> enumerate(mylist)

>>> list(enumerate(mylist))

[(0, 1), (1, 2), (2, 4)]

>>>

any(iterable) 和 all(iterable)

主要用来判断给定迭代对象是否满足相应条件,all表示要都满足,而any表示至少有一个满足时返回真。这两个函数只有一个输入,而且是对每个元素判断ture or faulse,因此常常和map函数配合使用。

等价于

def all(iterable):

for item in iterable:

if not item:

return False

return True

def any(iterable):

for item in iterable:

if item:

return True

return False

mylist = [0,1,2,3,-2]

print map(lambda x: x > 0, mylist)

if all(map(lambda x: x > 0, mylist)):

print 'all item grater than 0'

else:

print 'some less than 0'

输出为:

[False, True, True, True, False]

some less than 0

zip(iter1 [,iter2 [...]])

主要用于将一组键和一组值组合成字典。

print zip(['hello','world'],['hi','big'],['nice','night','right'])

[('hello', 'hi', 'nice'), ('world', 'big', 'night')]

该函数接收多个序列并将它们组合成元组,值得注意的是木桶效应,生成的列表(Python2中返回列表,3中为迭代对象)取决于最短的输入序列长度。

4、描述符

一个描述符就是一个对象,该对象代表了一个属性的值。这就意味着如果一个账户对象有一个属性“name”,那么描述符就是另一个能够用来代表属性“name”持有值的对象。描述符协议中“定义了__get__”、“__set__”或”__delete__” 这些特殊方法,描述符是实现其中一个或多个方法的对象。

class Descri(object):

def __init__(self,name):

self.name = name

def __get__(self, instance, owner):

print '__get__'

return self.name

def __set__(self, instance, value):

print '__set__'

self.name = value

D = Descri('hello')

D.name = '123'

print D.name

D.name = 'yuan'

print D.name

class Foo(object):

name = Descri('dodo')

F = Foo()

print F.name

F.name = 'Jiessie'

输出为:

123

yuan

__get__

dodo

__set__

上面的程序很有意思,为什么直接调用Descri类没有进入__get__方法,而下面通过另一个类调用却会进入。首先要明确什么是描述符,顾名思义,在python中是用来描述一个属性的,一般来说,像上面Foo类name属性,回忆总结一中,当实例化后,在类的外面是可以随便修改属性值的,而描述符会对它所代表的类的属性执行类型检查等自定义操作,这也是描述符存在的价值。

当访问类Foo实例的任何属性时,描述符会调用它的__get__方法。需要注意的是,__get__方法的第一个参数是描述符代表的属性被引用的源对象。当属性被分配时,描述符会调用它的__set__方法。当没有定义__set__方法时就是只读变量。

描述符可以用来对变量值进行检查,但相对繁琐,提供了另一种相对简洁方式,property(fget=None, fset=None, fdel=None, doc=None) ,然后实现相关函数即可。

很容易想到property修饰符也表示了同样的工作,并且更简洁,因此,主要用@property这种方式,但描述符需要理解。

5、迭代器

可以直接作用于for循环的对象统称为可迭代对象Iterable。有以下几种:

一类是集合数据类型,如list、tuple、dict、set、str等;

一类是generator,包括生成器和带yield的generator function。

由之前知道,生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

于是,迭代器就是可以被next()函数调用并不断返回下一个值的对象。要分清楚可迭代对象和迭代器。

from collections import Iterable,Iterator

print isinstance([],Iterable)

print isinstance((),Iterable)

print isinstance({},Iterable)

print isinstance([],Iterator)

print isinstance((),Iterator)

print isinstance({},Iterator)

print isinstance((x*x for x in range(2,5)),Iterator)

输出为:

True

True

True

False

False

False

True

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值