1. map()函数
高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回,不改变原有列表。
def format_name(s):
return s[0].upper()+s[1:].lower()
print map(format_name, ['adam', 'LISA', 'barT'])
输出:['Adam', 'Lisa', 'Bart']
2. reduce()函数
高阶函数,接收参数一个函数 f,一个list,f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。f还可以接收第三个参数,作为初始计算值。
def prod(x, y):
return x*y
print reduce(prod, [2, 4, 5, 7, 12])
计算过程:2*4 = 8,8*4 = 32....
输出:3360
3. filter()函数
高阶函数,接收一个函数 f 和一个list,函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
import math
def is_sqr(x):
return int(math.sqrt(x))**2==x
print filter(is_sqr, range(1, 101))
输出:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
4. sorted()函数
高阶函数,对list进行排序,可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0,默认从小到大排序。
#自定义排序函数
def cmp_ignore_case(s1, s2):
if s1.upper()>s2.upper():
return 1
if s1.upper()<s2.upper():
return -1
else:
return 0
print sorted(['bob', 'about', 'Zoo', 'Credit'],cmp_ignore_case)
#这里函数必须放在列表后面,不然会报函数对象不是迭代错误!
5. python中返回函数
def calc_sum(lst):
def lazy_sum():
return sum(lst)
return lazy_sum
#这里内层函数引用了外层函数的变量lst,称之为闭包。
>>> f = calc_sum([1, 2, 3, 4])
>>> f #f是个函数,参数已经确定
<function lazy_sum at 0x1037bfaa0>
>>> f() #调用f函数,输出值
>>> 10
返回函数不要引用任何循环变量,或者后续会发生变化的变量。
def count():
fs = []
for i in range(1, 4):
def f(j): #闭包函数g没有直接引用循坏变量i,所以可以获得3个参数值不一样的函数。
def g():
return j*j
return g
fs.append(f(i))
return fs
f1, f2, f3 = count()
print f1(), f2(), f3()
输出:1、4、9
6. 匿名函数
lambda x: x * x
匿名函数只能有一个表达式,不写return
#strip()用于去除字符串首尾的指定字符,默认空格或换行符
print filter(lambda s : s and len(s.strip())>0,['test', None, '', 'str', ' ', 'END'])
7. decorator 装饰器
当要对原有函数进行修改是,可以通过高阶函数返回新函数,并将其传给原有函数名,从而覆盖原有函数。可以减少重复性代码。
Python中的@语法是为了简化装饰器调用。
@log 打印日志
@performance 检测性能
@transaction 数据库事物
@#post(’/register’) URL路由
Python的 *args 和 kw,保证任意个数的参数总是能正常调用
args表示任何多个非关键字参数,它是一个tuple;**kwargs表示关键字参数,它是一个dict。并且同时使用args和kwargs时,必须*args参数列要在**kwargs前
import time
#不带参数的decorator,f是要检测的函数
def performance(f):
def fn(*args,**kw):
t1 = time.time() #函数执行前时间
r = f(*args,**kw)
t2 = time.time() #函数执行后时间
print 'call %s() in %d' %(f.__name__,t2-t1) #f.__name__ 是函数名
return r
return fn
@performance
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
输出:
call factorial() in 0
3628800
############有参数的decorator########
import time
def performance(unit): #unit参数
def log_decorator(f): #f函数作为参数
@functools.wraps(f) #把原函数属性复制到新属性中,在返回的新函数前用
def fn(*args,**kw):
t1 = time.time()
r = f(*args,**kw)
t2 = time.time()
print 'call %s() in %d%s' %(f.__name__,t2-t1,unit)
return r
return fn
return log_decorator
@performance('ms')
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10)
输出:
call factorial() in 0ms
3628800
decorator返回的新函数函数名已经不是’factorial’,而是@log内部定义的’fn’,这对于那些依赖函数名的代码就会失效。所以需要把原函数的一些属性复制到新函数中。用functools.wraps(f)
8、偏函数
functools.partial可以把一个参数多的函数变成一个参数少的新函数,少的参数需要在创建时指定默认值,这样,新函数调用的难度就降低了。
>>> import functools
>>> int2 = functools.partial(int, base=2) #转化为二进制,这样就不用每次都输入base参数
>>> int2('1000000')
64
#cmp(a,b) 如果啊a<b 返回-1,a>b 返回1 ,否则 0
>>> sorted_ignore_case = functools.partial(sorted,cmp = lambda s1,s2:cmp (s1.lower(),s2.lower())) #从小到大排序
>>> print sorted_ignore_case(['bob', 'about', 'Zoo', 'Credit'])
['about', 'bob', 'Credit', 'Zoo']
9. 动态模块导入
导入模块错误是执行其他导入
try:
import json
except ImportError:
import simplejson as json
10. 使用__future__
可以在Python旧版本中引入新版本的功能
#在Python 3.x中,字符串统一为unicode,2.7则要加u
from __future__ import unicode_literals
s = 'am I an unicode?'
print isinstance(s, unicode)
11.类
按照 Python 的编程习惯,类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的。
类的实例属性可以像变量一样操作。
__attr :两个下划线开头的属性是私有属性,无法被外部访问。
class Person(object):
pass
#可以为类实例分别定义不同属性
p1 = Person()
p1.name = 'Bart'
p2 = Person()
p2.grade = 2
#可以为Person类添加一个特殊的__init__(self)方法,这样类实例都会有方法里定义的属性
#**kw 定义关键字参数,参数个数可以不用固定
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(): #遍历kw关键字参数,self.k = v
setattr(self,k,v)
xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student',age = 19)
print xiaoming.name
print xiaoming.job
类属性
当实例属性和类属性重名时,实例属性优先级高
#__init__之前写的属性,可以不用先创建实例,再访问,放入实例也可以访问这个属性
class Person(object):
count = 0 #定义初始值
def __init__(self,name):
self.name = name
Person.count += 1 #每创建一个实例都会调用一次__init__,count属性就会+1
实例方法和类实例
实例的方法就是在类中定义的函数,它的第一个参数永远是 self,调用实例方法必须在实例上调用,其他参数和一个普通函数是完全一样。
在实例方法内部,可以访问所有实例属性,这样,如果外部需要访问私有属性,可以通过方法调用获得
class Person(object):
def __init__(self, name, score):
self.name = name
self.score = score
self.get_grade = lambda: 'A' #这里的get_grade是函数,因为不需要实例传入参数
p1 = Person('Bob', 90)
print p1.get_grade
print p1.get_grade()
类方法
在class中定义的全部是实例方法,实例方法第一个参数 self 是实例本身。
class Person(object):
__count = 0
@classmethod #将方法绑定到Person类上
def how_many(cls): #参数名为cls,cls.__count 相当于 Person.count
return cls.__count
def __init__(self,name):
self.name = name
Person.__count+=1
print Person.how_many() #直接访问类方法
12. 类的继承
Python从一个类继承,可以是object,class MyClass (object): pass
调用super().__init__
初始化父类
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
class Teacher(Person):
#super(Teacher,self)返回Teacher继承的父类Person,然后调用__init__方法初始化父类,不然没有name,gender属性,__init__中self已经在super中隐式传入,不能写
def __init__(self, name, gender, course):
super(Teacher,self).__init__(name,gender)
self.course = course
p = Person('Tim', 'Male')
t = Teacher('Alice', 'Female', 'English')
isinstance(p,Teacher)
False #不能认为父类是子类,因为子类比父类多了写属性和方法
isinstance(t,Person)
True #子类可以认为是父类
如果父类和子类有相同的方法,那么方法调用将作用在实际类型上,这个行为叫多态。
多重继承
从多个父类继承,称为多重继承。
dir()返回的属性是字符串列表,如果已知一个属性名称,要获取或者设置对象的属性,就需要用 getattr() 和 setattr( )函数了。
getattr(s, 'age', 20)
获取s的age属性值,没有就返回20
setattr(s, 'name', 'Adam')
设置name属性值,没有就新增属性
13.python 中的一些特殊方法
定义在类中,把类的实例变成str就需要用到__str__()特殊方法或__repr__()方法,其中__str__()是给用户看,而__repr__()是给开发人员看。
class Student(Person):
def __init__(self, name, gender, score):
super(Student, self).__init__(name, gender)
self.score = score
def __str__(self):#定义print实例时的输出形式
return '(Student:%s,%s,%s)' %(self.name,self.gender,self.score)
def __cmp__(self, s): #对类的实例进行排序需要用到__cmp__()
if self.score == s.score:
return cmp(self.name, s.name) #成绩一样的按名字排序,列表元素仅是类实例,否则会报错
return -cmp(self.score, s.score)
如果一个类表现得像一个list,要获取有多少个元素,就得用__len()__ 函数。
#斐波那契数列
class Fib(object):
def __init__(self, num):
a,b = 0,1
l = []
for i in range(num):
l.append(a)
a,b = b,a+b
self.numbers = l #初始化numbers属性,并复制l
def __str__(self): #把实例变成字符串格式,不然print f时不是列表形式,不过这也不影响计算实例元素个数!
return str(self.numbers)
def __len__(self):
return len(self.numbers)
f = Fib(10)
print f
print len(f)
from __future__ import division
class Rational(object):
def __init__(self, p, q):
self.p = p
self.q = q
def __int__(self):
return self.p // self.q
def __float__(self):
return self.p / self.q
print int(Rational(7, 2))
print float(Rational(1, 3))
@property
class Student(object):
def __init__(self, name, score):
self.name = name
self.__score = score
@property
def score(self): #获取成绩,不需要参数
return self.__score
@score.setter #是@property 的副产品,设置成绩,要有一个score参数
def score(self,score):
if score < 0 or score > 100:
raise ValueError('invalid score')
self.__score = score
@property
def grade(self): #相当于新增属性grade
if self.score >= 80:
return 'A'
elif self.score >= 60:
return 'B'
return 'C'
s = Student('Bob', 59)
print s.grade
s.score = 60
print s.grade
s.score = 99
print s.grade
Python是动态语言,任何实例在运行期都可以动态地添加属性。如果要限制添加属性的范围,可以用__slots__来实现。
class Person(object):
#限制属性范围,放在__init__之前
__slots__ = ('name', 'gender')
def __init__(self, name, gender):
self.name = name
self.gender = gender
所有的函数都是可调用对象,一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__()。
class Fib(object):
def __call__(self,num):
a,b,l = 0,1,[]
for i in range(num):
l.append(a)
a, b = b, a + b
return l
f = Fib()
print f(10) #调用实例对象