python 第五天
双层装饰器
#一个装饰器用另一个装饰器的功能
#一个函数用两个装饰器
#第三
#双层装饰器记法:
#---解释时从下往上解释
#---执行时从上到下执行
解释顺序:
1.将index函数传给check_admin,生成新的函数(即check_admin的inner),老index函数为check_admin的func
2.将check_admin函数传给check_login,生成新的函数(即check_login的inner),老的check_admin的inner变成了func
执行顺序:
1.执行check_login函数,判断成功后执行func即check_admin的inner函数
2.再执行check_admin的inner函数,判断成功后执行执行func即原始index函数
@check_login #第二次装饰,相当于在第一次装饰完成后用新生成的”新的index函数“又被创建了一个”新的index函数“
@check_admin #第一次装饰,相当于创建了一个 "新的index函数",是check_admin的inner函数体
def index():
print('index')
#双层装饰器程序
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:Minghu Wang
#判断登录
USER_INFO = {}
#USER_INFO['is_login']
#USER_INFO.get('is_login',None)
def check_login(func):
def inner(*args, **kwargs):
if USER_INFO.get('is_login',None): #如果is_login为真时,.get是判断is_login的values值不存在,返回None,即定位默认值
#.get 如果键值不存在,可定义第二个参数,返回None
ret = func(*args, **kwargs) #check_admin生成的”新的index“函数
return ret
else:
print('请登录') #没登录返回信息
return inner
#只判断管理,不判断登录
def check_admin(func):
def inner(*args, **kwargs):
if USER_INFO.get('user_type',None) == 2:
ret = func(*args, **kwargs) #原index函数
return ret
else:
print('无权限查看') #登录后,无权查看选项返回信息
return inner
#一个函数用两个装饰器,从下到上装饰
@check_login #第二次装饰,相当于在第一次装饰完成后用新生成的”新的index函数“又被创建了一个”新的index函数“
@check_admin #第一次装饰,相当于创建了一个 "新的index函数",是check_admin的inner函数体
def index():
print('index')
@check_login
def home():
print('home')
def login():
user = input('请输入用户名:')
if user == 'admin':
USER_INFO['is_login'] = True
USER_INFO['user_type'] = 2
else:
USER_INFO['is_login'] = True
USER_INFO['user_type'] = 1
def main():
while True:
inp = input('1,登录; 2,查看信息; 3,超级管理员管理 \n >>>')
if inp == '1':
login()
elif inp == '2':
home()
elif inp == '3':
index()
main()
字符串格式化
两种方法:format 和 %
% 常用字符串格式化
tpl = "i am %s" % "alex"
tpl = "i am %s age %d" % ("alex", 18)
tpl = "i am %(name)s age %(age)d" % {"name": "alex", "age": 18} #定义变量,以字典方式格式化
tpl = "percent %.2f" % 99.97623 #取小数点后两位
tpl = "i am %(pp).2f" % {"pp": 123.425556, } #把pp的key值传入,再取小数点后两位
tpl = "i am %.2f %%" % 123.425556 #取小数点后两位,取百分号,%%防转义
format字符常用方法
tpl = "i am {}, age {}, {}".format("seven", 18, 'alex') #{}为空占位符,随意传,按顺序参数
tpl = "i am {}, age {}, {}".format(*["seven", 18, 'alex']) #给列表加*是分别按顺序给占位符传值,不然会报错
tpl = "i am {0}, age {1}, really {0}".format("seven", 18) #{}占位符中指定索引号是为了传固定的值,不按顺序传,自由度高
tpl = "i am {0}, age {1}, really {0}".format(*["seven", 18]) #把列表传给{}占位符索引,用*分别传值
tpl = "i am {name}, age {age}, really {name}".format(name="seven", age=18) #{name} 占位符变量名,按变量名传值
tpl = "i am {name}, age {age}, really {name}".format(**{"name": "seven", "age": 18}) #{name} 占位符变量名,**以字典分别将key的value值传值
tpl = "i am {0[0]}, age {0[1]}, really {0[2]}".format([1, 2, 3], [11, 22, 33]) #{0[0]}占位符作用是以列表的索引的元素位值传值
tpl = "i am {:s}, age {:d}, money {:f}".format("seven", 18, 88888.1) #{:s}等以固定类型传值,{s:}字符串,{:d}数字,{:f}浮点型
tpl = "i am {:s}, age {:d}".format(*["seven", 18]) # * 星的作用是把列表值分别传给固定的类型
tpl = "i am {name:s}, age {age:d}".format(name="seven", age=18) #{name:s}等是以变量和固定类型限制传的值必须是固定类型
tpl = "i am {name:s}, age {age:d}".format(**{"name": "seven", "age": 18}) # ** 双星的作用是把字典的value值分别传入
tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2) #按{:b}二进制,{:o}八进制,{:d}十进制,{:x}十六进制,{:X}大写十六进制,{:%}百分比 传值
tpl = "numbers: {0:b},{0:o},{0:d},{0:x},{0:X}, {0:%}".format(15) #按索引传值,用各种进制和类型转换
tpl = "numbers: {num:b},{num:o},{num:d},{num:x},{num:X}, {num:%}".format(num=15) #指定变量num,按变量传值,用各种进制和类型转换
#左对齐减号 -10 包含字符长度
s = "asdf%(name) -10saaa %(age)-10d %(p).2f" %{'name':'alex','age': -123, "p": 1.236567}
print(s)
#进制转换 %s %c %x %g
s = "asdifuyaksdf %c ---- %o ===== %x ===== %g" %(65, 15, 15, 100)
print(s)
s1 = "alex %"
print(s1)
#当格式化时,字符串中出现占位符 %s.. 需要用 %% 输出 %
s2 = "alex %s %%" %('SB')
print(s2)
#根据索引号传值
s1 = "asdfasdf{0}a123{0}123{1}".format(123, "alex")
print(s1)
#固定类型格式化
s1 = "----{name:s}____{age:d}===={name:s}".format(name='alex', age=123)
print(s1)
#居中格式化
s2 = "----{:*^20s}====={:+d}===== {:x}".format('alex', 123, 15)
print(s2)
#取小数点后两位并带百分比
s3 = "asdfasdfasd {:.2%}".format(0.234567)
print(s3)
生成器 (yield)
出现yield 就是生成器
yield 控制顺序,保存上次执行的位置
生成器,本质就是yield控制位器,按顺序一个一个执行
程序1
def func():
print(1111)
yield 1
print(222)
yield 2
print(333)
yield 3
ret = func()
r1 = ret.__next__() #进入函数找到yield,获取yield后的数据,__next__ 一个一个拿yielld函数位的值
print(r1)
r2 = ret.__next__() #进入函数找到yield,获取yield后的数据
print(r2)
r3 = ret.__next__() #进入函数找到yield,获取yield后的数据
print(r3)
# r4 = ret.__next__() #进入函数找到yield,获取yield后的数据
# print(r4)
#自写range功能1
def myrange(arg):
start = 0
while True:
if start > arg:
return
yield start
start += 1
ret = myrange(3)
r = ret.__next__()
print(r)
r = ret.__next__()
print(r)
r = ret.__next__()
print(r)
r = ret.__next__()
print(r)
#自写range功能2
def myrange(arg):
start = 0
while True:
if start > arg:
return
yield start
start += 1
ret = myrange(3) #循环遍历四次(包括0)
for item in ret:
print(item)
函数嵌套调用
def d():
return '123'
def c():
r = d() #调用d函数
return r
def b():
r = c() #调用c函数
return r
def a():
r = b() #调用b函数
print(r)
a() #执行a函数,应该一层层找,打印123
递归函数
def func(n):
n += 1
print(n)
if n > 4:
return 'end'
return func(n) #这个return为了返回函数结果(end)
r = func(1)
print(r)
模块:
内置模块
自定义模块
第三方模块
为什么要有模块?
将代码归类
导入模块的依据
import sys
sys.path
模块
py:模块
其他:类库
先导入
后写入
sys.argv传参模块:
#a.py程序
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:Minghu Wang
import sys
print(sys.argv)
python a.py jkdsjf jfkdsjf jksfdjf
#函数调用(导入)
#目录结构
day5/
├── lib
│?? ├── commons.py
│?? └── __pycache__
│?? └── commons.cpython-35.pyc
├── __pycache__
│?? └── s4.cpython-35.pyc
├── s3.py #执行函数,调用s4.py、lib/commons.py
├── s4.py
└── s4.pyc
lib 目录下的
commons.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:Minghu Wang
def f1():
print("F1")
s4.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:Minghu Wang
def login():
print("login")
def logout():
print('logout')
执行函数
s3.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:Minghu Wang
import s4
import lib.commons
s4.login()
lib.commons.f1()
结果
login
F1
跨目录导模块
sys.path #导入模块先到sys.path的目录找
从上到下找,找不到就报错
在opt目创建脚本
vi /opt/outer.py
def aa():
print('wmh')
在任意目录创建脚本调用
#导入我的模块
vi /root/a.py
import sys
sys.path.append("/opt")
import outer
outer.aa()
执行a.py
python a.py
返回结果
wmh
#模块名称非常重要,不要和内置重名
#创建自己的模块不要和内置模块一样,不然只执行自己的,不执行内置的
import sys
print(sys.path)
#执行函数
s3.py
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:Minghu Wang
import lib.commons
from s4 import login #从s4.py模块 导入login函数
login() #直接执行
s4.login()
lib.commons.f1()
调用模块方法
from s4 import * #导入s4.py模块所有函数
from lib import commons #导入同级lib目录的commons.py模块
commons.f1()
#模块别名
from lib import commons1 as commons1
from lib import commons as commons2
#导入模块
单模块
使用 import
嵌套文件夹下
使用 from lib import commons #单独导入
from lib import commons as f1 #别名
#安装requests
#加环境变量
C:\Users\Administrator\AppData\Local\Programs\Python\Python35\Scripts
python3 -m pip install --upgrade pip
python3 -m pip install requests
import requests
序列化模块
json
json.dumps #将pyhton 基本数据类型转成字符串 (序列化)
json.loads #将python字符串形式转化成基本数据类型 (反序列化读)
使用方法
import json
import pickle
json使用dumps
a.py
import json
dic = {'k1':'v1'}
print(dic,type(dic))
result = json.dumps(dic) # dumps将pyhton 基本数据类型转成字符串形式
print(result,type(result))
返回结果
{'k1': 'v1'} <class 'dict'> #原为字典
{"k1": "v1"} <class 'str'> #dumps转后成为字符串类型
json使用loads
b.py
import json
s1= '{"k1":123}'
dic = json.loads(s1) # loads将python字符串形式转化成基本数据类型
print(dic,type(dic))
返回结果
{'k1': 123} <class 'dict'>
使用requests抓取页面字符,用json的loads转成字典打印
import json
import requests
response = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=北京')
response.encoding = 'utf-8'
print(response.text)
dic = json.loads(response.text) #response.text是request的用法,获取http内容
print(dic,type(dic))
注意点
import json
r = json.dumps([11,22,33])
li = '["alex","eric"]' #必须以单引在外,双引在内,不然报错
ret = json.loads(li) #通过loads反序列化时,一定要用""双引号
print(ret,type(ret))
#dump 将列表序列化写到文件
import json
li = [11,22,33]
json.dump(li,open('db','w')) #将列表序列化写到文件
#load 将文件反序列化读输出
import json
li = json.load(open('db','r')) #将文件反序列化读输出
print(type(li),li)
json / pickle 区别
json 更加适合跨语言,字符串基本数据类型
pickle 所有类型的序列化,仅适用pyhton,可以用于存储加密的程序
常用为对文件操作
pickle 序列化使用
#程序1
import pickle
li = [11,22,33]
r = pickle.dumps(li) #序列化成python专用类型,你不知道的类型,python专用
print(r)
result = pickle.loads(r) #将python 类型用loads载入反序列化输出
print(result)
#程序2
li = [11,22,33]
pickle.dump(li,open('db','wb')) #用dump方法以python特定写入到文件
result = pickle.load(open('db','rb')) #使用load反序列化载入输出
print(result,type(result))
time 和 datetime 模块使用
import time
import datetime
print(time.time()) #时间戳
print(time.ctime()) #当前时间
print(time.ctime(time.time()-86400)) #昨天
print(time.gmtime())
time_obj = time.gmtime()
print(time_obj)
print(time_obj.tm_year,time_obj.tm_mon) #取年、月
print(time.localtime()) #本地时间
print(time.mktime(time_obj)) #转成时间戳
#睡眠4秒
time.sleep(4)
print("------")
time.strftime("%Y-%m-%d %H:%M:%S",time.time())
print("-------")
tm = time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime())
print(tm)
tm = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
print(tm)
tm = time.strptime("2016-05-6","%Y-%m-%d")
print(tm)
tm = time.strptime("2016-05-6 15:06","%Y-%m-%d %H:%M")
print(tm)
tm = time.strptime("2016-05-6 15:06","%Y-%m-%d %H:%M") #字符串转成时间戳
print(time.mktime((tm)))
print(datetime.date.today())
print(datetime.date.fromtimestamp(time.time))
# time和datetime 使用
#_*_coding:utf-8_*_
import time #取时间戳
import datetime #取日期
print(time.clock()) #返回处理器时间,3.3开始已废弃
print(time.process_time()) #返回处理器时间,3.3开始已废弃
print(time.time()) #返回当前系统时间戳
print(time.ctime()) #输出Tue Jan 26 18:23:48 2016 ,当前系统时间
print(time.ctime(time.time()-86640)) #将时间戳转为字符串格式
print(time.gmtime(time.time()-86640)) #将时间戳转换成struct_time格式
print(time.localtime(time.time()-86640)) #将时间戳转换成struct_time格式,但返回 的本地时间
print(time.mktime(time.localtime())) #与time.localtime()功能相反,将struct_time格式转回成时间戳格式
#time.sleep(4) #sleep
#常用取时间日期
print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #将struct_time格式转成指定的字符串格式
print(time.strptime("2016-01-28","%Y-%m-%d") ) #将字符串格式转换成struct_time格式
#datetime module
print(datetime.date.today()) #输出格式 2016-01-26 ,取今天
print(datetime.date.fromtimestamp(time.time()-864400) ) #2016-01-16 将时间戳转成日期格式
#常用2
current_time = datetime.datetime.now() #
print(current_time) #输出2016-01-26 19:04:30.335935
print(current_time.timetuple()) #返回struct_time格式
#datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]])
print(current_time.replace(2014,9,12)) #输出2014-09-12 19:06:24.074900,返回当前时间,但指定的值将被替换
str_to_date = datetime.datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M") #将字符串转换成日期格式
new_date = datetime.datetime.now() + datetime.timedelta(days=10) #比现在加10天
new_date = datetime.datetime.now() + datetime.timedelta(days=-10) #比现在减10天
new_date = datetime.datetime.now() + datetime.timedelta(hours=-10) #比现在减10小时
new_date = datetime.datetime.now() + datetime.timedelta(seconds=120) #比现在+120s
print(new_date)
时间博客
http://www.cnblogs.com/alex3714/articles/5161349.html
时间比较判断
import time
import datetime
#时间比较判断
current_time = datetime.datetime.now()
time_obj = current_time.replace(2015,5)
print(current_time==time_obj)
logging模块
debug(), info(), warning(), error() and critical() 5个级别
最简单用法
import logging
logging.warning("user [alex] attempted wrong password more than 3 times")
logging.critical("server is down")
#输出
WARNING:root:user [alex] attempted wrong password more than 3 times
CRITICAL:root:server is down
----Level------------------级别----------------------------------
DEBUG 详细信息,综合诊断 级别最低
INFO 工作状态信息
WARNING 异常警报,突发事件
ERROR 严重错误,功能失效
CRITICAL 严重错误,突然中断,不能继续运行
日志写到文件里
#level=loggin.INFO 把日志纪录级别设置为INFO,INFO或比INFO级别更高写入文件
#所以 debug信息不写入,因为级别低于info,如果想写,改level=logging.DEBUG即可
import logging
logging.basicConfig(filename='example.log',level=logging.INFO)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
记录时间日志
import logging
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%Y/%m/%d %I:%M:%S %p')
logging.warning('is when this event was logged.')
终端和文件同时写需要学习的组件
logging库提供了多个组件:Logger、Handler、Filter、Formatter。
Logger 对象提供应用程序可直接使用的接口,
Handler 发送日志到适当的目的地,
Filter 提供了过滤日志信息的方法,
Formatter 指定日志显示格式。
打印到终端同时写入到文件程序
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Author:Minghu Wang
import logging
#创建logger
logger = logging.getLogger('TEST-LOG') #创建一个logger
logger.setLevel(logging.DEBUG) #配置级别
#定义输出到终端
ch = logging.StreamHandler() #创建handler,用于输出到终端
ch.setLevel(logging.DEBUG) #配置输出终端日志级别
#定义输出到文件
fh = logging.FileHandler("access.log") #创建一个handler,用于写入日志文件
fh.setLevel(logging.WARNING) #配置写入文件日志级别
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #定义handler的输出格式formatter
#定义日志输出格式
ch.setFormatter(formatter) #以formatter定义的格式输出到终端
fh.setFormatter(formatter) #以formatter定义的格式写入到文件
#加载到handler
logger.addHandler(ch) #将定义的 ch 日志输出功能添加到handler
logger.addHandler(fh) #将定义的 fh 日志输出功能添加到handler
#给日志级别定义内容,并应用
logger.debug('debug message') #给日志级别定义内容,并应用
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
结果
2016-06-08 15:54:30,973 - TEST-LOG - DEBUG - debug message
2016-06-08 15:54:30,973 - TEST-LOG - INFO - info message
2016-06-08 15:54:30,973 - TEST-LOG - WARNING - warn message
2016-06-08 15:54:30,974 - TEST-LOG - ERROR - error message
2016-06-08 15:54:30,974 - TEST-LOG - CRITICAL - critical message