过滤删选(解析比filter快)
d = [-1, 3, 2, 1, 0, 10]
r = [x for x in d if d > 3] ==> [10]
dd = {'a': 1, 'b': -1}
rr = {k: v for k, v in dd.items() if v > 0} ==> {'a': 1}
集合对象,减少[0][1]...的使用,提高代码的可维护性
method-1:
index_name_1, index_name_2 ... = xrange(2)
s = ('a', 'b' ...)
s[index_name_1] ==> 'a'
s[index_name_2] ==> 'b'
method-2:
from collections import namdtuple
s = namdtuple('tuple_name', ['index_name_1', 'index_name_2'...])
obj = s('a', 'b' ... )
obj.index_name_1 ==> 'a'
obj.index_name_2 ==> 'b'
对一定结构数据的计数统计
from collections import Counter
a = [1, 2, 3, 3, 4, 1]
c = Counter(a)
a[1] ==> 2
a[2] ==> 1
a[3] ==> 2
a[4] ==> 4
c.most_common(1) ==> [(4, 4)]
Counter方法详细介绍:http://www.pythoner.com/205.html
dict中按照value值排序
method-1:
a = {'a': 2, 'b': 1, 'c': 5}
sorted(zip(a.itervalues(), a.iterkeys())) ==> [(1, 'b'), (2, 'a'), (5, ')]
method-2:
a = {'a': 2, 'b': 1, 'c': 5}
sorted(a.iteritems(), key=lambda x: x[1]) ==> [('b', 1), ('a', 2), ('c', 5)]
如何快速找到多个字典中的公共键(key)
method-1:(只是试用有限个数)
s1 = {'a': 1, 'b';2}
s2 = {'b': 1, 'c': 1}
s3 = {'a': 2, 'b': 3, 'd': 1}
s1.viewkeys() & s2.viewkeys() & s3.viewkeys() ==> {'b'}
method-2:
reduce(lambda a, b: a & b, map(dict.viewkeys, [s1, s2, s3])) ==> {'b'}
如何让字典保持有序(collections.OrderedDict)
from time import time
from random import randint
from collections import OrderedDict
d = OrderedDict()
players = list('abcdefgh')
start = time()
for i in xrange(7):
raw_input()
p = players.pop(randint(0, 7 - i))
end = time()
print i + 1, p, end - start
d[p] = (i + 1, end - start)
for y in d:
print y, d[y]
==> p (1, time)
p (2, time)
p (3, time)
p (4, time)
p (5, time)
p (6, time)
p (7, time)
记录历史记录,collections.deque和pickle的使用
from random import randint
from collections import deque
import pickle
N = randint(1, 100)
try:
history = pickle.load(open('history.txt'))
except:
history = deque([], 5)
def guess(k):
if k == N:
print 'right'
return True
if k < N:
print '%s is less then N' % k
else:
print '%s is greater then N' % k
return False
while True:
line = raw_input('plase input a number:')
if line.isdigit():
k = int(line)
history.append(k)
pickle.dump(history, open('history.txt', 'w'))
if guess(k):isalnum
break
elif line == 'history' or line == 'h?':
print list(history)
注:deque列表对象,有两个参数,初始队列和最大长度,并有append和appendleft方法,分别是从后插入和从前插入
pickle的作用是将python对象存入文件,用法与json的使用的方法很相似,有dump和load方法等
使用isdigit判断字符串是否可以转为整型,另外还有很多字符串内置的判断函数
构造可迭代对象,collections.Iterable和collections.Iterator的使用
from collections import Iterable, Iterator
class Demo1(Iterator):
def __init__(self, cities):
self.cities = cities
self.index = 0
def next(self):
if self.index == len(self.cities):
raise StopIteration
city = self.cities[self.index]
self.index += 1
return city
class Demo2(Iterable):
def __init__(self, cities):
self.cities = cities
def __iter__(self):
return Demo1(self.cities)
a = Demo2(['a','b', 'c'])
for each in a:
print each
注:在构造可迭代对象时必须使用raise StopIteration来结束迭代
使用yield生成器实现可迭代对象
class PrimeNumber:
def __init__(self, start, end):
self.start = start
self.end = end
def isPrimeNum(self, k):
if k < 2:
return False
for i in xrange(2, k):
if k % i == 0:
return False
return True
def __iter__(self):
for k in xrange(self.start, self.end + 1):
if self.isPrimeNum(k):
yield k
for x in PrimeNumber(1, 100):
print x
注:关注yield的使用
反向迭代(reversed)
class Demo:
def __init__(self, start, end, step=0.1):
self.start = start
self.end = end
self.step = step
def __iter__(self):
t = self.start
while t <= self.end:
yield t
t += self.step
def __reversed__(self):
t = self.end
while t >= self.start:
yield t
t -= self.step
a = Demo(1.0, 2.0, 0.1)
for x in reversed(a):
print x
注:reversed获得的是反向迭代器,iter获得的是正向迭代器
文件切片操作,itertools.islice常用与大文件的切片操作
from itertools import islice
a = range(10)
t = iter(a)
print 'islice start'
for x in islice(t, 2, 4):
print x
print 'islice end'
for x in t:
print x
注:使用islice后的迭代对象会被消耗掉在islice切片的数据,需要重新生成迭代对象
在for中同时迭代多个对象
# 计算每人三课的总分(并行问题,使用zip):
from random import randint
chinese = [randint(60, 100) for _ in xrange(40)]
math = [randint(60, 100) for _ in xrange(40)]
english = [randint(60, 100) for _ in xrange(40)]
total = []
for a, b, c in zip(chinese, math, english):
total.append(a + b + c)
# 统计几个班英语成绩都高于90的(串行问题,使用itertools.chain):
chain([1, 2, 3], [4, 5, 6]) ==> 生成1,2,3,4,5,6的迭代对象
e1 = [randint(60, 100) for _ in xrange(40)]
e2 = [randint(60, 100) for _ in xrange(42)]
e3 = [randint(60, 100) for _ in xrange(39)]
e4 = [randint(60, 100) for _ in xrange(43)]
count = 0
for _ in chain(e1, e2, e3, e4):
if _ > 90:
count += 1
拆分含有多个分隔符的字符串
method-1:
def mySplit(s, ds):
res = [s]
for d in ds:
t = []
map(lambda x: t.extend(x.split(d)), res)
res = t
return [_ for _ in res if _]
s = 'ab;cd|efg|hi,,jkl|mn\topq;rst,uvw\txyz'
print mySplit(s, ';,|\t')
==> ['ab', 'cd', 'efg', 'hi', 'jkl', 'mn', 'opq', 'rst', 'uvw', 'xyz']
method-2(推荐使用):
import re
s = 'ab;cd|efg|hi,,jkl|mn\topq;rst,uvw\txyz''
re.split(r'[;,|\t]+', s)
==> ['ab', 'cd', 'efg', 'hi', 'jkl', 'mn', 'opq', 'rst', 'uvw', 'xyz']
注:单个切割直接使用split比较快
判断字符串是否以某个字符串开头或结尾(使用startswith和endswith)
a = 'a.py'
a.startswith('a') ==> True
a.endswith('.py') ==> True
注:startswith和endswith只能接受一个元祖不能使用列表
字符替换(使用re.sub)
import re
a = '2017-11-01'
re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\2/\3/\1', a)
==> '11/01/2017'
re.sub('(?P\d{4})-(?P\d{2})-(?P\d{2})', r'\g/\g/\g', a)
==> '11/01/2017'
注:使用正则表达式时最好使用'r'防止字符串的转义
拼接字符串(使用str.join)
a = ['a', 'b', 'c', 'd']
'',join(a) ==> 'abcd'
'+'.join(a) ==> 'a+b+c+d'
a = ['abc', 123, 'xyz']
''.join([str(_) for _ in a]) ==> 'abc123xyz'
''.join((str(_) for _ in a)) ==> 'abc123xyz'
注:推荐使用第二种方式,使用生成器方式减少内存占用
对字符串左右居中对齐
method-1:
s = 'abc'
s.ljust(10) ==> 'abc '
s.rjust(10) ==> ' abc'
s.center(10) ==> ' abc '
s.ljust(10, '=') ==> 'abc======='
method-2:
s = 'abc'
format(s, '<20') ==> 'abc '
format(s, '>20') ==> ' abc'
format(s, '^20') ==> ' abc '
去掉字符串中不需要的字符
method-1(删除首尾,使用strip,lstrip,rstrip):
s = ' abc 123 '
s.strip() ==> 'abc 123'
s.lstrip() ==> 'abc 123 '
s.rstrip() ==> ' abc 123'
s = '--abc--123--'
s.strip() ==> 'abc--123'
s.lstrip() ==> 'abc--123--'
s.rstrip() ==> '--abc--123'
s = '--abc++'
s.strip('-+') ==> 'abc'
method-2(删除中间的字符,使用切片):
s = 'abc+123'
s[:3] + s[4:] ==> 'abc123'
method-3(删除或替换任何位置的字符,使用replace,re.sub):
s = '\tabc\t123\txyz'
s.replace('\t', '') ==> 'abc123xyz'
s = '\tabc\t123\txyz\ropq\r'
import re
re.sub('[\t\r]', '', s) ==> 'abc123xyzopq'
注:replace只能替换一种字符,re.sub可以使用正则表达式替换多种
method-4(删除任何位置的字符,使用translate):
s = 'abc\t123\nref\r'
s.translate(None, '\r\t\n') ==> 'abc123ref'
文件读写
python2:
s = u'你好'
with open('test.txt', 'w') as f:
f.write(s.encode('utf-8'))
with open('test.txt', 'r') as f:
s = f.read().decode('utf-8')
python3:
s = '你好'
# 't'指的是一种文本模式
with open('demo.txt', 'wt', encoding='utf-8') as f:
f.write(s)
with open('demo.txt', 'rt', encoding='utf-8') as f:
s = f.read()
注:
Python2和Python3字符对应关系
python2 python3
str ==> bytes
unicode ==> str
一般都会将字节写入物理文件
文件读写缓冲
# 全缓冲
f = open('demo.txt', 'w', buffering=2048)
# 行缓冲
f = open('demo.txt', 'w', buffering=1)
...
# 在写入'\n'之前都是写入缓冲,在写入'\n'后会将缓冲中的内容写入磁盘
f.write('\n')
# 无缓冲
f = open('demo.txt', 'w', buffering=0)
# 执行write即写入磁盘,不做缓冲
注:open默认是全缓冲,大小是4096
文件状态访问
系统调用:os.stat,os.fstat,o.lstat获取文件状态
快捷函数:os.path下的函数,使用起来更加简洁
import os
os.path.isdir 判断是否是文件夹
os.path.islink 判断是否是连接文件
os.path.isfile 判断是否是普通文件
os.path.isabs 判断是否是绝对路径
...
如何使用临时文件(使用tempfile中的TemporaryFile和NamedTemporaryFile)
# 获得临时文件对象
f = TemporaryFile()
# 将数据写入磁盘
f.write('abc' * 4096)
# 先将文件指针指向开头后才能将数据都会到内存中
f.seek(0)
# 根据具体需求量读取数据
f.read(100)
# delete自动清除参数默认是True,如果需要保留可以设置FALSE
ntf = NamedTemporaryFile()
# NamedTemporaryFile创建的临时文件路径
ntf.name
注:在系统文件中找不到TemporaryFile创建的临时文件,使用NamdTemporaryFile创建的临时文件可以在系统中找到TemporaryFile创建的只能在本进程中访问NamedTemporaryFile创建的可以多进程进行访问
csv读写(使用csv模块)
import csv
rf = open('demo.csv', 'rb')
# reader 是一个可迭代对象
reader = csv.reader(rf)
# 打印每一行
for _ in reader:
# 每一行都是一个列表
print _
wf = open('demo.csv', 'wb')
writer = csv.writer(wf)
# 写入的数据是一个列表
writer.writerow(list_obj)
# 写入的数据是由多个元组组成的列表
writer.writerows([tuple_obj, tuple_obj...])
注:一定要使用二进制文件
json文件格式的处理(使用json库)
import json
a = {'a': None, 'b': 1}
json.dumps(a) ==> '{"a": null, "b": 1}'
# 可以去除多余的空格,另外也可以自己定制
json.dumps(a, separators=[',', ':']) ==> '{"a":null,"b":1}'
a = '{"a": null, "b": 1}'
json.loads(a) ==> {'a': None, 'b': 1}
with open('demo.json', 'wb') as f:
json.dump(a, f)
with open('demo.json', 'rb') as f:
a = json.load(f)
注:json.dump和json.load作用于文件
excel文件处理(使用第三方库xlrd,xlwt)
pip install xlrd xlwt
book = xlrd.open_workbook('demo.xlsx')
# 所有sheet的列表
book.sheets()
# 根据索引获得单个sheet对象
sheet = book.sheet_by_index(0)
# 根据名字获得单个sheet对象
sheet = book.sheet_by_name(name)
如何派生内置不可变类型并修改实例化行为(使用真正的构造函数new)
class IntTuple(tuple):
def __new__(cls, iterable):
g = (_ for _ in iterable if isinstance(_, int) and _ > 0)
return super(IntTuple, cls).__new__(cls, g)
def __init__(self, iterable):
print self ==> (1, 6)
super(IntTuple, self).__init__(iterable)
t = IntTuple([1, -2, 'abc', 6, ['a', 'b'], 0])
print t ==> (1, 6)
注:new是类真正的构造函数,先于init被调用,self是由new构造获得
如何为创建大量实例节省内存(使用slots属性来声明实例属性列表)
class Player1(object):
def __init__(self, uid, name, status=0, level=1):
self.uid = uid
self.name = name
self.status = status
self.level = level
class Player2(object):
__slots__ = ['uid', 'name', 'status', 'kevek']
def __init__(self, uid, name, status=0, level=1):
self.uid = uid
self.name = name
self.status = status
self.level = level
p1 = Player1('001', 'p1')
p1.x = 11
p2 = Player2('002', 'p2')
p2.x == 11 ==> 报错,因为没有__dict__属性做数据的动态绑定
注:使用slots关闭默认的动态属性绑定dict,减少内存也可以用来阻值类的数据动态绑定
如何让对象支持上下文管理(使用enter和exit)
class Demo(object):
def start(self):
"""
with打开后执行的方法
"""
# 主要的操作内容,例如输入密码登录等等操作
def __enter__(self):
"""
with之前的一些准备工作
必须要有返回值,作用给with调用后as的对象
"""
# 准备工作,例如打开连接
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""
必要参数,在没有异常时,以下参数的值都是None
exc_type:异常类型
exc_val:异常的值
exc_tb:错误路径
"""
# 结束工作,例如关闭连接
# 设置返回值为True,如果有异常也不会抛出
# return True
with Demo() as d:
d.start()
注:enter在with之前调用,exit在with之后调用遇到异常也会执行exit内的方法
如何创建可管理的对象属性(使用property)
class Demo(object):
def __init__(self):
self.show = 0
def getShow(self):
return self.show
def setShow(self, num):
self.show = num
SHOW = property(getShow, setShow)
d = Demo()
print d.SHOW ==> 0
d.SHOW = 2
print d.show ==> 2
注:property的第一个参数是get操作,第二参数是set操作,第三个属性是del操作需要补充@property的使用方法
类对象之间的<,<=,>,>=,==,!=
# method-1(使用__lt__,__le__,__gt__,__eq__,__ne__):
注:一般有两个参数,一个是self,另一个obj(需要比较的对象)
# method-2(使用functools.total_ordering):
from functools import total_ordering
@total_ordering
class Demo(object):
def __init__(self):
pass
def __lt__(self, obj):
return
def __eq__(self, obj):
return
注:使用functools.total_ordering只需要重写lt和eq就可以实现全部<,<=,>,>=,==,!=
# method-3(使用抽象基类):
from functools import total_ordering
from abc import ABCMeta, abstractmethod
@total_ordering
class DemoBase(object):
@abstractmethod
def foo(self):
"""
所有继承该类的子类都需要实现这个方法
"""
pass
def __lt__(self, obj):
if not isinstance(obj, DemoBase):
raise TypeError('obj is not DemoBase')
return self.foo() < obj.foo()
def __eg__(self, obj):
if not isinstance(obj, DemoBase):
raise TypeError('obj is not DemoBase')
return self.foo() == obj.foo()
class Demo1(DemoBase):
def __init__(self):
pass
def foo(self):
"""
此方法必须实现
"""
pass
class Demo2(DemoBase):
def __init__(self):
pass
def foo(self):
"""
此方法必须实现
"""
pass
d1 = Demo1()
d2 = Demo2()
# 使用DemoBase做基类就可以实现<,<=,>,>=,==,!=
# 子类就不需要实现__lt__,__eg__等方法
d1 > d2
d2 <= d2
...
如何会用描述符对实例属性做类型检查
class Attr(object):
def __init__(self, name, type_):
# type_ 指python内置类型
self.name = name
self.type_ = type_
def __get__(self, instance, cls):
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, self.type_):
raise TypeError('expected an %s' % self.type_)
return instance.__dict__[self.name] = value
def __delete__(self, instance):
def instance.__dict__[self.name]
class Person(object):
name = Attr('name', str)
age = Attr('age', int)
height = Attr('height', float)
p = Person()
p.name = 'cancan'
prnt p.name ==> 'cancan'
p.name = 11 ==> raise Exception
...
如何在环状数据结构中管理内存
sys.getrefcount(obj) - 1 ==> 查看对象被引用的次数
gc.collect() ==> 在对象定义了析构函数__del__时不能被清除引用
a = Demo()
a_wref = weakref.ref(a)弱引用方式,在循环引用中可以减少引用次数,方便管理
使用字符串来调用类中的方法
# method-1(使用getattr方法):
# 第一个参数是类对象名,第二参数是类对象拥有的方法名字符串,第三个参数是在没有找到对应方法时返回的值
f = getattr(class_obj_name, class_obj_func_name, None)
if f:
f(args)
# method-2(使用operator.methodcaller)
from operater import mehtodcaller
s = 'abc123abc456'
# 从第四个参数找'abc'
s.find('abc', 4) ==> 6
mehtodcaller('find', 'abc', 4)(s) ==> 6
多线程使用(使用threading.Thread)
from threading import Thread
def foo():
"""
需要线程处理的函数
"""
pass
# method-1(直接使用方法):
# 传入args是一个元组,当只有一个参数时需要加','
T = Thread(target=foo, args=(arg1, arg2..))
T.start()
# method-2(使用类):
class Demo(Thread):
"""
使用类可以更好的封装数据
"""
def __init__(self, args):
# 必须条用Thread这个父类的构造器
Thread.__init__(self)
self.args = args
def run(self):
"""
必须实现该方法
"""
# 指定需要运行的函数
foo()
threads = []
for _ in xrange(1, 10):
T = Demo(args)
threads.append(T)
# 使用start()会进入run()函数
T.start()
for _ in threads:
# join()是一个阻塞函数,run()没有运行完不会退出
_.join()
注:python中的多线程只适合用于多I/O密集型的环境,如果是CPU密集型,建议使用多进程
线程间事件通知(使用Threading.Event)
from Threading import Event
def f(e):
print 'f 0'
e.wait()
print 'f 1'
e = Event()
t = Thread(target=f, args=(e, ))
t.start()
==> 'f 0' # 此时等待e调用set()方法
e.set()
==> 'f 1'
# 清理后才可以重复使用
e,clear()
注:
1.两个线程都需要是Event
2.wait是一个阻塞函数,会等待另一个线程中set的调用
如何实现线程本地的数据(使用threading.local)
from threading import local
l = local()
# 创建的x是在调用该线程时的私有数据
# 注意:目前l属于主线程
l.x = 'a'
# 主线程中运行会修改参数
def f();
l.x = 'b'
f()
print l.x ==> 'b'
# 子线程中运行不会修改主线程中的数据
l.x = 'a'
threading.Thread(target=f).start()
print l.x ==> 'a'
如何使用线程池(python3中使用concurrent.futures.ThreadPoolExecutor)
# 3表示线程池的个数
executor = ThreadPoolExecutor(3)
def f(a, b):
print('f', a, b)
return a ** b
# 使用池中的一个线程
executor.submit(f, 2, 3,) ==> f 2 3
# future 是使用池中线程之后返回的对象
future = executor.submit(f, 2, 3) ==> f 2 4
# 如果f函数运行时间很长,result()就会阻塞
future.result() ==> 16
# 同时调用
executor.map(f, [2, 3, 4], [4, 5, 6])
==> f 2 4
f 3 5
f 5 6
注:如果线程数大于线程池的数,超出的线程就会等待线程池中的线程运行完毕,有了空位才会运行
如何使用多进程(使用multiprocessing.Process)
from multiprocessing import Process
def f(s): print s
# 启动一个子进程
p = Process(target=f, args=('hello', ))
p.start() ==> 'hello'
# 等待一个进程结束
p.join()
# 与多线程的不同之处在于使用的虚拟地址空间是不同的
x = 1
def f():
global x
x = 5
# 在本进程调用这个函数
f()
x ==> 5
# 启动子进程来测试
x = 1
p = Process(target=f).start()
# 在主进程中查看x,x并没有变化,得出子进程和主进程看到的x不是同一个
# 说明个个进程之间他们的虚拟地址是独立的
x ==> 1
进程间进行通信(使用multiprocessing.Queue和multiprocessing.Pipe)
# method-1(使用multiprocessing.Queue):
from multiprocessing import Process, Queue
q = Queue()
def f(q):
# 等待主进程传一个值
print 'start'
print q.get()
print 'end'
Process(target=f, args=(q, )).start()
==> start
# 打印start,等待主进程传入一个值
q.put(100)
# 当传入一个值后子进程立马执行
==> 100
end
# method-2(使用multiprocessing.Pipe):
from multiprocessing import Process, Pipe
# Pipe会创建一个双向管道
c1, c2 = Pipe()
# 从c1传入'a'
c1.send('a')
# 只能从c2读取'a'
c2.recv() ==> 'a'
# 从c2传入'a'
c1.send('a')
# 只能从c1读取'a'
c2.recv() ==> 'a'
def f(c):
c.send(c.recv() * 2)
# 启动子进程,等待c1端输入
Process(target=f, args=(c2,)).start()
c1.send(2)
c1.recv() ==> 4
如何使用装饰器
# -*- coding: utf-8 -*-
def memo(func):
cache = {}
def wrap(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrap
# [题目1] 菲波那切数列(Fibonacci Sequence),又称黄金分割数列
# 指的是这样一个数列: 1,1,2,3,5,8,11.21...
# 这个数列从第三项开始,每一项都等于前面两项之和,求数列第n项
@memo
def fibonacci(n):
if n <= 1:
return 1
return fibonacci(n - 1) + fibonacci(n - 2)
print fibonacci(50)
# [题目2] 一个共有10个台阶的楼梯,从下面走到上面,一次只能迈1~3个台阶
# 并且不能后退,走完这个楼梯共有多少种方法
@ memo
def climb(n, steps):
count = 0
if n == 0:
count = 1
elif n > 0:
for step in steps:
count += climb(n - step, steps)
return count
print climb(10, (1,2,3))
为被装饰的函数保存元数据
from functools import update_wrapper, wrap, WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES
method-1(使用update_wrapper函数):
def Demo(func):
def wrapper(*args, **kwargs):
"""is wrapper"""
print 'is wrapper'
func(*args, **kargs)
# 使用原函数的属性替换包裹函数,倒数第二个参数是替换,倒数第一个参数是合并
# 后两个参数可以使用如下默认参数
# WRAPPER_ASSIGNMENTS ==> ('__module__', '__name__', '__doc__')
# WRAPPER_UPDATES ==> ('__dict__', )
update_warapper(wrapper, func, ("__name__", "__doc__"), ("__dict__", ))
return wrapper
method-2(使用wraps装饰器):
def Demo(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""is wrapper"""
print 'is wrapper'
func(*args, **kargs)
return wrapper
注:
函数元数据
f.__name__ : 函数的名字
f.__doc__ : 函数文档字符串
f.__module__ : 函数所属模块名
f.__dict__ : 属性字典
f.__defaults__ : 默认参数元祖
...
定义带参数的装饰器(使用与python3)
# python3 中的模块
from inspect import signature
def typeAssert(*ty_args, **kwy_args):
def decorator(func):
"""
解决思路:
func -> a,b
d = {'a': int, 'b', str}
使用signature实现上述d的生成
wrapper通过d来做验证
arg in d, instache(arg, d[arg])
"""
# 获得func的签名
sig = signature(func)
btypes = sig.bind_partial(*ty_args, **kwy_args).arguments
def wrapper(*args, **kwargs):
for name, obj in sig.bind(*args, **kwargs).arguments.iteritems():
if name in btypes:
if not isinstance(obj, btypes[name])
raise TypeError('%s must be %s' % (name, btypes[name]))
return func(*args, **kwargs)
return wrapper
return decorator
@typeAssert(int, str, list)
def f(a, b, c):
print(a, b, c)
f(1, 'abc', [1, 2, 3])
f(1, 2, [1, 2, 3])
==> 1 abc [1, 2, 3]
TypeError: 'b' must be ''
如何实现属性可修改的函数装饰器(适用于python3)
from functools import wraps
from random import randint
import time
import logging
def warn(timeout):
def decorator(func):
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
used = time.time() - start
if used > timeout:
msg = '%s : %s > %s' % (func.__name__, used, timeout)
logging.warn(msg)
return res
def setTimeout(k):
# python3 特有的类型,用于设置闭包内的全局变量
# 如果不声明,此函数中的timeout与warn(timeout)中的timeout不是同一个
nonlocal timeout
timeout = k
wrapper.setTimeout = setTimeout
return wrapper
return decorator
@warn(0.5)
def test():
print 'in test'
while randint(0, 1):
time.sleep(0.5)
for _ in range(30):
test()
test.setTimeout(1)
for _ in range(30):
test()