1.Python支持的函数式编程
A.不是纯函数式编程:允许有变量(纯函数式编程:不需要变量,没有副作用,测试简单
B.支持高阶函数:函数可以作为变量传入
C.支持闭包:有了闭包就能返回函数
D.有限度地支持匿名函数
2.高阶函数
能接收函数做参数的函数
变量可以指向函数
函数的参数可以接受变量
一个函数可以接收另一个函数作为参数
能接收函数作参数的函数就是高阶函数
A.map()是python内置的高阶函数,它接收一个函数f和一个list,并通过把函数f依次作用在list的每个元素上,得到一个新的list并返回
B.reduce()函数也是python内置的一个高阶函数,reduce()函数接收的参数和map()类似,一个函数f,一个list,但行为和map()不同,reduce()传入的函数f必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值,reduce()还可以接收第三个可选参数,作为计算的初始值.
C.filter()函数式python内置的另一个有用的高阶函数,filter()函数接收一个函数f和一个list,这个函数f的作用是对每个元素进行判断,返回True或者False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新的list
请利用filter()过滤出1~100中平方根是整数的数,即结果应该是:
import math
def is_sqr(x):
return math.sqrt(x)%1 == 0
print filter(is_sqr, range(1, 101))
D.sorted()函数可对list进行排序,同样也是一个高阶函数,它可以接收一个比较函数来实现自定义排序
对内容进行忽略大小写排序
def campstr(s1,s2):
return cmp(s1.lower(),s2.lower())
print sorted(['bob', 'about', 'Zoo', 'Credit'],campstr)
3.闭包
Python的函数不但可以返回int,str,list,dict等数据类型,还可以返回函数
Python中闭包,在函数内部定义的函数和外部定义的函数式一样的,只是无法被外部访问,如果有被定义在外函数内部的情况,并且内层函数引用了外层函数的参数,然后返回内层函数的情况,我们称为闭包.
闭包的特点是返回的函数还引用了外层函数的局部变量,所以要正确地使用闭包,就要确保引用的局部变量在函数返回后不能变.
Python中的匿名函数,高阶函数可以接收函数做参数,有些时候,我们不需要显式地定义函数,直接传入匿名函数更方便,在python中,对匿名函数提供了有限支持,关键字lambda表示宁明函数,冒号前面的x表示函数参数 eg: lambda x:x*x 匿名函数有一个限制,就是只能有一个表达式,不写return,返回值就是该表达式的结果
4.装饰器
Python内置的@语法就是为了简化装饰器调用
@new_fn
def f1(x):
Return x*2
def f1(x):
return x*2
f1 = new_fn(f1)
作用:
可以极大地简化代码,避免每个函数编写重复性代码
打印日志:@log
检测性能:@performance
数据库事务:@transaction
URL路由:@post(‘/register’)
请编写一个@performance,它可以打印出函数调用的时间。
import time
def performance(f):
def fn(x):
time1 = time.time()
val = f(x)
print "run time = ",time.time() - time1
return val
return fn
@performance
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
5.偏函数
当一个函数有很多参数的时候,调用者就需要提供多个参数,如果减少参数个数,就可以简化调用者的负担
我们在sorted这个高阶函数中传入自定义排序函数就可以实现忽略大小写排序。请用functools.partial把这个复杂调用变成一个简单的函数:sorted_ignore_case(iterable)
def campstr(s1,s2):
return cmp(s1.lower(),s2.lower())
sorted_ignore_case = functools.partial(sorted,cmp= campstr)
print sorted_ignore_case(['bob', 'about', 'Zoo', 'Credit'])
6.模块和包的概念
当代码越来越多的时候如果将所有的代码放入一个py文件:无法维护
如果将代码分拆放入多个py文件中,好处:
同一个名字的变量互不影响
引用其他的模块
#test.py ---> 自身模块名
Import math --->引用math模块
当模块多了以后,也容易重名,解决模块名冲突,只要将模块放入到不同的包中就可以解决
引用完整的模块名:
Import p1.util
使用:
P1.util.demo()
包就是文件夹,模块名就是.py
如何区分包和普通目录:
包下面有个_init_.py这样python才会当做包来处理
动态导入模块
如果导入的模块不存在,python解释器会报ImportError错误
EG:
利用import ... as ...,还可以动态导入不同名称的模块。
Python 2.6/2.7提供了json 模块,但Python 2.5以及更早版本没有json模块,不过可以安装一个simplejson模块,这两个模块提供的函数签名和功能都一模一样。
试写出导入json 模块的代码,能在Python 2.5/2.6/2.7都正常运行。
try:
import json
except ImportError:
import simplejson as json
print json.dumps({'python':2.7})
使用__future__
Python的新版本会引入新的功能,但是,实际上这些功能在上一个老版本中就已经存在了,要试用某一新的特性,就可以通过导入__future__模块的某些功能来实现
例如:
from __future__ import division
print 10 / 3 #3.3333333333333335
print 10//3 #3
安装第三方模块
a.easy_install
b.pip(推荐,已内置到Python2.7.9)
例如安装web.py第三方模块
pip install web.py
7.Python面向对象编程
面向对象编程是一种程序设计范式
把程序看做不同对象的相互调用
对现实世界建立对象模型
基本思想
类用于定义抽象类型
实例根据类的定义被创建出来
最重要的思想:数据封装
由于Python是动态语言,对每一个实例,都可以直接给他们的属性赋值
可以给一个实例绑定很多属性,如果不希望被外部访问到,可以用__双下划线开头,该属性就无法被外部访问.但是如果一个属性以 __xxx__的形式定义,则又可以被外部访问了,以__xxx__定义的属性在python的类中被称为特殊属性,有很多预定义的特殊属性可以使用,通常不把普通属性用__xxx__定义
8.类属性
绑定在实例上的属性不会影响其他实例,但是,类本身也是一个对象,如果在类上绑定一个属性,则所有实例都可以访问类的属性,并且,所有实例访问的类属性都是同一个,也就是说,实例属性每个实例各自拥有,互相独立,而类属性有且只有一份(类似于java的static)
定义类属性可以直接在class中定义
class Demo(object):
data1 = 12
Print Demo.data1
因为类属性是直接绑定在类上的,所以访问类属性不需要创建实例.
对一个实例调用类的属性也是可以访问的,所有实例都可以访问到它所属的类的属性
由于Python是动态语言,类属性也是可以动态添加和修改的...
当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。不要在实例上修改类属性,它实际上并没有修改类属性,而是给实例绑定了一个实例属性
9.实例方法
实例的方法就是在类中定义的函数,它的第一个参数永远是 self,指向调用该方法的实例本身,其他参数和一个普通函数是完全一样的:在实例方法内部,可以访问所有实例属性,这样,如果外部需要访问私有属性,可以通过方法调用获得,这种数据封装的形式除了能保护内部数据一致性外,还可以简化外部调用的难度。
在class中定义的实例方法其实也是属性,实际上是一个函数对象,因为方法也是一个属性,所以它也可以动态地添加到实例上,只是需要用type.MethodType()把一个函数变为一个方法
10.类方法
和属性类似,方法也分实例方法和类方法.在class中定义的全部是实例方法,实例方法第一个参数self是实例本身.通过标记@classmethod 该方法将绑定到类上,而非类的实例上,该方法的第一个参数将传入类本身,通常将参数名命名为cls,因为是在类上调用,而非实例上调用,因此类方法无法获取任何实例变量,只能获得类的引用
class Person(object):
count = 0
@classmethod
def how_many(cls):
return cls.count
11.类的继承
子类和父类是is关系,总是从某各类继承 如果没有合适的就从object继承,不能忘记调用super().__init__
如果已经定义了Person类,需要定义新的Student和Teacher类时,可以直接从Person类继承:
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
定义Student类时,只需要把额外的属性加上,例如score:
class Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
一定要用 super(Student, self).__init__(name, gender) 去初始化父类,否则,继承自 Person 的 Student 将没有 name 和 gender。
函数super(Student, self)将返回当前类继承的父类,即 Person ,然后调用__init__()方法,注意self参数已在super()中传入,在__init__()中将隐式传递,不需要写出(也不能写)。
12.判断类型
函数isinstance()可以判断一个变量的类型,既可以用在Python内置的数据类型如str,list,dict,也可以用在我们自定义的类,它们本质上都是数据类型
Isinstance(“ss”,str)
继承链上,一个父类的实例不能是子类类型,因为子类比父类多了一些属性和方法,一个实例可以看成它本身的类型,也可以看成它父类的类型。
13.多态
类具有继承关系,并且子类类型可以向上转型看做父类类型,因此在实例方法的继承以及复写而言和java类似,但是bug的是因为python是动态语言,因此python在调用实例方法的时候不检查类型,只要方法存在,参数正确即可以调用.意思是:只要类中有这个方法,那么类似于这样的方法定义:
def demo(x):
x.demomethod()
只要x中有demomethod这个方法就可成功的调用demo方法.
14.多重继承
除了从一个父类继承外,python允许从多个父类继承,称为多继承
class A(object):
def __init__(self):
pass
def hi(self):
print "A hi"
pass
class B(object):
def __init__(self):
pass
def hi(self):
print "B hi"
pass
class C(A,B):
def __init__(self):
pass
c = C()
c.hi()
15.获取对象信息
拿到一个变量,除了用isinstance()判断是否是某种类型的实例外,可以用type()函数获取变量的类型,返回一个Type对象,也可以用dir()函数获取变量的所有属性,getattr()获取属性值,setattr()设置属性值
16.特殊方法
用于print的__str__
用于len的__len__
用于cmp的__cmp__
特殊方法的特点
a.定义在class中
b.不需要直接调用
c.某些函数或者操作符会调用对应的特殊方法
正确实现特殊方法
A.只需要编写用到的特殊方法
B.有关联性的特殊方法都必须实现
__getattr__
__setattr__
__delattr__
C.__str__和__repr__
如果要把一个类的实例变成str,需要实现特殊方法__str__()
__repr__()用于显示给开发人员看
D.__cmp__
对int,str等内置数据类型排序时,python的sorted()按照默认比较函数cmp排序,但是,如果对一组实例排序的时候,就必须提供自己的特殊方法__cmp__,__cmp__用实例自身self和传入的实例 s 进行比较,如果 self 应该排在前面,就返回 -1,如果 s 应该排在前面,就返回1,如果两者相当,返回 0。
E.__len__
如果一个类表现的像list,要获取有多少个元素,就得用len()函数,要让len()函数工作正常,类就必须提供一个特殊方法__len__()
F.数学运算
Python提供的基本数据类型int,float可以做整数和浮点的四则运算以及乘方等运算,但是四则运算不局限于int和float,还可以是有理数,矩阵等,要表示有理数,可以用Rational类来表示
G.类型转换
对于数据的类型转换 如下:
int(12.23) ---- > 12
float(12) -----> 12.0
如果要把一个对象转换为int应该实现特殊的方法__int__()
然后调用 int(obj) 即可
Float同理类似
H.@property
class Student(object):
def __init__(self, name, score):
self.name = name
self.__score = score
@property
def score(self):
return self.__score
@score.setter
def score(self, score):
if score < 0 or score > 100:
raise ValueError('invalid score')
self.__score = score
如上 可以通过对getter方法进行@progperty注解 ,这样就会将score()衍生出score属性,在调用的时候 可以通过 s.score来get或者set
I.__slots__
如果要限制添加的属性,例如,Student类只允许添加 name、gender和score 这3个属性,就可以利用Python的一个特殊的__slots__来实现。
顾名思义,__slots__是指一个类允许的属性列表:
class Student(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'
Traceback (most recent call last):
...
AttributeError: 'Student' object has no attribute 'grade'
__slots__的目的是限制当前类所能拥有的属性,如果不需要添加任意动态的属性,使用__slots__也能节省内存。
J.__call__
一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__()。
我们把 Person 类变成一个可调用对象:
class Person(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
现在可以对 Person 实例直接调用:
>>> p = Person('Bob', 'male')
>>> p('Tim')
My name is Bob...
My friend is Tim...
单看 p('Tim') 你无法确定 p 是一个函数还是一个类实例,所以,在Python中,函数也是对象,对象和函数的区别并不显著。