本文是廖雪峰教程学习记录,廖雪峰链接:http://blog.csdn.NET/GarfieldEr007/article/details/52422494?locationNum=1&fps=1
切片、迭代、enumerate、collections.Iterable、isinstance、列表生成式、生成器generator、map()、reduce()、lambda函数、join、filter、strip、修饰器decorator、偏函数functools.partial
①切片
取list中的元素:L[a:b:c],索引a开始的b个元素中,每c个取一个
>>> L=['A','B','C','D','E']
>>> L[0:3]
['A', 'B', 'C'] #取索引0开始,索引3前的元素
>>> L[-3:-1]
['C', 'D'] #取索引-3开始,索引-1前的元素
>>> L[-2:] #索引-2以后的元素
['D', 'E']
>>> L=range(100)
>>> L[:10:2] #前10个数,每两个取一个
[0, 2, 4, 6, 8]
>>> (1, 2, 3, 4, 5)[2:5]#tuple
(3, 4, 5)
>>> 'ABCDEFG'[2:5] #string
'CDE'
>>> u'ABCDEFG'[2:5]#Unicode
u'CDE'
二、迭代
for循环遍历list、tuple、dict、字符串等,这种遍历成为迭代。
遍历dict:
>>> d={'a':1,'b':2,'c':3}#默认迭代的是key
>>> for key in d:
... print key
...
a
c
b
>>> for value in d.itervalues():#迭代value
... print value
...
1
3
2
>>> for k,v in d.iteritems(): #key、value一起迭代
... print k,v
...
a 1
c 3
b 2
通过collections模块的Iterable类型可判断对象是否可迭代:
>>> from collections import Iterable
>>> isinstance('abc',Iterable)
True
import和from……import的区别:直接输Iterable到程序中,而不用使用collections.Iterable
>>> import collections
>>> isinstance('abc',collections.Iterable)
True
Python内置的enumerate函数可把list转变成索引-元素对,使得可以在for循环中迭代索引、元素对:
>>> for i, value in enumerate(['A','B','C']):
... print i, value
...
当然也可以:
>>> for i in range(3):
... print i, ['A','B','C'][i]
...
for循环中同时引用两个变量还如:
>>> for x, y in [(1, 1), (2, 4), (3, 9)]:
... print x, y
...
三、列表生成式
List Comprehensions,强大的创建list的生成式:
>>> range(1,11) #生成简单1~10
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> L=[]
>>> for i in range(1,11): #生成1*1 ~10*10
... L.append(i*i)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> [i*i for i in range(1,11)] #简化上述循环
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> [i*i for i in range(1,11) if i%2 ==0]#后面还可跟if
[4, 16, 36, 64, 100]
>>> [m+n for m in 'ABC' for n in 'XYZ']#还可两层循环
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
列表生成式可列出当前目录下所有目录和文件,一行代码即可实现:
>>> import os #os模块
>>> [d for d in os.listdir('.')] #listdir可列出文件和目录
['a.py', 'a.pyc', 'b.py', 'def.py', 'math.py', 'test1.py', 'while.py']
上述二中,dict的key、value一起迭代的for循环也可以用列表生成式:
>>> d={'a':'A','b':'B','c':'C'}#key和value不是同种类型时好像有问题来着?报错了
>>> [k + '='+ v for k,v in d.iteritems()]
['a=A', 'c=C', 'b=B']
将list中的所有字符串变成小写:
>>> L=['Hello', 'World', 'Hello', 'Everyone']
>>> [s.lower() for s in L]
['hello', 'world', 'hello', 'everyone']
四、生成器
在Python中,这种一边循环一边计算的机制,称为生成器(Generator),这样可以节省内存,元素需要时再生成。
generator的生成方法有两种:
一直接把列表生成式的[]改为():
>>> L=[x*x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g=(x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x000000000312BA20>
>>> g.next()
0
>>> g.next()
1
>>> for n in g:
... print n
...
4
9
16
25
36
49
64
81
generator生成的第二种方法:
斐波拉契数列用列表生成式表达不出来,可用函数表达,在函数定义中包含yield关键字,就变成了generator:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b #将普通函数的print b
a, b = b, a + b
n=n + 1
五、
变量可以指向函数
>>> f=abs
>>> f(-10)
10
函数名可以看成变量,如abs可以看成一个变量,指向一个可以计算绝对值的函数。
函数可以接收另一个函数作为参数,即高阶函数。
六、map()/reduce()
map()函数有两个参数:一个是函数,另一个是序列,map 将传入的函数依次作用到序列的每个元 素,并把结果作为新的list返回。
eg:
>>> def f(x):
... return x*x
...
>>> map(f,[1,2,3,4,5,6,7,8,9])
[1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> map(f,range(1,10))
[1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> map(str,range(1,10))
['1', '2', '3', '4', '5', '6', '7', '8', '9']
reduce用法。
reduce把一个函数作用在一个序列[x1,x2,x3...]上,这个函数须接收两个参数,reduce把结果继续和序列的下一个元素做累积运算,即为:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
eg:
序列求和
>>> def add(x, y):
... return x + y
...
>>> reduce(add, [1, 2, 3, 4])
10
将字符串'13579'转成数字13579可使用reduce和map函数:
>>> def str2int(s):
... def fx(x, y):
... return x*10+y
... def char2num(s):
... return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]
... return reduce(fn, map(char2num, s))
...
>>> str2int('12345')
12345
可用lambda函数精简该函数:
>>> def char2num(s):
... return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s]
...
>>> def str2int(s):
... return reduce(lambda x, y: x*10+y, map(char2num, s))
...
lambda函数:起到一个函数速写的作用。允许在代码内嵌入一个函数的定义
>>> f=lambda x, y, z: x+y+z
>>> f(1,2,3)
6
练习:
1、利用 map() 函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输 入: ['adam', 'LISA', 'barT'] ,输出: ['Adam', 'Lisa', 'Bart'] 。
>>> def f(s):
... L=[]
... L.append(s[0:1].upper())
... for i in range(1,4):
... L.append(s[i:i+1].lower())
... return ''.join(L) #''.join(L)可把list的各元素连起来转化成字符串,''单引号中可填用#什么连接各元素,如空格,加号
...
>>> map(f, ['adam','LISA','barT'])
['Adam', 'Lisa', 'Bart']
2、Python提供的 sum() 函数可以接受一个list并求和,请编写一个 prod() 函数,可以接受一个list并利用 reduce() 求 积。
>>> L=[1,2,3,4]
>>> def mul(x,y):
... return x*y
...
>>> def prod(L):
... return reduce(mul,L)
...
>>>
>>> prod(L)
24
七、filter
Python内建的 filter() 函数用于过滤序列。
filter()接收一个函数和一个序列,把传入的函数一次作用于每个序列里的元素,来觉得是否舍弃该元素。
把一个序列的空字符串删掉:
>>> def not_empty(s):
... return s and s.strip()# strip() 方法用于移除字符串头尾指定的字符(默认为空格)。
...
>>> filter(not_empty,['A', '', 'B', None, 'C', ' '])
['A', 'B', 'C']
strip() 方法用于移除字符串头尾指定的字符(默认为空格)。
>>> str="000000hello how are you00000"
>>> str.strip('0')
'hello how are you'
>>> str=" hello how are you "
>>> str.strip()
'hello how are you'
八、sorted
sorted函数可以对list排序
>>> sorted([4,2,5,11])
[2, 4, 5, 11]
sorted也可以接收一个比较函数实现自定义排序:
>>> def reversed_cmp(x,y):
... if x>y:
... return -1
... if x<y:
... return 1
... return 0
...
>>> sorted([4,2,5,11], reversed_cmp)
[11, 5, 4, 2]
九、函数作为返回值
高阶函数除了可以把函数作为入参,也可以把函数作为返回值
可变参数的求和,不是立即需要和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求 和的函数!
>>> def lazy_sum(*args):
... def sum():
... ar=0
... for n in args:
... ar=ar+n
... return ar
... return sum
...
>>> f
<function sum at 0x000000000381EF28>
>>> f() #调用f时,才真正计算求和结果
25
当调用 lazy_sum() 时,每次调用都会返回一个新的函数,即使传入相同的参数:
>>> f1=lazy_sum(1,3,5,7,9)
>>> f2=lazy_sum(1,3,5,7,9)
>>> f1==f2
False
当 lazy_sum 返回函数 sum 时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closur e)”
返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
十、装饰器
>>> def now():
... print '2013-12-25'
...
>>> f=now
>>> f()
2013-12-25
>>> f.__name__ #函数对象有个__name__属性,可以拿到函数的名字
'now'
们要增强 now() 函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改 now() 函数的定 义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
>>> def log(func): #定义一个能打印日志的decorator
... def wrapper(*args, **kw):
... print 'call %s():' % func.__name__
... return func(*args, **kw)
... return wrapper
...
借助Python 的@语法,把decorator置于函数的定义处:
>>> @log #把@log放到此处,相当于执行了now=log(now)
... def now():
... print '2013-12-25'
...
>>> now()
call now():
2013-12-25
>>> now.__name__
'wrapper'
上面@log处,相当于执行now=log(now),原来的now()函数仍存在,只不过现在同名的now变量指向了新的函数,
于是调用now()执行新的函数。
若decorator需传入参数
>>> def log(text):
... def decorator(func):
... def wrapper(*args,**kw):
... print '%s %s():' % (text, func.__name
__)
... return func(*args,**kw)
... return wrapper
... return decorator
...
>>> @log('execute') #相当于执行了log('execute')(now)
... def now():
... print '2013-12-25'
...
>>> now()
execute now():
2013-12-25
此时:
>>> now.__name__
'wrapper'
__name__从now变成了wrapper,需要把原始函数的 __name__ 等属性复制 到 wrapper() 函数中,import functools 后,在定义 wrapper() 的前面加 上 @functools.wraps(func) 即可。
练习:
1、请编写一个decorator,能在函数调用的前后打印出 'begin call' 和 'end call' 的日志。
十一、偏函数
Python的 functools 模块提供了很多有用的功能,其中一个就是偏函数(Partial function)
>>> int('100000',base=2)
32
若想把大量的二进制转化为十进制,可定义带默认参数base=2的函数int2来简化:
def int2(x, base=2):
return int(x, base)
functools.partial可不需要再自定义int2
>>> import functools
>>> int2=functools.partial(int,base=2)
>>> int2('100000')
32
可知functools.partial的作用是把函数的某些参数设为默认参数,返回一个新的函数。
创建偏函数,参数可以当做是①函数对象②*args③**kw这三个参数
故上面base=2可当做是固定了关键字参数。
>>> max2=functools.partial(max,10)#10作为*args的一部分传到左边
>>> max2(5,6,7) #max(10,5,6,7)
10
十二、模块
(一)
一个.py文件是一个模块。为避免不同人写的模块名字相同,可按目录来组织模块,称为包package。
每个包目录下有个__init__.py文件,可为空文件,也可有代码,它也是模块,模块名是包名。
#!/usr/bin/env python#使可以在Linux运行
# -*- coding: utf-8 -*-#使用标准utf-8编码
'test_module.py' #模块的第一个字符串被视为文档的注释,可用变量__doc__访问
__author__ = 'hello' #__author__作者
import sys
def test():
args = sys.argv#sys模块的argv变量是个list,储存了所有变量,
#执行python test_module.py hello aa时,sys.argv=['test_module.py',#'hello', 'aa']
if len(args)==1:
print 'Hello World'
print args
elif len(args)==2:
print 'Hello, %s' % args[1]
print args
else:
print 'Too many arguments'
print args
if __name__=='__main__': #在命令行运行test_module模块时,Python解释器把变量__name__置为#__main,若在其他地方import test_module时,不执行test()函数
test()
print ' aaaaa ',__name__#导入时,__此处__name__为test_module
(二)模块别名
try:
import cStringIO as StringIO#优先使用cStringIO
except ImportError: # 导入失败会捕获到ImportError
import StringIO#导入cStringIO失败才用StringIO
(三)模块函数变量作用域
公有变量:可被外部访问,如abc
私有变量:不希望被外部访问,定义时可用_前缀,如_abc
特殊变量:__name__、__doc__、__author__等
(四)搜索路径
>>> import sys
>>> sys.path
['', 'C:\\WINDOWS\\SYSTEM32\\python27.zip', 'C:\\Python27\\DL
Ls', 'C:\\Python27\\lib', 'C:\\Python27\\lib\\plat-win', 'C:\
\Python27\\lib\\lib-tk', 'C:\\Python27', 'C:\\Python27\\lib\\
site-packages']
>>>sys.path.append('********')
十三、__future__模块
该模块提供把Python下个版本的特性代码导入当前版本,来测试新版本特性。
在2.7的版本中,可使用unicode_literals来使用3.x的版本的字符串表示方法:2.7的'xxx'表str,u'xxx'表unicode,3.x的'xxx'和u'xxx'都表unicode,3.x以'xxx'表示的str前面必须加b,即b'xxx',表二进制字符串。
from __future__ import unicode_literals
在2.x中运行3.x的除法,可用__future__中的division实现:2.x中,两整数相除也为整数,3.x两整数相除都为精确商,若得到像2.x的整数结果,可用//表示。