本节大纲:
一:双层装饰器:
一个函数可以被多层装饰器进行装饰,函数渲染(编译)从下到上,函数执行从上到下。
如下程序:
1 #!/usr/bin/env python
2 #-*-coding:utf-8-*-
3 # author:liumeide
4
5 # USERINOF={'islogin':True}
6 USERINOF={'user_type':'2','islogin':True}
7 def login(func):
8 def inner_1(*args,**kwargs):
9 if USERINOF.get('islogin',None):
10 ret=func()
11 return ret
12 else:
13 print('login first!')
14 return inner_1
15 def check_user(func):
16 def inner(*args,**kwargs):
17 if USERINOF.get('islogin',None)==True and USERINOF.get('user_type',None)=='2':
18 ret=func()
19 return ret
20 else:
21 print('permission deny!!')
22 return inner
23 @login
24 @check_user
25 def index():
26 print('index')
27
28 index()
多层装饰器该如何理解呢?
上面的函数的可以执行顺序可以理解为:
首先:函数login、check_user、index加载到内存。在调用index函数的时候,执行index函数,因为index函数被check_user函数装饰,所以把check_user函数的内的inner函数体重新赋值给index,index函数体被当做
参数传入check_user函数。当满足inner函数的条件的时候被执行,新的函数index函数的函数体inner被login函数的所装饰,也就是说inner函数被重新赋值给inner_1函数。也就是说最后调用执行index()顺序:
先执行inner_1函数体----->在执行inner函数体-->在执行index原先的函数体。
多层装饰器以此类推,同样的原理。三层以上的装饰器很少使用。
二:字符串格式化:
%[(name)][flags][width].[precision]typecode
%号初始化字符串:
顺序传入参数。
执行名称传入参数
保留小数点后几位
当有占位符的时候 需要%%输出%如果没有占位符需要只写一个%在占位符的时候类似一个转义的意思。
1:
1 print('name:%s,age:%s'%('evil','22'))
2
3 name:evil,age:22
普通字符串的初始化,需要传入的实参和占位符的个数保持一致。
(name):按名字进行取值。
2:可以根据占位的name的key,根据后面的字典对应的value进行传入来进行传入实参。
1 print("Name:%(name)s"%{'name':'ok'})
2 Name:ok
3: flags一般和width宽度来一起配合使用,如果单纯的使用flags并没什么效果。很少使用这个功能。
1 print("qqqq%(name)+s"%{'name':'ok'})
2 qqqqok
2个一起配合使用:+10表示右对齐,字符串ok占用10个字符。右对齐;正数前加正好,负数前加负号
1 print("qqqq%(name)+10s"%{'name':'ok'})
2 qqqq ok
-号表示左对齐。左对齐;正数前无符号,负数前加负号;
空格 右对齐;正数前加空格,负数前加负号;
0 右对齐;正数前无符号,负数前加负号;用0填充空白处;
.precision 可选,小数点后保留的位数
但是没有居中的功能。
1 print("qqqq%(name)-10sqqq"%{'name':'ok'})
2 qqqqok qqq
print("%+10d" % 10)
+10
1 print("%-10d" %10)
2 10
1 print("%04d" % 5)
2 0005
1 print("%04d" % -5)
2 -005
1 print("% 4d" % 5)
2 5
1 print("%.2f" % 1.225)
2 1.23
typecode表示执行传入的字符串类型。有如下:
s,获取传入对象的__str__方法的返回值,并将其格式化到指定位置
r,获取传入对象的__repr__方法的返回值,并将其格式化到指定位置
c,整数:将数字转换成其unicode对应的值,10进制范围为 0 <= i <= 1114111(py27则只支持0-255);字符:将字符添加到指定位置
o,将整数转换成 八 进制表示,并将其格式化到指定位置
x,将整数转换成十六进制表示,并将其格式化到指定位置
d,将整数、浮点数转换成 十 进制表示,并将其格式化到指定位置
e,将整数、浮点数转换成科学计数法,并将其格式化到指定位置(小写e)
E,将整数、浮点数转换成科学计数法,并将其格式化到指定位置(大写E)
f, 将整数、浮点数转换成浮点数表示,并将其格式化到指定位置(默认保留小数点后6位)
F,同上
g,自动调整将整数、浮点数转换成 浮点型或科学计数法表示(超过6位数用科学计数法),并将其格式化到指定位置(如果是科学计数则是e;)
G,自动调整将整数、浮点数转换成 浮点型或科学计数法表示(超过6位数用科学计数法),并将其格式化到指定位置(如果是科学计数则是E;)
%,当字符串中存在格式化标志时,需要用 %%表示一个百分号
但是没有将整数转换成二进制功能。
1 print('%%%d'%5)
2 %5
1 print('------%c-----%o-------%x'%(65,15,15))
2 ------A-----17-------f
format函数初始化字符串:
[[fill]align][sign][#][0][width][,][.precision][type]
1 print('adad{0}adadada{0}dada{1}'.format(1,2))
2 adad1adadada1dada2
1 print('adad{name}adadada{age}'.format(name='OK',age=22))
2 adadOKadadada22
居中功能并用a填充宽度为10.
1 print('adad{name:a^10s}adadada{age}'.format(name='OK',age=22))
2 adadaaaaOKaaaaadadada22
左对齐<
1 print('adad{name:a<10s}adadada{age}'.format(name='OK',age=22))
2 adadOKaaaaaaaaadadada22
右对齐>
1 print('adad{name:a>10s}adadada{age}'.format(name='OK',age=22))
2 adadaaaaaaaaOKadadada22
转化百分比
print('this is {:%}'.format(0.2222))
this is 22.220000%
支持整数转化二进制输出:
1 print("---{0:d}----{0:b}---{0:o}--{1:%}".format(15,0.2))
2 ---15----1111---17--20.000000%
三:生成器和迭代器
具有生成一定条件数据的能力的对象叫做生成器。
具有取数据的能力叫做迭代器。
在进行处理大数据的时候,用生成器会降低内存的消耗,每一次取值生成一次,在下次取值的时候,内存会回收该值,避免了浪费内存。
其中filter函数和map函数返回的对象就是生成器。比如xrange函数返回的对象也是生成器。
1 a=[1,2,31,4]
2 f=filter(lambda a:a>3,a)
3
4 for i in f:
5 print(i)
6 print(f)
7 31
8 4
9
生成器本身由函数创造的,如何把普通的函数转成生成器呢?
如果函数体内包含关键字yield 时这个函数就是生成器。
1 def fun():
2 print(111)
3 yield 1
4 fun()
5 print(fun())
6
在调用函数的fun()时候并不执行函数。只有去取这个对象的时候进行生成。
1 def fun():
2 yield 1
3 yield 2
4 yield 3
5 fun()
6 for i in fun():
7 print('__%s'%i)
8 print(fun())
9 __1
10 __2
11 __3
12
当for循环执行时,执行函数体。第一次的时候,去函数func找yield 对应的值1 赋值给i输出,第二次从第一次的位置下一个的yield的值为2取值并赋值给i,直到取到所有的yield的结束循环。每一次取值生成对应的对象。
上面的函数fun是生成器而生成的结果fun()是迭代器,也就说对象具有可以被迭代,在迭代时候执行next方法取值,只能从前往后取值,
练习:基于生成器生成range功能。
1 def myrange(args):
2 st=0
3 while True:
4 if st >args:
5 return
6 yield st
7 st+=1
8 ret=myrange(9)
9 for i in ret:
10 print(i)
11 0
12 1
13 2
14 3
15 4
16 5
17 6
18 7
19 8
20 9
四:函数递归。执行本身的函数体,当满足一定条件退出,并把最后执行的结果返回给上个函数,如果没有条件限制会无限执行下去。
1 def fun(x):
2 x+=1
3 if x>3:
4 return 1
5 return fun(x)
6 t=fun(1)
7 print(t)
8 1
执行3次fun(x)函数。循环执行多次相同的函数体。
练习:实现累乘功能,比如输入3 实现3*2*1
1 def fun(x):
2 if x==1:
3 return 1
4 return x*fun(x-1)
5 print(fun(3))
6 6
五:模块
分类:内置模块、第三方模块、自定义模块。在python中叫模块其他语言叫类库。
使用模块:先import 导入后使用。
存在方式:.py文件。或者一个文件夹里有多个.py文件组成的一个模块。
自定义模块导入:
目录之间用.表示
如果同一级不通模块导入相同的方法该如何区分呢???
1:通过相对路径来区分
request模块调用上面的2个co模块。如果路径层级不多可以这么写 如果层级过多呢?调用次数过多呢?
1 import lib.co
2 import common.co
3 common.co.login()
4 lib.co.login()
5 common OK
6 lib OK
简单的方法 将导入的模块进行别名操作:
1 from lib import co as f1
2 from common import co as f2
3 f1.login()
4 f2.login()
5 lib OK
6 common OK
下面的方法是我们经常用的。
模块的意义:便于管理代码。不同的功能的代码进行归类。
模块导入的依据:
1 import sys
2 print(sys.path)
3 C:\python2\day6
4 C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32\python35.zip
5 C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32\DLLs
6 C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32\lib
7 C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32
8 C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32\lib\site-packages
sys.path是一个路径的列表。默认python 有限搜索当前py文件的目录依次搜索。所以当我们自定义模块时候可以有2种方式让python 找到我们定义的模块:
1:把自定义模块加入这个列表(append())
2:把自定义的模块加入上面的目录之中。
这样在导入模块的时候不会出现:ImportError: No module named 'xxx'
那怎么找出自己模块所在目录呢?
1 import os
2 print(os.path.abspath(__file__))
3 print(os.path.dirname(os.path.abspath(__file__)))
4 print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
5
6 C:\python2\day6\s2.py
7 C:\python2\day6
8 C:\python2
根据自己需求将自己的变量导入sys.path即可。
模块的名称:不要和系统的内置模块的名字冲突。
第三方模块:1:pip进行安装
2:源码进行安装。
安装第三方模块:requests
pip install requests
常用模块介绍:
json模块:
常用函数dums()、dum();loads()、load()
对于加s参数和不加s参数区别:
加s的是直接可以对python 的数据转换成json串(dums())或者直接将json串转换成python能识别的数据类型。而不加s的是将python的数据转换成json串并将json串写入文件中,或者将文件中的json串转换成python的基本数据。
1 data=[1,2,3,4,(1,2,True)]
2 obl=json.dumps(data)
3 with open('data.txt','w') as f1:
4 f1.write(obl)
5 [1, 2, 3, 4, [1, 2, true]]
如果需要写入需要操作文件才能写入。
1 data=[1,2,3,4,(1,2,True)]
2 obl=json.dumps(data)
3 t_load=json.loads(obl,encoding='utf8')
4 print(type(t_load),t_load)
5 [1, 2, 3, 4, [1, 2, True]]
在将python基本数据类型进行json转换的时候,会将python的一些数据类型或者相应的值进行转换,比如上面的python的元组转换json时候变为列表。True变为 true。
转换表如下:
跨语言平台常用该模块。该模块可以将python的基本数据类型(列表、字典)转换成字符串----序列化。也可以将字符串形式的python 类型字符创转换成对应的数据类型(列表、字典)--反序列化。
1 import json
2 list_1=[1,2,3,4,]
3 # json.dump(list_1,open('json.txt','w'))
4 obj=json.load(open('json.txt','r'))
5 print(obj)
6 [1, 2, 3, 4]
pickle模块:可以将非python数据类型的数据进行序列化和反序列化。存储方式是二进制。所以要以wb或者rb进行相关的dums和loads
1 import pickle
2 a='aa'
3 pickle.dump(bytes(a,encoding='utf-8'),open('pickle.txt','wb'))
pickle.dumps()将相应的数据类型转换成字节。如果不指定编码,python解释器会用默认编码进行处理。
1 import pickle
2 data=[1,2,3,4,(1,2,True)]
3 t=pickle.dumps(data)
4 print(t,type(t))
5 b'\x80\x03]q\x00(K\x01K\x02K\x03K\x04K\x01K\x02\x88\x87q\x01e.'
1 import pickle
2 a='aa'
3 # pickle.dump(bytes(a,encoding='utf-8'),open('pickle.txt','wb'))
4 t=pickle.load(open('pickle.txt','rb'))
5 s=str(t,encoding='utf-8')
6 print(s)
7 aa
import pickle
data=[1,2,3,4,(1,2,True)]
t=pickle.dumps(data)
t_load=pickle.loads(t)
print(t_load,type(t_load))
[1, 2, 3, 4, (1, 2, True)]
在Django中会用到经常用到pickle模块。
requests模块:属于第三方模块需要进行手动安装(pip install requests)
进入python安装目录:E:\python3.6\Scripts
运行:pip.exe install request
import requests
import json
res=requests.get("http://wthrcdn.etouch.cn/weather_mini?city=北京")
res.encoding='utf-8'
print(type(res))
dict_1=json.loads(res.text)
print(dict_1)