2015.8.5
慕课网Python进阶学习:
函数式编程(functional):
1.python不是纯函数式编程:允许存在变量
2.支持高阶函数:函数可作为变量传入
3.支持闭包:有了闭包就能返回函数
4.有限度的支持匿名函数
高阶函数:能接收函数作为参数的函数。
def add(x,y,f):
return f(x)+f(y)
print add(4,5,abs)
其中abs是个求值函数
map()函数:它接收一个函数f和一个list,通过函数f依次作用在list的每个元素上
def format_name(s):
a=s[:1].upper()+s[1:].lower()
return a
print map(format_name,['adam','LISA','barT'])
reduce()函数:它接收一个函数f和一个list,它传入的函数f必须接收两个参数,对list反复调用f并返回最总结果值。也可接收第三个参数为它的初始值。
def prod(x, y):
return x*y
print reduce(prod,[2,4,5,7,12])
print reduce(prod,[2,4,5,7,12],100)
第一个输出的运算形式:prod(2,4)=8 ;=>prod(8,5)=40;=>.......依次相乘
第二个输出的运算形式:prod(100,2)=200 ;=>prod(200,4)=800;=>.......依次相乘
filter()函数:它接收一个函数f和一个list,f对每个元素进行判断,返回true或false,filter()通过判断结果自动过滤不符合条件的元素,返回由符合条件元素组成的新的list
import math
def is_sqr(x):
r=int(math.sqrt(x))
return r*r==x
print filter(is_sqr, range(1,100))
math.sqrt(x)求x的平方根,返回结果是浮点数,int()将其转为int类型
sorted()自定义排序函数:接收一个比较函数f和一个list,f接收两个待比较的元素x,y,如果x应该排在y的前面,返回-1,如果x应该排在y的后面返回1,如果x,y相等,返回0
def cmp_ignore_case(s1, s2):
u1=s1.upper()
u2=s2.upper()
if u1<u2:
return-1
if u1==u2:
return0
if u1>u2:
return1
print sorted(['bob','about','Zoo','Credit'],cmp_ignore_case)
从小到大排列,忽略大小写
返回函数:
def calc_prod(lst):
def g():
def d(x,y):
return x * y
return reduce(d,lst,1)
return g
f = calc_prod([1,2,3,4])
print f()
闭包:内层函数应用了外层函数的变量,然后返回内层函数的情况称为闭包。注意:返回函数不要引用任何循环变量或者后续会发生编发的变量
def count():
fs =[]
for i in range(1,4):
def f(x):
def g():
return x*x;
return g
r=f(i)
fs.append(r)
return fs
f1, f2, f3 = count()
print f1(), f2(), f3()
匿名函数:lambda 只能有一个表达式,不写return,返回值就是该表达式的结果
print filter(lambda s:s and len(s.strip())>0,['test',None,'','str',' ','END'])
s为匿名函数参数
2015.8.6
装饰器(decorator):
极大的简化代码,避免每个函数编写重复性代码
使用@在调用装饰器函数的函数之前
不带参数装饰器
打印日志:@log
def log(f):
def fn(x):
print'call '+ f.__name__ +'()...'
return f(x)
return fn
@log
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
#此处代码如下
factorial=log(
对于参数不是一个的,调用将报错,@log写死了只含有一个参数的返回值,要让@log自适应任何参数的函数可以使用*args和**kw,保证任意个参数都能正常调用
def log(f):
def fn(*args,**kw):
print'call '+ f.__name__ +'()...'
return f(*args,**kw)
return fn
@log
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
检测性能:@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: x*y, range(1, n+1))
print factorial(10)
数据库事务:@transaction
URL路由:@post('/register')
带参数的装饰器
def log(str):
def log_decorator(f):
def fn(*args,**kw):
print'call [%s] %s()...'%(str,f.__name__)
return f(*args,**kw)
return fn
return log_decorator
@log('debug')
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
#factorial=log(factorial)
print factorial(10)
import time
def performance(unit):
def pp(f):
def ff(*a,**k):
t1=time.time()
r=f(*a,**k)
t2=time.time()
print'call %s() in %f%s'%(f.__name__,t2-t1,unit)
return r
return ff
return pp
@performance('ms')
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
由于decorator会改造函数,便会改变函数的__name__,__doc__等其他属性,所以就需要将原函数属性复制到新函数中使用functools自动化完成这个复制任务
import functools
def log(f):
#@functools.wraps(f)
def wrapper(*args,**kw):
print'call...'
return f(*args,**kw)
return wrapper
@log
def ff():
return1
print ff.__name__
此时输出wrapper 若加上@functools.wraps(f) 输出ff
import time, functools
def performance(unit):
def pp(f):
@functools.wraps(f)
def ff(*rags,**k):
t1=time.time()
r=f(*rags,**k)
t2=time.time()
print'call %s in %f%s'%(f.__name__,t2-t1,unit)
return r
return ff
return pp
@performance('ms')
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
print factorial.__name__
偏函数:
functools.partial可以将一个参数多的函数变为一个参数少的函数,少的函数需要在创建是指定默认值
import functools
sorted_ignore_case = functools.partial(sorted,cmp=lambda s1,s2:cmp(s1.upper(),s2.upper()))
print sorted_ignore_case(['bob','about','Zoo','Credit'])
cmp(x,y)函数为对比函数 x>y返回1 x=y返回0 x<y 返回-1
模块和包:
包便是文件夹,.py文件便是模块,包中必须要有__init__.py文件,包的每层目录中都需要有
用import引用其他模块的函数等
将同名模块放入不同的包中
#test.py
import p1.unit
print p1.unit.f(2,1)
os.path模块提供了is.dir()和isfile()函数,判断指定目录和文件是否存在
import os.path
print os.path.isdir(r'/data/webroot/resource/python')
print os.path.isfile(r'/data/webroot/resource/python/test.txt')
动态导入模块(动态引入需要在直接引入之前):
同样实现stringIO的功能,但是CStringIO模块部分是用c写的,所以CStringIO要比StringIO运行要快。
try:
from cStringIO importStringIO
exceptImportError:
fromStringIOimportStringIO
try:
import json
exceptImportError:
import simplejson as json
print json.dumps({'python':2.7})
使用import...as...动态导入不同名称的模块
使用__future__
python新版本会引入新的功能,但是,实际上这些功能再上一个老版本中已经存在,要试用某些新特性,就可以通过导入__future__模块的某些功能来实现。
from __future__ import division#若不引入,print 10/3输出3,引入输出3.3333333
import p1.hello
print10/3
print p1.hello.factorial(10)
from __future__ import unicode_literals
s = b'am I an unicode?'
print isinstance(s, unicode)
在现在的版本中,字符串同意为unicode不需要加u前缀,而str 必须加b前缀
安装第三方模块
工具:easy_install pip(官方推荐,内置到python2.7.9)
确保python版本为python2.7.9以上版本,在命令提示符下使用pip install web.py(web.py为第三方模块)
面向对象编程
classPerson(object):
pass
类名首字母大写,object为该类继承的类
classPerson(object):
def __init__(self,name):#构造函数
self.name=name
xiaoming =Person('xiaoming')
xiaohong =Person('xiaohong')
print xiaoming.name
print xiaohong.name
print xiaoming.name==xiaohong.name
classPerson(object):
pass
p1 =Person()
p1.name ='Bart'
p2 =Person()
p2.name ='Adam'
p3 =Person()
p3.name ='Lisa'
L1 =[p1, p2, p3]
L2 = sorted(L1,lambda p1,p2:cmp(p1.name,p2.name))
print L2[0].name
print L2[1].name
print L2[2].name
python关键字参数和可变参数
python关键字参数用**kw表示,在调用时可以默认赋值且可以为任意个的参数
可变参数用*args表示,在调用时可以是任意个的参数
def foo1(arg1,arg2,*arg,**keywords):
print"arg1 parameters is ",arg1
print"arg2 parameters is ",arg2
print"Arbitrary parameter is ", arg
print"keywords parameter is ",keywords
foo1(1,2,3,4,5,6,k1=1,k2=2,k3=3)
构造函数初始化,参数是可以为关键字参数或可变参数
classPerson(object):
def __init__(self,name,sex,bor,*args,**kw):
self.name=name
self.sex=sex
self.bor=bor
for k,v in kw.iteritems():
setattr(self,k,v)
for c in args:
setattr(self,c)
xiaoming =Person('Xiao Ming','Male','1990-1-1', job='Student',job2='sty')
print xiaoming.name
print xiaoming.job
print xiaoming.job2
访问限制:
设置某属性为外部无法访问用双下划线开头 __
classPerson(object):
def __init__(self, name, score):
self.name=name
self.__score=score
p =Person('Bob',59)
print p.name
print p.__score
创建类属性(不同于实例属性)
classPerson(object):
count=0
def __init__(self,name):
Person.count=Person.count+1
self.name=name
p1 =Person('Bob')
printPerson.count
p2 =Person('Alice')
printPerson.count
p3 =Person('Tim')
printPerson.count
当实例属性和类属性重名时,实例属性优先级高,实例中是不能修改类属性的
classPerson(object):
__count =0
count=0
def __init__(self, name):
Person.__count=Person.__count+1
self.name=name
p1 =Person('Bob')
p2 =Person('Alice')
printPerson.__count
printPerson.count
定义实例函数
#-*- coding:utf-8 -*-
classPerson(object):
def __init__(self, name, score):
self.__score=score
self.name=name
def get_grade(self):
if self.__score>=80:
return'优秀'
if self.__score>=60:
return'及格'
if self.__score<60:
return'不及格'
p1 =Person('Bob',90)
p2 =Person('Alice',65)
p3 =Person('Tim',48)
print p1.get_grade()
print p2.get_grade()
print p3.get_grade()
最上面那句是为了使其支持中文编码
方法也可以看出是属性,可以将方法动态的添加到实例上,只是需要使用types.MethodType()将一个函数变为一个方法
import types
def fn_get_grade(self):
if self.score >=80:
return'A'
if self.score >=60:
return'B'
return'C'
classPerson(object):
def __init__(self, name, score):
self.name = name
self.score = score
p1 =Person('Bob',90)
p1.get_grade = types.MethodType(fn_get_grade, p1,Person)
print p1.get_grade()
# => A
p2 =Person('Alice',65)
print p2.get_grade()
# ERROR: AttributeError: 'Person' object has no attribute 'get_grade'
# 因为p2实例并没有绑定get_grade
classPerson(object):
def __init__(self, name, score):
self.name = name
self.score = score
self.get_grade =lambda:'A'
p1 =Person('Bob',90)
print p1.get_grade
print p1.get_grade()
定义类方法,和属性相似,方法也分实例方法和类方法
classPerson(object):
count=0
@classmethod
def howMany(cls):
return cls.count
def __init__(self,name):
self.name=name
Person.count=Person.count+1
printPerson.howMany()
p1=Person('xiaoming')
printPerson.howMany()
classPerson(object):
__count =0
def __init__(self,name):
Person.__count=Person.__count+1
self.name=name
@classmethod
def how_many(cls):
return cls.__count
printPerson.how_many()
p1 =Person('Bob')
printPerson.how_many()
继承
classPerson(object):
count=0
@classmethod
def howMany(cls):
return cls.count
def __init__(self,name,gender):
self.name=name
Person.count=Person.count+1
classStudent(Person):
def __init__(self,name,gender,school,score):
super(Student,self).__init__(name,gender)
self.school=school
self.score=score
printPerson.howMany()
p1=Person('xiaoming','m')
s1=Student('n','s','d',11)
print s1.name
printPerson.howMany()
isinstance(s,type)函数,检测s是否是type类型,可用于判断属性是否是int、str等类型
classPerson(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
classStudent(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
classTeacher(Person):
def __init__(self, name, gender, course):
super(Teacher, self).__init__(name, gender)
self.course = course
t =Teacher('Alice','Female','English')
print isinstance(t,Person)
print isinstance(t,Student)
print isinstance(t,Teacher)
print isinstance(t,object)
多态
classPerson(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def whoAmI(self):
return'I am a Person, my name is %s'% self.name
classStudent(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
def whoAmI(self):
return'I am a Student, my name is %s'% self.name
classTeacher(Person):
def __init__(self, name, gender, course):
super(Teacher, self).__init__(name, gender)
self.course = course
def whoAmI(self):
return'I am a Teacher, my name is %s'% self.name
def who_am_i(x):
print x.whoAmI()
p =Person('Tim','Male')
s =Student('Bob','Male',88)
t =Teacher('Alice','Female','English')
who_am_i(p)
who_am_i(s)
who_am_i(t)
其中调用whoAmI函数时,先找该对象的方法,没有再向其父类找
python提供了open()方法来打开一个磁盘文件,并返回File对象,File对象有一个read()方法可以读取文件内容
任何含有read()方法的函数都可以称为 File-like-object 都可以直接将其对象传给json.load()
import json
classStudents(object):
def read(self):
return r'["Tim", "Bob", "Alice"]'
s =Students()
print json.load(s)
多重继承 从多个父类继承,称为多重继承
在多重继承中,父类的父类的__init__方法只会被调用一次
Python的网络服务器有TCPServer、UDPServer、UnixStreamServer、UnixDatagramServer
服务器运行模式有多进程ForkingMixin和多线程ThreadingMixin
classPerson(object):
pass
classStudent(Person):
pass
classTeacher(Person):
pass
classSkillMixin(object):
pass
classBasketballMixin(SkillMixin):
def skill(self):
return'basketball'
classFootballMixin(SkillMixin):
def skill(self):
return'football'
classBStudent(BasketballMixin,Student):
pass
classFTeacher(FootballMixin,Teacher):
pass
s =BStudent()
print s.skill()
t =FTeacher()
print t.skill()
获取对象信息
type(x)获取对象x的类型 dir(x)获取对象x的所有属性信息。
若知道一个属性名称,要获取或设置对象的属性,就需要用到getattr()和serattr()
#-*- coding:utf-8 -*-
classPerson(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
classStudent(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
def whoAmI(self):
return'I am a Student, my name is %s'% self.name
s =Student('Bob','Male',88)
print type(s)
print getattr(s,'name')
print getattr(s,'age',20)#不存在age值则返回默认值20
setattr(s,'name','Adam')
print dir(s)
2015.8.7
特殊方法(魔术方法)
特殊方法定义的class中,不需要直接调用,Python的某些函数或操作符会调用对应的特殊方法
#-*- coding:utf-8 -*-
classPerson(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
s =Person('Bob','Male')
print s
print s.__str__()#输出结果同上__str__()便是一个特殊方法,用于显示给用户
print s.__rpr__()#用于显示给开发人员
特殊方法也可以重写
classPerson(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
classStudent(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
def __str__(self):
return'Student: %s,%s,%s'%(self.name,self.gender,self.score)
__repr__=__str__
s =Student('Bob','male',88)
print s
__cmp__()方法
对于int,str等内置数据类型排序是,python的sorted()安装默认额比较函数cmp排序,但是对一组Student类的实例排序是就必须提供我们自己的特殊方法__cmp__()
classStudent(object):
def __init__(self, name, score):
self.name = name
self.score = score
def __str__(self):
return'(%s: %s)'%(self.name, self.score)
__repr__ = __str__
def __cmp__(self, s):
if self.score<s.score:
return-1
elif self.score==s.score:
return0
else:
return1
L =[Student('Tim',99),Student('Bob',88),Student('Alice',99)]
print sorted(L)
__len__()方法
如果类的实例想要使用len()方法必须实现__len__()方法
classFib(object):
def __init__(self, num):
a,b,L=0,1,[]
for n in range(num):
L.append(a)
a,b=b,a+b
self.numbers=L
def __str__(self):
return str(self.numbers)
__repr__=__str__
def __len__(self):
return len(self.numbers)
f =Fib(10)
print f
print len(f)
数学运算
有理数:有理数是一个整数a和一个非零整数b的比,例如3/8
def gcd(a,b):#处理有理数归约
if b==0:
return a
return gcd(b,a%b)
classRational(object):
def __init__(self, p, q):
self.p = p
self.q = q
def __add__(self, r):
returnRational(self.p * r.q + self.q * r.p, self.q * r.q)
def __sub__(self, r):
returnRational(self.p*r.q-self.q*r.p,self.q*r.q)
def __mul__(self, r):
returnRational(self.p*r.p,self.q*r.q)
def __div__(self, r):
returnRational(self.p*r.q,self.q*r.p)
def __str__(self):
g=gcd(self.p,self.q)
return'%s/%s'%(self.p/g,self.q/g)##########
__repr__ = __str__
r1 =Rational(1,2)
r2 =Rational(1,4)
print r1 + r2
print r1 - r2
print r1 * r2
print r1 / r2
类型转换
classRational(object):
def __init__(self, p, q):
self.p = p
self.q = q
def __int__(self):
return self.p // self.q
def __float__(self):
return float(self.p)/self.q
print float(Rational(7,2))
print float(Rational(1,3))
@property装饰器
classStudent(object):
def __init__(self, name, score):
self.name = name
self.__score = score
@property #如get方法
def score(self):
return self.__score
@score.setter #如set方法
def score(self, score):
if score <0or score >100:
raiseValueError('invalid score')
self.__score = score
@property
def grade(self):
if self.score<60:
return'C'
if self.score<80:
return'B'
return'A'
s =Student('Bob',59)
print s.grade
s.score =60
print s.grade
s.score =99
print s.grade
__slots__方法控制类属性如下
classStudent(object):
__slots__ =('name','gender','score')
def __init__(self, name, gender, score):
self.name = name
self.gender = gender
self.score = score
s =Student('Bob','male',59)
s.name ='Tim'# OK
s.score =99# OK
s.grade ='A'
在__slots__中只定义了三个属性,所以会导致s.grade不能正常运行,只有在__slots__中定义了的属性才能够运行
classPerson(object):
__slots__ =('name','gender')
def __init__(self, name, gender):
self.name = name
self.gender = gender
classStudent(Person):
__slots__ =('score',)#当只有一个属性是,之后需要加个,
def __init__(self,name,gender,score):
super(Student,self).__init__(name,gender)
self.name=name
self.gender=gender
self.score=score
s =Student('Bob','male',59)
s.name ='Tim'
s.score =99
print s.score
__call__ 将一个实例编程一个可调用对象,即时将一个实例变为一个可调用函数
classPerson(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def __call__(self, friend):
print'My name is %s...'% self.name
print'My friend is %s...'% friend
p=Person('bob','man')
p('tim')
classFib(object):
def __call__(self,num):
a,b,L=0,1,[]
for n in range(num):
L.append(a)
a,b=b,a+b
return L
f =Fib()
print f(10)