返回函数
类似js的闭包;
例子1:
def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs
计数器:
在fn()
函数内部加一个nonlocal x
的声明, 解释器把fn()的x看作外层函数的局部变量,它已经被初始化了,可以正确计算x+1
.
def createCounter():
x = 0
def counter():
nonlocal x #去掉会报错
x = x +1
return x
return counter
f = createCounter()
print(f()) # 1
print(f()) # 2
print(f()) # 3
print(f()) # 4
匿名函数
lambda
定义了匿名函数
过滤偶数:
filter
中的函数参数没有()
与参数
# -*- coding: utf-8 -*-
def is_odd(n):
return n % 2 == 1
L = list(filter(is_odd, range(1, 20))) #is_odd不需要写参数
#通过匿名函数
L = list(filter(lambda x : x % 2 == 1, range(1, 20)))
装饰器
wrapper()
函数的参数定义是(*args, **kw)
,因此,wrapper()
函数可以接受任意参数的调用。
wrapper.__name__ = func.__name__
等同于Python内置的@functools.wraps(func)
设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间:
# -*- coding: utf-8 -*-
import time, functools
def metric(fn):
@functools.wraps(fn)
def wrapper(*args,**kw):
startTime = time.time()
result = fn(*args,**kw)
endTime = time.time()
excuteTime = 1000 * (endTime- startTime)
print('%s executed in %s ms' % (fn.__name__, excuteTime))
return result
return wrapper
# 测试
@metric
def fast(x, y):
time.sleep(0.0012)
return x + y;
@metric
def slow(x, y, z):
time.sleep(0.1234)
return x * y * z;
f = fast(11, 22)
s = slow(11, 22, 33)
##输出
fast executed in 1.293182373046875 ms
slow executed in 123.56829643249512 ms
带参数的decorator
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
#定义函数
@log('execute')
def now():
print('2015-3-25')
#执行结果
>>> now()
execute now():
2015-3-25
偏函数
int()
函数提供 base
参数,默认值为 10
。如果传入 base
参数,就可以做N进制的转换:
>>> int('12345', base=8)
5349
>>> int('12345', 16)
74565
利用偏函数固定参数:
functools.partial
固定函数的某个参数, 实现简化函数调用
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
模块
以内建的 sys
模块为例:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
' a test module '
__author__ = 'Michael Liao'
import sys
def test():
args = sys.argv
if len(args)==1:
print('Hello, world!')
elif len(args)==2:
print('Hello, %s!' % args[1])
else:
print('Too many arguments!')
if __name__=='__main__':
test()
作用域
类似_xxx
和__xxx
这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc
,__abc
等;
Python并没有一种方法可以完全限制访问private
函数或变量,但是,从编程习惯上不应该引用private
函数或变量。
private函数的作用示例:
def _private_1(name):
return 'Hello, %s' % name
def _private_2(name):
return 'Hi, %s' % name
def greeting(name):
if len(name) > 3:
return _private_1(name)
else:
return _private_2(name)
面向对象编程
类和实例
和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self
,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。
定义类:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
(object)
,表示该类是从哪个类继承下来的,继承的概念我们后面再讲,通常,如果没有合适的继承类,就使用object
类,这是所有类最终都会继承的类。
>>> bart = Student('Bart Simpson', 59)
>>> bart.name
'Bart Simpson'
>>> bart.score
59
数据封装
在Student
类的内部定义访问数据的函数,这样,就把“数据”给封装起来了。这些封装数据的函数是和Student
类本身是关联起来的,我们称之为类的方法:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))
除了self
不用传递,其他参数正常传入:
>>> bart.print_score()
Bart Simpson: 59
访问限制
通过私有变量private实现: __name
, __score
双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name
是因为Python解释器对外把__name
变量改成了_Student__name
,所以,仍然可以通过_Student__name
来访问__name
变量:
>>> bart._Student__name
'Bart Simpson'
继承与多态
多态: 子类方法与父类重合时会覆盖父类的方法,即优先调用子类的方法.
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
pass
class Cat(Animal):
pass
#调用
dog = Dog()
dog.run()
cat = Cat()
cat.run()
#结果
Animal is running...
Animal is running...
#子类方法:
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
#再次调用结果:
Dog is running...
Cat is running...
def run_twice(animal):
animal.run()
animal.run()
>>> run_twice(Animal())
Animal is running...
Animal is running...
>>> run_twice(Dog())
Dog is running...
Dog is running...
Python的动态特点, 不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了.
获取对象信息
type()
isinstance()
dir()
:
获得一个str对象的所有属性和方法:
>>> dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']
getattr()
、setattr()
、hasattr()
,可以直接操作一个对象的状态:
>>> class MyObject(object):
... def __init__(self):
... self.x = 9
... def power(self):
... return self.x * self.x
...
>>> obj = MyObject()
#操作
>>> hasattr(obj, 'x') # 有属性'x'吗?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有属性'y'吗?
False
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> hasattr(obj, 'y') # 有属性'y'吗?
True
>>> getattr(obj, 'y') # 获取属性'y'
19
>>> obj.y # 获取属性'y'
19
#传入一个default参数
>>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
404
#获得对象的方法:
>>> hasattr(obj, 'power') # 有属性'power'吗?
True
>>> getattr(obj, 'power') # 获取属性'power'
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn
>>> fn # fn指向obj.power
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn() # 调用fn()与调用obj.power()是一样的
81
实例属性与类属性
创建类的属性:
class Student(object):
name = 'Student'
测试:
>>> class Student(object):
... name = 'Student'
...
>>> s = Student() # 创建实例s
>>> print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
Student
>>> print(Student.name) # 打印类的name属性
Student
>>> s.name = 'Michael' # 给实例绑定name属性
>>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
Michael
>>> print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问
Student
>>> del s.name # 如果删除实例的name属性
>>> print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了
Student
为了统计学生人数,可以给Student类增加一个类属性,每创建一个实例,该属性自动增加:
class Student(object):
count = 0
def __init__(self, name):
self.name = name
Student.count += 1
self.count = Student.count
#测试
# 测试:
if Student.count != 0:
print('测试失败!')
else:
bart = Student('Bart')
if Student.count != 1:
print('测试失败!')
else:
lisa = Student('Bart')
if Student.count != 2:
print('测试失败!')
else:
print('Students:', Student.count)
print('测试通过!')