python基础-特性
导航:
高阶特性:
切片:Python没有针对字符串的截取函数,只需要切片一个操作就可以完成
迭代:Python的for
循环抽象程度要高于Java的for
循环,因为Python的for
循环不仅可以用在list或tuple上,还可以作用在其他可迭代对象上
列表生成器:即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式
生成器:Generator,一系列算法,使用时才计算值,一般采用for遍历.关键字yield
高阶函数:
map: map()
函数接收两个参数,一个是函数,一个是序列,map
将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
reduce: reduce() 函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。
filter: filter()
也接收一个函数和一个序列。和map()
不同的时,filter()
把传入的函数依次作用于每个元素,然后根据返回值是True
还是False
决定保留还是丢弃该元素。
sorted: Python内置的sorted()
函数就可以对list进行排序.
返回函数:函数作为返回值,闭包
匿名函数:不需要显式地定义函数,直接传入匿名函数,关键字lambda
表示匿名函数,冒号前面的值表示函数参数.
函数参数:必选参数、默认参数、可变参数和关键字参数.
装饰器:增强函数的功能,但又不希望修改now()
函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
偏函数:functools.partial
,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
高阶特性:
切片:Python没有针对字符串的截取函数,只需要切片一个操作就可以完成,非常简单。
L[a:b] , 获取下标a至下标(b-1)之间的元素,如果a为0还可以省略,例如:L[:3]
L[-a:-b],获取倒数第a个元素至倒数第b个元素之间的元素,如果-b 为-1 还可以省略,例如:[-10:]
L[a:b:c],获取下标a至下标(b-1)之间的元素,并且每隔c个元素取得一个元素,如果a和b是负数,同上,c不能为负数,否则返回空集.
L[::c],每隔c个元素取一个元素,且c不能为负数.
迭代: Python的for
循环抽象程度要高于Java的for
循环,因为Python的for
循环不仅可以用在list或tuple上,还可以作用在其他可迭代对象上。
迭代是通过for ... in
来完成
只要是可迭代对象,无论有无下标,都可以迭代,比如字符串:
>>> for ch in 'ABC': ... print ch ... A B C
只要作用于一个可迭代对象,for
循环就可以正常运行,判断一个对象是可迭代对象:
>>> from collections import Iterable >>> isinstance('abc', Iterable) # str是否可迭代 True >>> isinstance([1,2,3], Iterable) # list是否可迭代 True >>> isinstance(123, Iterable) # 整数是否可迭代 False
Python内置的enumerate
函数可以把一个list变成索引-元素对,这样就可以在for
循环中同时迭代索引和元素本身:
>>> for i, value in enumerate(['A', 'B', 'C']): ... print i, value ... 0 A 1 B 2 C
for
循环里,同时引用了多个变量,在Python里是很常见的,比如下面的代码:
>>> for x,y,z in [(1,1,2),(2,4,6),(3,9,12)]: ... print x,y,z ... 1 1 2 2 4 6
3 9 12
dict迭代的是key。如果要迭代value,可以用for value in d.itervalues()
,如果要同时迭代key和value,可以用for k, v in d.iteritems()
即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式:
>>> [str(x)+'*'+str(x) for x in range(1,11)] ['1*1', '2*2', '3*3', '4*4', '5*5', '6*6', '7*7', '8*8', '9*9', '10*10'] >>> [x * x for x in range(1,11)] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] >>> [x * x for x in range(1,11) if x % 2 == 0] [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('.')] # os.listdir可以列出文件和目录 ['.emacs.d', '.ssh', '.Trash', 'Adlm', 'Applications', 'Desktop', 'Documents', 'Downloads', 'Library', 'Movies', 'Music', 'Pictures', 'Public', 'VirtualBox VMs', 'Workspace', 'XCode']
>>> d = {'a':'A','u':'B','z':'C'} >>> [ k + '=' + v for k,v in d.iteritems()] ['a=A', 'z=C', 'u=B']
>>> L = ['Hello','World','IBM','Apple'] >>> [s.lower() for s in L] ['hello', 'world', 'ibm', 'apple']
list中既包含字符串,又包含整数,由于非字符串类型没有lower()
方法:
>>> L = ['Hello','World',18,'Apple',None] >>> [s.lower() for s in L if isinstance(s,str)] ['hello', 'world', 'apple']
生成器:列表元素按照某种算法推算出来,可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)
创建一个generator,有很多种方法:
1、把一个列表生成式的[]
改成()
,就创建了一个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 0x0250DEB8>
打印出generator的每一个元素,如果要一个一个打印出来,可以通过generator的next()
方法
>>> g.next() 0 >>> g.next() 1 >>> g.next() 4
也可以采用遍历的方式:
>>> from collections import Iterable >>> isinstance(g,Iterable) True >>> [ j for j in g] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for
循环无法实现的时候,还可以用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1
2、如果一个函数定义中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator:
>>> def fib(max): ... n,a,b = 0,0,1 ... while n < max: ... yield b ... a,b = b, a + b ... n = n + 1 ... >>> fib(6) <generator object fib at 0x024FC328>
最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行。
高阶函数:就是让函数的参数能够接收别的函数。
map()
函数接收两个参数,一个是函数,一个是序列,map
将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
reduce把一个函数作用在一个序列[x1, x2, x3...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
更多python内建函数:https://docs.python.org/2/library/functions.html
filter()
也接收一个函数和一个序列。和map()
不同的时,filter()
把传入的函数依次作用于每个元素,然后根据返回值是True
还是False
决定保留还是丢弃该元素
>>> def is_odd(n): ... return n %2 ==1 ... >>> filter(is_odd,[1,2,4,5,6,8,9]) [1, 5, 9]
>>> def not_empty(s): ... return s and s.strip() ... >>> filter(not_empty,['A','','B',None,'C',' ']) ['A', 'B', 'C']
练习:filter()
删除1~100的素数 以及 filter()删除1~100的非素数:
#判断是不是素数/质数
def is_primes(n): for i in range(2,n): if n % i == 0: return False; return True;
#判断不是素数/质数 def not_primes(n): for i in range(2,n): if n % i == 0: return True return False; if __name__ == '__main__': notp = filter(not_primes,range(2,101)) #100以内不是素数/质数的 isp = filter(is_primes,range(2,101)) #100以内是素数/质数的 print notp print isp
[4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 38, 39, 40, 42, 44, 45, 46, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 60, 62, 63, 64, 65, 66, 68, 69, 70, 72, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100]
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Python内置的sorted()
函数就可以对list进行排序:
>>> sorted([36, 5, 12, 9, 21])
[5, 9, 12, 21, 36]
sorted()
函数也是一个高阶函数,它还可以接收一个比较函数来实现自定义的排序。比如,如果要倒序排序,我们就可以自定义一个reversed_cmp
函数:
def reversed_cmp(x, y): if x > y: return -1 if x < y: return 1 return 0
>>> sorted([36, 5, 12, 9, 21], reversed_cmp)
[36, 21, 12, 9, 5]
>>> sorted(['bob', 'about', 'Zoo', 'Credit']) ['Credit', 'Zoo', 'about', 'bob']
def cmp_ignore_case(s1, s2): u1 = s1.upper() u2 = s2.upper() if u1 < u2: return -1 if u1 > u2: return 1 return 0
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], cmp_ignore_case) ['about', 'bob', 'Credit', 'Zoo']
def lazy_sum(*args): def sum(): ax = 0 for n in args: ax = ax + n return ax return sum
调用函数返回的函数时,才真正计算求和的结果:
>>> f = lazy_sum(1, 3, 5, 7, 9) >>> f <function sum at 0x10452f668> >>> f() 25
每次调用都会返回一个新的函数,即使传入相同的参数:
>>> f1 = lazy_sum(1, 3, 5, 7, 9) >>> f2 = lazy_sum(1, 3, 5, 7, 9) >>> f1==f2 False
>>> map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]) [1, 4, 9, 16, 25, 36, 49, 64, 81]
关键字lambda
表示匿名函数,冒号前面的x
表示函数参数
>>> f = lambda x: x * x >>> f <function <lambda> at 0x10453d7d0> >>> f(5) 25
def build(x, y): return lambda: x * x + y * y
必选参数:必须传入的参数,如:def func(a,b)
默认参数:不必传入的有默认值得参数,如:def func(a,b=None), 注意:默认参数必须指向不变对象,如 str,None。
可变参数:传入的参数个数是可变的,如:def func(*a),接受为一个tuple的不可变对象,如func(1,2,3) 在内部就是一个tuple的(1,2,3)
关键字参数:键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。如 def func(**kv) , 接受一个为一个dict对象, 如 func(city='BeiJing') 接收为:{'city':'BeiJing'}
装饰器:增强函数的功能,但又不希望修改now()
函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
def log(func): def wrapper(*args, **kw): print 'call %s():' % func.__name__ return func(*args, **kw) return wrapper
借助Python的@语法,把decorator置于函数的定义处:
>>> @log ... def now(): ... print '2015-10-27' ... >>> now() call now(): 2015-10-27
如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:
>>> 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') ... def now(): ... print '2013-12-25' ... >>> now() execute now: 2013-12-25
functools的wrap,它能保留原有函数的名称和docstring:
#不带参数
import functools def log(func): @functools.wraps(func) def wrapper(*args, **kw): print 'call %s():' % func.__name__ return func(*args, **kw) return wrapper
#带参数
import functools def log(text): def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): print '%s %s():' % (text, func.__name__) return func(*args, **kw) return wrapper return decorator
请编写一个decorator,能在函数调用的前后打印出'begin call'
和'end call'
的日志。
再思考一下能否写出一个@log
的decorator,使它既支持:
import functools def log(*a): def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): print 'begin call' if a is not None: print 'log parameter: ',a res = func(*args,**kw) print 'end call' return res #这里返回的值为None,因为执行的函数什么也没有返回. return wrapper return decorator @log() def decorator_test(): print 'this is a decorator test function' if __name__ == '__main__': decorator_test()
偏函数:functools.partial
,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单:
将int()中的base参数固定住:
>>> int('12345', base=8) 5349 >>> int('12345', 16) 74565 >>> int('12345') 12345 >>> int('12345',10) 12345
>>> import functools >>> int2 = functools.partial(int,base=2) >>> int2('10010') 18