一、 Python进阶学习
![1561517114609.png](https://img.haomeiwen.com/i18575213/055b0d93ec1ac882.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)一、函数式编程
1.1函数式编程
1561517114609.png 1561517172562.png ![1561517281088.png](https://img.haomeiwen.com/i18575213/acd06f8057bd7dfc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)1.2高阶函数
1.2.1
![1561517550621.png](https://img.haomeiwen.com/i18575213/08d529dcc74f60b7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)import math
def add(x, y, f):
return f(x) + f(y)
print add(25, 9, math.sqrt)
1.2.2python中map()函数
map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回。
def f(x):
return x*x
print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
输出结果:
[1, 4, 9, 10, 25, 36, 49, 64, 81]
注意:map()函数不改变原有的 list,而是返回一个新的 list。
1561518419092.png
利用map()函数,可以把一个 list 转换为另一个 list,只需要传入转换函数。
1.2.3python中reduce()函数
reduce()函数也是一个高阶函数,接收的参数一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。
(1)编写一个f函数,接收x和y,返回x和y的和:
def f(x, y):
return x + y
调用 reduce(f, [1, 3, 5, 7, 9])时,reduce函数将做如下计算:
先计算头两个元素:f(1, 3),结果为4;
再把结果和第3个元素计算:f(4, 5),结果为9;
再把结果和第4个元素计算:f(9, 7),结果为16;
再把结果和第5个元素计算:f(16, 9),结果为25;
由于没有更多的元素了,计算结束,返回结果25。
上述计算实际上是对 list 的所有元素求和。
虽然Python内置了求和函数sum(),但是,利用reduce()求和也很简单。
reduce()还可以接收第3个可选参数,作为计算的初始值。如果把初始值设为100,计算:
reduce(f, [1, 3, 5, 7, 9], 100)
结果是125
(2)编写一个f函数,接收x和y,返回x和y的积:
def prod(x, y):
return x * y
print reduce(prod, [2, 4, 5, 7, 12])
1.2.4python中filter()函数
filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
eg:请利用filter()过滤出1~100中平方根是整数的数,即结果应该是:
import math
def is_sqr(x):
if math.sqrt(x)%1==0 :
return x
print filter(is_sqr, range(1, 101))
注意:s.strip(rm) 删除 s 字符串中开头、结尾处的 rm 序列的字符
当rm为空时,默认删除空白符(包括'\n', '\r', '\t', ' '),如下:
a='\t\t123\r\n'
a.strip()
结果:'123'
1.2.5python中自定义排序函数
Python内置的 sorted()函数可对list进行排序:
sorted([36, 5, 12, 9, 21])
[5, 9, 12, 21, 36]
但 sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。
要实现倒序排序,只需要编写一个reversed_cmp函数:
def reversed_cmp(x, y):
if x > y:
return -1
if x < y:
return 1
return 0
这样,调用 sorted() 并传入 reversed_cmp 就可以实现倒序排序:参数先写list,再写f函数!!!!!
sorted([36, 5, 12, 9, 21], reversed_cmp)
[36, 21, 12, 9, 5]
sorted()也可以对字符串进行排序,字符串默认按照ASCII大小来比较:
sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']
'Zoo'排在'about'之前是因为'Z'的ASCII码比'a'小。
任务
对字符串排序时,有时候忽略大小写排序更符合习惯。请利用sorted()高阶函数,实现忽略大小写排序的算法。
输入:['bob', 'about', 'Zoo', 'Credit']
输出:['about', 'bob', 'Credit', 'Zoo']
1.2.6返回函数
请注意区分返回函数和返回值:
def myabs():
return abs # 返回函数
def myabs2(x):
return abs(x) # 返回函数调用的结果,返回值是一个数值
eg:
def calc_sum(lst):
def lazy_sum():
return sum(lst)
return lazy_sum
调用calc_sum()并没有计算出结果,而是返回函数:
f = calc_sum([1, 2, 3, 4])
f
eg:请利用filter()过滤出1~100中平方根是整数的数,即结果应该是:
>import math
def is_sqr(x):
if math.sqrt(x)%1==0 :
return x
print filter(is_sqr, range(1, 101))
>>注意:s.strip(rm) 删除 s 字符串中开头、结尾处的 rm 序列的字符
>当rm为空时,默认删除空白符(包括'\n', '\r', '\t', ' '),如下:
a='\t\t123\r\n'
a.strip()
结果:'123'
###1.2.5python中自定义排序函数
Python内置的 sorted()函数可对list进行排序:
>sorted([36, 5, 12, 9, 21])
[5, 9, 12, 21, 36]
但 sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。
要实现倒序排序,只需要编写一个reversed_cmp函数:
>def reversed_cmp(x, y):
if x > y:
return -1
if x < y:
return 1
return 0
这样,调用 sorted() 并传入 reversed_cmp 就可以实现倒序排序:
>>参数先写list,再写f函数!!!!!
>> sorted([36, 5, 12, 9, 21], reversed_cmp)
[36, 21, 12, 9, 5]
sorted()也可以对字符串进行排序,字符串默认按照ASCII大小来比较:
>> sorted(['bob', 'about', 'Zoo', 'Credit'])
['Credit', 'Zoo', 'about', 'bob']
'Zoo'排在'about'之前是因为'Z'的ASCII码比'a'小。
任务
对字符串排序时,有时候忽略大小写排序更符合习惯。请利用sorted()高阶函数,实现忽略大小写排序的算法。
输入:['bob', 'about', 'Zoo', 'Credit']
输出:['about', 'bob', 'Credit', 'Zoo']
###1.2.6返回函数
请注意区分返回函数和返回值:
>def myabs():
return abs # 返回函数
def myabs2(x):
return abs(x) # 返回函数调用的结果,返回值是一个数值
>>eg:
>def calc_sum(lst):
def lazy_sum():
return sum(lst)
return lazy_sum
调用calc_sum()并没有计算出结果,而是返回函数:
>> f = calc_sum([1, 2, 3, 4])
>> f
<function lazy_sum at 0x1037bfaa0>
对返回的函数进行调用时,才计算出结果:
f()
10
1.2.7闭包(Closure)
1、定义
内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。
2、特点
返回的函数还引用了外层函数的局部变量,要确保引用的局部变量在函数返回后不能变。举例如下:
希望一次返回3个函数,分别计算1x1,2x2,3x3:
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果全部都是 9
原因就是当count()函数返回了3个函数时,这3个函数所引用的变量 i 的值已经变成了3。由于f1、f2、f3并没有被调用,所以,此时他们并未计算 i*i,当 f1 被调用时:
f1()
9
因为f1现在才计算i*i,但现在i的值已经变为3
因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量。
修改后:
def count():
fs = []
for i in range(1, 4):
def f(j):
def g():
return j*j
return g
fi=f(i)
fs.append(fi)
return fs
f1, f2, f3 = count()
print f1(), f2(), f3()
1.2.8匿名函数lambda
关键字lambda 表示匿名函数,冒号前面的 x 表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不写return,返回值就是该表达式的结果。
使用匿名函数,可以不必定义函数名,直接创建一个函数对象:
sorted([1, 3, 9, 5, 0], lambda x,y : -cmp(x,y))
[9, 5, 3, 1, 0]
返回函数的时候,也可以返回匿名函数:
myabs = lambda x : -x if x < 0 else x
myabs(-1)
1
1.2.9decorator装饰器
1、装饰器定义
Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。
不用装饰器:
1561535968062.png
使用装饰器:
1561536060596.png ![1561536294538.png](https://img.haomeiwen.com/i18575213/9b1a6698cf579312.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2、编写无参数的decorator
要让 @log 自适应任何参数定义的函数,可以利用Python的 *args 和 **kw,保证任意个数的参数总是能正常调用:
def log(f):
def fn(*args, *kw):
print 'call ' + f.name + '()...'
return f(args, **kw)
return fn
eg:请编写一个@performance,它可以打印出函数调用的时间。
计算函数调用的时间可以记录调用前后的当前时间戳,然后计算两个时间戳的差。
import time
def performance(f):
def fn(*args, *kw):
t1 = time.time()
r = f(args, *kw)
t2 = time.time()
print 'call %s() in %fs' % (f.name, (t2 - t1))
return r
return fn
performance
def factorial(n):
return reduce(lambda x,y: xy, range(1, n+1))
print factorial(10)
3、带参数的decorator
如果有的函数非常重要,希望打印出'[INFO] call xxx()...',有的函数不太重要,希望打印出'[DEBUG] call xxx()...',这时,log函数本身就需要传入'INFO'或'DEBUG'这样的参数,类似这样:
@log('DEBUG')
def my_func():
pass
把上面的定义翻译成高阶函数的调用,就是:
my_func = log('DEBUG')(my_func)
上面的语句看上去还是比较绕,再展开一下:
log_decorator = log('DEBUG')
my_func = log_decorator(my_func)
eg:@performance只能打印秒,请给 @performace 增加一个参数,允许传入's'或'ms':
1561539338978.png
三层嵌套:最外层要先返回一个decorator,第二层返回wrapper,第三层返回原来的函数f
1.2.10完善的decorator
decorator“改造”后的函数,和原函数相比,除了功能多一点外,有没有其它不同的地方?
(1)在没有decorator的情况下,打印函数名:
def f1(x):
pass
print f1.name
输出: f1
(2)有decorator的情况下,再打印函数名:
def log(f):
def wrapper(*args, *kw):
print 'call...'
return f(args, **kw)
return wrapper
@log
def f2(x):
pass
print f2.name
输出: wrapper
解决方案:
Python内置的functools可以用来自动化完成这个“复制”的任务:
import functools
1561600539881.png
def log(f):
@functools.wraps(f)
def wrapper(*args, *kw):
print 'call...'
return f(args, **kw)
return wrapper
二、模块
模块名冲突:
引用模块:
![1561600680685.png](https://img.haomeiwen.com/i18575213/d98ca2ccec31aed9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
包可以有多层:
但每一层必须 包含一个文件__init.py
2.2导入模块
若干种方式:(eg :os.path)
import os
import os.path
from os import path
from os.path import isdir, isfile
[图片上传失败...(image-bf3006-1562071047270)]
2、动态导入模块
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
try 的作用是捕获错误,并在捕获到指定错误时执行 except 语句。
导入新版本的新特性:
当新版本的一个特性与旧版本不兼容时,该特性将会在旧版本中添加到future中,以便旧的代码能在旧版本中测试新特性。
from future import unicode_literals
s = 'am I an unicode?'
print isinstance(s, unicode)
3、导入第三方模块
python内置了许多模块,但仍有外部模块,可以导入使用
eg:pip
三、面向对象
1561603249167.png1561603309443.png
3.1实例化属性:
请定义Person类的init方法,除了接受 name、gender 和 birth 外,还可接受任意关键字参数,并把他们都作为属性赋值给实例。
要定义关键字参数,使用 **kw;
除了可以直接使用self.name = 'xxx'设置一个属性外,还可以通过 setattr(self, 'name', 'xxx') 设置属性。
参考代码:
class Person(object):
def init(self, name, gender, birth, **kw):
self.name = name
self.gender = gender
self.birth = birth
for k, v in kw.iteritems():
setattr(self, k, v)
xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student')
print xiaoming.name
print xiaoming.job
3.2属性的访问限制:
[图片上传中...(1561606531797.png-a6873d-1562070557388-0)]
(1)以双下划线开头的属性‘__xxx'不能直接被外部访问。
(2)以"xxx"的形式定义,那它又可以被外部访问了,以"xxx"定义的属性在Python的类中被称为特殊属性,有很多预定义的特殊属性可以使用,通常我们不要把普通属性用"xxx"定义。
(3)以单下划线开头的属性"_xxx"虽然也可以被外部访问,但是,按照习惯,他们不应该被外部访问。
3.3类属性
实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。
定义类属性可以直接在 class 中定义:
class Person(object):
address = 'Earth'
def init(self, name):
self.name = name
因为类属性是直接绑定在类上的,所以,访问类属性不需要创建实例,就可以直接访问:
print Person.address
=> Earth
p1 = Person('Bob')
print p1.address
=> Earth
类属性和实例属性名冲突:
当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。
千万不要在实例上修改类属性,它实际上并没有修改类属性,而是给实例绑定了一个实例属性。
定义实例方法:
虽然私有属性无法从外部访问,但是,从类的内部是可以访问的。除了可以定义实例的属性外,还可以定义实例的方法。
实例的方法就是在类中定义的函数它的第一个参数永远是 self,指向调用该方法的实例本身,其他参数和一个普通函数是完全一样的.
定义类方法:
方法也分实例方法和类方法。
在class中定义的全部是实例方法,实例方法第一个参数 self 是实例本身。
在class中定义类方法:
class Person(object):
count = 0
@classmethod
def how_many(cls):
return cls.count
def init(self, name):
self.name = name
Person.count = Person.count + 1
print Person.how_many()
p1 = Person('Bob')
print Person.how_many()
通过标记一个 @classmethod,该方法将绑定到 Person 类上,而非类的实例。类方法的第一个参数将传入类本身,通常将参数名命名为 cls,上面的 cls.count 实际上相当于 Person.count。
可以通过一个类方法获取类的私有属性。
四、继承
4.1继承
1561620022645.png 1561620429253.png判断数据类型:
函数isinstance()可以判断一个变量的类型,既可以用在Python内置的数据类型如str、list、dict,也可以判断类的对象的类型
isinstance(p, Person)
True
isinstance(p, Student)
False
PS:以上是2019-06-26到2019-06-07学习廖雪峰老师python进阶课程记录~
网友评论