Quantcast
Channel: Sam的技术Blog
Viewing all articles
Browse latest Browse all 158

Python使用记录

$
0
0
作者: Sam (甄峰)  sam_code@hotmail.com

屡次使用python2.x python3. 记录备忘。

1. Python的函数。

1.1:

1.2:匿_名函数:
1.2.1: lambda简介:
python使用 lambda来创建匿_名函数。
lambda的主体是一个表达式,而不是一个代码块,仅仅能在lambda表达式中封装有限的逻辑。
它有着自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。

lambda使用方法如下:
lambda [arg1 [,arg2,.....argn]]: Exp
例如:
sum = lambda x, y: x+y

s1 = sum(2,3)
print("Sum is:", s1)

结果为:
('Sum is:', 5)

lambda与C/C++中内联函数的区别:
C/C++中的内联函数是为了调用小函数时不占用栈内存从而增加运行效率。 而lambda并不提高效率,只是为了使得代码简练清晰。


1.2.2.:与filter, map, reduce组合使用:
Python提供了几个函数方便用户使用---filter, map, reduce。他们支持把函数作为参数。

filter:
filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。

该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。



所以可以使用lambda创建一个匿_名函数,作为filter的第一个参数。
参数
function -- 判断函数。
iterable -- 可迭代对象。
返回值
返回一个迭代器对象(Python3)
Python2中,则返回列表。

Python2:
old_v = [1,2,3,4,5,6,7,8]

new_v = filter(lambda x:x % 2 == 0, old_v)
print(new_v)
结果:
[2, 4, 6, 8]

map():
描述
map() 会根据提供的函数对指定序列做映射。

第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

语法
map() 函数语法:

map(function, iterable, ...)
参数
function -- 函数
iterable -- 一个或多个序列

返回值
Python 2.x 返回列表。
Python 3.x 返回迭代器。

例:
old_v = [1,2,3,4,5,6,7,8]
plus_v = [2,3,4,5,6,7,8,9]


plus_new = map(lambda x, y: x+y, old_v, plus_v)
print(plus_new)

结果:
[3, 5, 7, 9, 11, 13, 15, 17]


reduce()
描述
reduce() 函数会对参数序列中元素进行累积。

函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。

语法
reduce() 函数语法:

reduce(function, iterable[, initializer])
参数
function -- 函数,有两个参数
iterable -- 可迭代对象
initializer -- 可选,初始参数
返回值
返回函数计算结果。



2. 迭代器和生成器:
2.1:迭代器(iterator):
迭代是Python最强大的功能之一。是访问集合元素的一种方式。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完而结束。 迭代器只能前进不能后退。
迭代器有两个基本方法: iter(), next()
iter()用来创建迭代器对象。它返回一个特殊的迭代器对象,这个对象实现了next()方法。
next()逐一返回迭代器对象中的元素。当没有数据可用时,会引发:StopIteration异常。

利用迭代器对象,可是使用for....in方式逐个访问集合内元素。


字符串,元祖(tuple)或者列表(List)对象都可以用于创建迭代器。文件对象(相当于文件描述符)也可以用来创建迭代器--文件迭代器。(见注1:可迭代对象),

例1:List, tuple, 字符串对象用来创建迭代器。

#List
list1 = [1,2,3,4,5,"sam", "test"]
it = iter(list1)
print("Iter1",next(it))
for i in it:
    print(i)


Iter1 1
2
3
4
5
sam
test


注意:it是一个迭代器,可以通过next(it)和for 去取下一个元素。 但它只能从前往后取。 所以第一个next(it)取出一个元素后。 for则从下一个开始取。


#Tuple
tuple1 = ("t1", "t2", 9,8,7)
it = iter(tuple1)
print("Iter2")
for i in it:
    print(i)


Iter2
t1
t2
9
8
7
   
#String
var1 = "Hello World!"
it = iter(var1)
print("Iter3:")
for i in it:
    print(i)



Iter3:
H
e
l
l
o
 
W
o
r
l
d
!

#文件迭代器
逐行显示文件内容。
for i in open("test.txt", encoding="utf-8"):
    print(i)

也可以自定义迭代器。
例:



2.2: 生成器(generator):
生成器是个函数,与普通函数不同的是,它返回一个迭代器。
生成器的表示是使用yield.
在调用生成器过程中,每次遇到yield时,函数会暂停并保存当前所有运行信息,返回yield的值,并在下一次调用时从当前位置继续执行。

def fibonacci(n): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
        
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
 
for i in f:
    print(i)


0
1
1
2
3
5
8
13
21
34
55


3. 文件夹的遍历:
3.1. os.walk()

 os.walk(top, topdown=True, onerror=None, followlinks=False)
os.walk()用来遍历目录中的子目录和文件。它本身是个生成器(generator)---Directory tree generator
所以它的返回值就是一个迭代器。---yields a 3-tuple
分别为:dirpath, dirnames, filenames
代表了:
dirpath: 是个string.当前正在遍历的目录。
dirnames:是个list. 内容是dirpath目录内所有目录名(不包括子目录,不包括 . 和 ..)
filenames:是个list.内容是dirpath目录内所有文件名。(不包括子目录内的文件)

参数: 
top: 要遍历的目标目录。
topdown: True,则优先遍历top目录。  false:优先遍历top的子目录。

例:
for root,dirs,files in os.walk("../"):
    print("\nroot:", root)
    print("Dir:")
    for dir in dirs:
        print(dir)
    print("Files:")    
    for file in files:
        print(file)
因为是个迭代器, 所以可以用 for.....in ....



3.2: os.listdir()

os.listdir(path=None)
返回一个list. 包含目录path内左右文件名(包括目录名)。
for file in os.listdir("../"):
    print(file)





注1:
可迭代对象(iterable):
可迭代对象是能够逐一返回其成员项的对象。包括序列类型(如:list, 字符串,tuple)和非序列类型(如dict,文件对对象,定义__iter__()方法的任何自定义类对象)。
一个可迭代对象都有一个__iter__()方法。 也就是说,有 __iter__()方法的对象,就是可迭代对象。

注2:
迭代器,生成器相关:

问题一:既然可迭代对象也可以使用for循环遍历,为何还要使用迭代器呢?

一般情况下不需要将可迭代对象封装为迭代器。但是想象一种需要重复迭代的场景,在一个class中我们需要对输入数组进行正序、反序、正序step=1、正序step=2等等等等的多种重复遍历,那么我们完全可以针对每一种遍历方式写一个迭代容器,这样就不用每次需要遍历时都费劲心思的写一堆对应的for循环代码,只要调用相应名称的迭代器就能做到,针对每一种迭代器我们还可以加上类型判断及相应的处理,这使得我们可以不必关注底层的迭代代码实现。

从这种角度来看,你可以将迭代器看做可迭代对象的函数化,有一个非常流行的迭代器库itertools,其实就是如上所说的,他为很多可迭代类型提前定义好了一些列的常见迭代方式,并封装为了迭代器,这样大家就可以很方便的直接通过调用此模块玩转迭代。

此外iterator还可以节省内存,这点在问题二会描述。

问题二:生成器(generator)如何节约内存的?

generator的标志性关键字yield其实可以看作return,以本文上述的generator_list()方法为例,generator_list(a)就是一个生成器。

生成器最大的好处在于:generator_list(a)并不会真正执行函数的代码,只有在被循环时才会去获取值,且每次循环都return一个值(即yield一个值),在处理完毕后下次循环时依然使用相同的内存(假设处理单位大小一样)来获取值并处理,这样在一次for循环中函数好像中断(yield)了无数次,每次都用相同大小的内存来存储被迭代的值。

yield与return的最大区别就是yield并不意味着函数的终止,而是意味着函数的一次中断,在未被迭代完毕之前yield意味着先返回一次迭代值并继续下一次函数的执行(起始位置是上一次yeild语句结束),而return则基本意味着一个函数的彻底终止并返回一个全量的返回值。

因此generator是为了节省内存的,而且将函数写为一个生成器可以使函数变的可迭代,如果我们想遍历函数的返回值,我们不用再单独定义一个可迭代变量存储函数的返回值们,而是直接迭代生成器函数即可(除非函数本身返回一个全量的可迭代对象)。

同理iterator的__iter__()方法只是一个迭代的入口,每次调用__next__()时返回一个迭代值,同样以O(1)的空间复杂度完成了迭代。

问题三:iterator与generator的异同?

generator是iterator的一个子集,iterator也有节约内存的功效,generator也可以定制不同的迭代方式。






 

Viewing all articles
Browse latest Browse all 158

Trending Articles