装饰器
在代码动态运行期间增加功能的方式,称为装饰器。本质上,decorator就是一个返回函数的高阶函数,也可以说高阶函数+嵌套函数=》装饰器。
def timer(func): #timer(test1) func=test1 def deco(*args,**kwargs): start_time = time.time() func(*args,**kwargs) # run test1 stop_time = time.time() print('the func run time is %s'%(start_time-stop_time)) return deco @timer #test1 = timer(test1) def test1(): time.sleep(3) print('in the test1') @timer #test2 = timer(test2) = deco test2(name)=deco(name) def test2(name,age): print('test2:',name,age) test1() test2('yeqin',22)
如上,timer为一个装饰器,所以接受一个函数作为参数,并且返回一个函数,同时借用Python的@语法,把decorator置于函数的定义处。比如上述代码timer装饰test1()和test2.
生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
创建一个generator,方法一只要把一个列表生成式的[]
改成()
,就创建了一个generator,如下:
g = (x*x for x in range(10))
如果要一个一个打印出来,可以通过next()
函数获得generator的下一个返回值:
print(next(g))
我们讲过,generator保存的是算法,每次调用next(g)
,就计算出g
的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration
的错误。
但是我们一般不使用next方法,太麻烦了,正确的方法是使用for
循环,因为generator也是可迭代对象:
for n in g: #使用for循环打印g中的元素 print(n)
练习:斐波那契数列
def fib(max): n,a,b = 0,0,1 while n < max: # print(b) yield b a,b = b,a+b n = n+1 return '---done---' # f = fib(10) g = fib(6)
generator的另一种方法。如果一个函数定义中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator。generator的函数,在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行。
def odd(): print('step1') yield 1 print('step2') yield(3) print('step3') yield(5) o = odd() print(next(o)) print("----------") print(next(o))
调用该generator时,首先要生成一个generator对象,然后用next()
函数不断获得下一个返回值:
step1 1 ---------- step2 3 step3 5
执行3次yield
后,已经没有yield
可以执行了,所以,第4次调用next(o)
就会报错。
注意:1、生成器只有在调用时才会生成相应的数据;
2、只记住当前位置;
3、只有一个——next()——方法。
迭代器
可以直接作用于for循环的对象统称为迭代对象:Iterable。可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。迭代器和迭代对象均可以用isinstance()判断一个对象是否为相应的数。
print('Iterable?[1,2,3]:',isinstance([1,2,3],Iterable)) print('Iterable?\'abc\':',isinstance('abc',Iterable)) print('Iterable?123:',isinstance(123,Iterable) ) print('Iterable?g():',isinstance(g(),Iterable)) print('Iterator?[1,2,3]:',isinstance([1,2,3],Iterator)) print('Iterator?\'abc\':',isinstance('abc',Iterator)) print('Iterator?123:',isinstance(123,Iterator) ) print('Iterator?g():',isinstance(g(),Iterator))
注意:
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。
Python的for
循环本质上就是通过不断调用next()
函数实现的。
内置方法
print(all([1,-5,3])) #元素全为非0才为真 true
print(any([1,0,3])) #任意为真,则为真 true
print(bin(8)) #十进制转二进制
print(bool(-1)) #判断真假 true
a = bytes('abcdef',encoding = 'utf-8')
print(a.capitalize(),a) #bytes字符串转为二进制形式,不可修改
b = bytearray('abcdef',encoding = 'utf-8') #改二进制字符串
print(b[1])
b[1] = 50
print(b)
def hello(): #判断是否可调用
pass
print(callable(hello)) #true
print(chr(97)) #返回ASCII对应表 a
print(ord('d')) #ASCII返回对应数字
code = '''
for i in range(10):
print(i)
'''
exec(code) #可直接运行代码
print(dir(dict())) #dict生成默认字典,dir查询方法
x = 1
print(eval('x+1')) #eval()运行python表达式 2
calc = lambda n:print(n) #匿名函数
print(calc(5))
calc2 =lambda n:3 if n<4 else n #进行三元运算
print(calc2(5))
#filter()过滤
res = filter(lambda n:n>5,range(10))
for i in res:
print(i) #5,6,7,8,9,
#map()一个时函数,一个数Iterable,map将传入的函数一次作用于序列的每个元素,并把结果作为新的Iterable
res = map(lambda n:n*n,range(10))
for i in res:
print(i)
print(hex(255)) #把一个数转为16进制
print(oct(8)) #转八进制
print(pow(2,5)) #返回2的5次方
print(round(1.31678,2)) #保留两位小数
a = [1,2,3,4]
b =['a','b','c','d']
for i in zip(a,b): #融合a和b
print(i)
序列化与反序列化
序列化:把变量从内存中变成可存储或者传输的过程称为序列化。
反序列化:把变量内容和从序列化的对象重新读入内存
json 序列化
import json dict = {'name':'Alex', 'age':33, 'address':'中国'} print('未序列化前的数据类型为:', type(dict)) print('为序列化前的数据:', dict) #对dict进行序列化的处理 dict_xu = json.dumps(dict,ensure_ascii=False) #添加ensure_ascii=False进行序列化 print('序列化后的数据类型为:', type(dict_xu)) print('序列化后的数据为:', dict_xu) #对dict_xu进行反序列化处理 dict_fan = json.loads(dict_xu) print('反序列化后的数据类型为:', type(dict_fan)) print('反序列化后的数据为: ', dict_fan) ---------------------------------------------------------------------- 未序列化前的数据类型为: <class 'dict'> 未序列化前的数据: {'name': 'Alex', 'age': 33, 'address': '中国'} 序列化后的数据类型为: <class 'str'> 序列化后的数据为: {"name": "Alex", "age": 33, "address": "中国"} 反序列化后的数据类型为: <class 'dict'> 反序列化后的数据为: {'name': 'Alex', 'age': 33, 'address': '中国'}
注意:在序列化时,中文汉字总是被转换为unicode码,在dumps函数添加参数ensure_ascii=False即可解决问题。
pickle序列化与json功能类似,用法相同。不同的是,json更适合夸语言,可以处理字符串,基本数据类型;pickle为python专有,更适合用于处理复杂;类型的序列化。