首页 > 代码库 > Python学习记录day5
Python学习记录day5
title: Python学习记录day5
tags: python
author: Chinge Yang
date: 2016-11-26
1.多层装饰器
多层装饰器的原理是装饰器装饰函数后其实也是一个函数这样又可以被装饰器装饰。 编译是从下至上进行的执行时是从上至下进行。
#!/usr/bin/env python
# _*_coding:utf-8_*_
‘‘‘
* Created on 2016/11/29 20:38.
* @author: Chinge_Yang.
‘‘‘
USER_INFO = {}
# USER_INFO[‘is_login‘] = True
# USER_INFO[‘user_type‘] = 2
def check_login(func):
def inner(*args, **kwargs):
if USER_INFO.get("is_login", None):
ret = func(*args, **kwargs)
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)
return ret
else:
print(‘无权限查看‘)
return inner
@check_login
@check_admin
def index():
"""
管理员的功能
:return:
"""
print(‘Index‘)
@check_login
def home():
"""
普通用户功能
:return:
"""
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()
elif inp == "q":
exit()
main()
2.字符串格式化
Python的字符串格式化有两种方式: 百分号方式、format方式
百分号的方式相对来说比较老而format方式则是比较先进的方式企图替换古老的方式目前两者并存。[PEP-3101]
This PEP proposes a new system for built-in string formatting operations, intended as a replacement for the existing ‘%’ string formatting operator.
1.百分号方式
%[(name)][flags][width].[precision]typecode
- (name) 可选用于选择指定的key
- flags 可选可供选择的值有:
+ 右对齐正数前加正好负数前加负号
- 左对齐正数前无符号负数前加负号
空格 右对齐正数前加空格负数前加负号
0 右对齐正数前无符号负数前加负号用0填充空白处 - width 可选占有宽度
- .precision 可选小数点后保留的位数
- typecode 必选
s获取传入对象的__str__方法的返回值并将其格式化到指定位置
r获取传入对象的__repr__方法的返回值并将其格式化到指定位置
c整数将数字转换成其unicode对应的值10进制范围为 0 <= i <= 1114111py27则只支持0-255字符将字符添加到指定位置
o将整数转换成 八 进制表示并将其格式化到指定位置
x将整数转换成十六进制表示并将其格式化到指定位置
d将整数、浮点数转换成 十 进制表示并将其格式化到指定位置
E将整数、浮点数转换成科学计数法并将其格式化到指定位置大写E
f 将整数、浮点数转换成浮点数表示并将其格式化到指定位置默认保留小数点后6位
F同上
g自动调整将整数、浮点数转换成浮点型或科学计数法表示超过6位数用科学计数法并将其格式化到指定位置如果是科学计数则是e
G自动调整将整数、浮点数转换成浮点型或科学计数法表示超过6位数用科学计数法并将其格式化到指定位置如果是科学计数则是E
%当字符串中存在格式化标志时需要用 %%表示一个百分号
注Python中百分号格式化是不存在自动将整数转换成二进制表示的方式
常用格式化
tpl = "i am %s" % "ygqygq2"
tpl = "i am %s age %d" % ("ygqygq2", 27)
tpl = "i am %(name)s age %(age)d" % {"name": "ygqgyq2", "age": 27}
tpl = "percent %.2f" % 99.97623
tpl = "i am %(pp).2f" % {"pp": 123.425556, }
tpl = "i am %.2f %%" % {"pp": 123.425556, }
2.Format方式
[[fill]align][sign][#][0][width][,][.precision][type]
- fill 【可选】空白处填充的字符
- align 【可选】对齐方式需配合width使用
<内容左对齐
>内容右对齐(默认)
内容右对齐将符号放置在填充字符的左侧且只对数字类型有效。即使符号+填充物+数字
^内容居中
sign 【可选】有无符号数字
+正号加正负号加负
-正号不变负号加负
空格 正号空格负号加负
# 【可选】对于二进制、八进制、十六进制如果加上#会显示0b/0o/0x否则不显示
【可选】为数字添加分隔符如1,000,000
width 【可选】格式化位所占宽度
.precision 【可选】小数位保留精度
type 【可选】格式化类型
传入” 字符串类型 “的参数
s格式化字符串类型数据
空白未指定类型则默认是None同s
传入“ 整数类型 ”的参数
b将10进制整数自动转换成2进制表示然后格式化
c将10进制整数自动转换为其对应的unicode字符
d十进制整数
o将10进制整数自动转换成8进制表示然后格式化
x将10进制整数自动转换成16进制表示然后格式化小写x
X将10进制整数自动转换成16进制表示然后格式化大写X
传入“ 浮点型或小数类型 ”的参数
e 转换为科学计数法小写e表示然后格式化
E 转换为科学计数法大写E表示然后格式化;
f 转换为浮点型默认小数点后保留6位表示然后格式化
F 转换为浮点型默认小数点后保留6位表示然后格式化
g 自动在e和f中切换
G 自动在E和F中切换
%显示百分比默认显示小数点后6位
常用格式化
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)
tpl = "i am {name}, age {age}, really {name}".format(**{"name": "seven", "age": 18})
tpl = "i am {0[0]}, age {0[1]}, really {0[2]}".format([1, 2, 3], [11, 22, 33])
tpl = "i am {:s}, age {:d}, money {:f}".format("seven", 18, 88888.1)
tpl = "i am {:s}, age {:d}".format(*["seven", 18])
tpl = "i am {name:s}, age {age:d}".format(name="seven", age=18)
tpl = "i am {name:s}, age {age:d}".format(**{"name": "seven", "age": 18})
tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
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)
更多格式化操作https://docs.python.org/3/library/string.html
3.迭代器和生成器
1.迭代器
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问直到所有的元素被访问完结束。迭代器只能往前不会后退不过这也没什么因为人们很少在迭代途中往后退。另外迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素而在这之前或之后元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合比如几个G的文件
特点
访问者不需要关心迭代器内部的结构仅需通过next()方法不断去取下一个内容
不能随机访问集合中的某个值 只能从头到尾依次访问
访问到一半时不能往回退
便于循环比较大的数据集合节省内存
>>> a = iter([1,2,3,4,5])
>>> a
<list_iterator object at 0x101402630>
>>> a.__next__()
1
>>> a.__next__()
2
>>> a.__next__()
3
>>> a.__next__()
4
>>> a.__next__()
5
>>> a.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
2.生成器
一个函数调用时返回一个迭代器那这个函数就叫做生成器generator如果函数中包含yield语法那这个函数就会变成生成器
def func():
print(11)
yield 1
print(22)
yield 2
print(33)
yield 3
print(44)
yield 4
上述代码中func是函数称为生成器当执行此函数func()时会得到一个迭代器。
>>> temp = func()
>>> temp.__next__()
11
1
>>> temp.__next__()
22
2
>>> temp.__next__()
33
3
>>> temp.__next__()
44
4
>>> temp.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
4.函数递归
在函数内部可以调用其他函数。如果一个函数在内部调用自身本身这个函数就是递归函数。
def func(n):
n += 1
if n >= 4:
return "end"
return func(n)
res = func(1)
print(res)
递归函数的优点是定义简单逻辑清晰。理论上所有的递归函数都可以写成循环的方式但循环的逻辑不如递归清晰。
使用递归函数需要注意防止栈溢出。
详细请看廖雪峰的官方网站中递归函数
5.模块
为了编写可维护的代码我们把很多函数分组分别放到不同的文件里这样每个文件包含的代码就相对较少很多编程语言都采用这种组织代码的方式。在Python中一个.py文件就称之为一个模块Module。
模块分为三种
* 自定义模块
* 第三方模块
* 内置模块
1.使用模块有什么好处
1. 最大的好处是大大提高了代码的可维护性。
2. 使用模块还可以避免函数名和变量名冲突。
2.导入模块
单模块import
嵌套在文件夹下
from xxx import xxx
from xxx import as ooo
3.第三方模块
pip3安装pip安装
pip3 install requests
源码安装
curl -OL https://github.com/kennethreitz/requests/tarball/master
解压后进入目录
python setup.py install
6.序列化
Python中用于序列化的两个模块
- json 用于【字符串】和【python基本数据类型】间进行转换
- pickle 用于【python特有的类型】和【python基本数据类型】间进行转换
Json模块提供了四个功能dumps、dump、loads、load
pickle模块提供了四个功能dumps、dump、loads、load
json相关用法
import json
dict = {‘k1‘: ‘v1‘}
print(dict, type(dict))
# 将python基本数据类型转换成字符串形式
res = json.dumps(dict)
print(res, type(res))
{‘k1’: ‘v1’} <class ‘dict’>
{“k1”: “v1”} <class ‘str’>
import json
# 将python字符串形式转换成基本数据类型
s1 = ‘{"k1": 123}‘
dict = json.loads(s1) # 反序列化时一定要使用 ""
print(dict, type(dict))
{‘k1’: 123} <class ‘dict’>
import json
li = [11,22,33]
json.dump(li,open(‘test.txt‘,‘w‘))
li = json.load(open(‘test.txt‘,‘r‘))
print(type(li),li)
pickle相关用法
import pickle
li = [11,22,33]
r = pickle.dumps(li)
print(r)
res = pickle.loads(r)
print(res)
b’\x80\x03]q\x00(K\x0bK\x16K!e.’
[11, 22, 33]
li = [11,22,33]
pickle.dump(li, open(‘test4.txt‘, ‘wb‘))
res = pickle.load(open(‘test4.txt‘, ‘rb‘))
print(res)
[11, 22, 33]
json和pickle对比
1. json更适合跨语言字符串基本数据类型
2. pickle更适合python所有类型的序列化操作
7.time & datetime模块
#_*_coding:utf-8_*_
__author__ = ‘Alex Li‘
import time
# print(time.clock()) #返回处理器时间,3.3开始已废弃 , 改成了time.process_time()测量处理器运算时间,不包括sleep时间,不稳定,mac上测不出来
# print(time.altzone) #返回与utc时间的时间差,以秒计算\
# print(time.asctime()) #返回时间格式"Fri Aug 19 11:14:16 2016",
# print(time.localtime()) #返回本地时间 的struct time对象格式
# print(time.gmtime(time.time()-800000)) #返回utc时间的struc时间对象格式
# print(time.asctime(time.localtime())) #返回时间格式"Fri Aug 19 11:14:16 2016",
#print(time.ctime()) #返回Fri Aug 19 12:38:29 2016 格式, 同上
# 日期字符串 转成 时间戳
# string_2_struct = time.strptime("2016/05/22","%Y/%m/%d") #将 日期字符串 转成 struct时间对象格式
# print(string_2_struct)
# #
# struct_2_stamp = time.mktime(string_2_struct) #将struct时间对象转成时间戳
# print(struct_2_stamp)
#将时间戳转为字符串格式
# print(time.gmtime(time.time()-86640)) #将utc时间戳转换成struct_time格式
# print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #将utc struct_time格式转成指定的字符串格式
#时间加减
import datetime
# print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925
#print(datetime.date.fromtimestamp(time.time()) ) # 时间戳直接转成日期格式 2016-08-19
# print(datetime.datetime.now() )
# print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间+3天
# print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天
# print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时
# print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分
#
# c_time = datetime.datetime.now()
# print(c_time.replace(minute=3,hour=2)) #时间替换
8.logging模块
很多程序都有记录日志的需求并且日志中包含的信息即有正常的程序访问日志还可能有错误、警告等信息输出python的logging模块提供了标准的日志接口你可以通过它存储各种格式的日志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 | When it’s used |
---|---|
DEBUG | Detailed information, typically of interest only when diagnosing problems. |
INFO | Confirmation that things are working as expected. |
WARNING | An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected. |
ERROR | Due to a more serious problem, the software has not been able to perform some function. |
CRITICAL | A serious error, indicating that the program itself may be unable to continue running. |
如果想把日志写到文件里也很简单
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‘)
其中下面这句中的level=loggin.INFO意思是把日志纪录级别设置为INFO也就是说只有比日志是INFO或比INFO级别更高的日志才会被纪录到文件里在这个例子 第一条日志是不会被纪录的如果希望纪录debug的日志那把日志级别改成DEBUG就行了。
logging.basicConfig(filename=‘example.log‘,level=logging.INFO)
感觉上面的日志格式忘记加上时间啦日志不知道时间怎么行呢下面就来加上!
import logging
logging.basicConfig(format=‘%(asctime)s %(message)s‘, datefmt=‘%m/%d/%Y %I:%M:%S %p‘)
logging.warning(‘is when this event was logged.‘)
12/12/2010 11:46:36 AM is when this event was logged.
日志格式
%(name)s | Logger的名字 |
---|---|
%(levelno)s | 数字形式的日志级别 |
%(levelname)s | 文本形式的日志级别 |
%(pathname)s | 调用日志输出函数的模块的完整路径名可能没有 |
%(filename)s | 调用日志输出函数的模块的文件名 |
%(module)s | 调用日志输出函数的模块名 |
%(funcName)s | 调用日志输出函数的函数名 |
%(lineno)d | 调用日志输出函数的语句所在的代码行 |
%(created)f | 当前时间用UNIX标准的表示时间的浮 点数表示 |
%(relativeCreated)d | 输出日志信息时的自Logger创建以 来的毫秒数 |
%(asctime)s | 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 |
%(thread)d | 线程ID。可能没有 |
%(threadName)s | 线程名。可能没有 |
%(process)d | 进程ID。可能没有 |
%(message)s | 用户输出的消息 |
如果想同时把log打印在屏幕和文件日志里就需要了解一点复杂的知识 了
Python 使用logging模块记录日志涉及四个主要类使用官方文档中的概括最为合适
1. logger提供了应用程序可以直接使用的接口
2. handler将(logger创建的)日志记录发送到合适的目的输出
3. filter提供了细度设备来决定输出哪条日志记录
4. formatter决定日志记录的最终输出格式。
logger
每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名比如聊天工具的图形界面模块可以这样获得它的Logger
LOG=logging.getLogger(”chat.gui”)
而核心模块可以这样
LOG=logging.getLogger(”chat.kernel”)
Logger.setLevel(lel):指定最低的日志级别低于lel的级别将被忽略。debug是最低的内置级别critical为最高
Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr)增加或删除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()可以设置的日志级别
handler
handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台有些Logger可以把信息输出到文件还有些 Handler可以把信息发送到网络上。如果觉得不够用还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler
Handler.setLevel(lel):指定被处理的信息级别低于lel级别的信息将被忽略
Handler.setFormatter()给这个handler选择一个格式
Handler.addFilter(filt)、Handler.removeFilter(filt)新增或删除一个filter对象
每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler
- logging.StreamHandler
使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是
StreamHandler([strm])
其中strm参数是一个文件对象。默认是sys.stderr - logging.FileHandler
和StreamHandler类似用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是
FileHandler(filename[,mode])
filename是文件名必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a’即添加到文件末尾。 - logging.handlers.RotatingFileHandler
这个Handler类似于上面的FileHandler但是它可以管理文件大小。当文件达到一定大小之后它会自动将当前日志文件改名然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后RotatingFileHandler自动把 文件改名为chat.log.1。不过如果chat.log.1已经存在会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log继续输出日志信息。它的构造函数是
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode两个参数和FileHandler一样。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0意味着日志文件可以无限大这时上面描述的重命名过程就不会发生。
backupCount用于指定保留的备份文件的个数。比如如果指定为2当上面描述的重命名过程发生时原有的chat.log.2并不会被更名而是被删除。 - logging.handlers.TimedRotatingFileHandler
这个Handler和RotatingFileHandler类似不过它没有通过判断文件大小来决定何时重新创建日志文件而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似不过新的文件不是附加数字而是当前时间。它的构造函数是
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位不区分大小写。它有以下取值
S 秒
M 分
H 小时
D 天
W 每星期interval==0时代表星期一
midnight 每天凌晨
import logging
#create logger
logger = logging.getLogger(‘TEST-LOG‘)
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# create file handler and set level to warning
fh = logging.FileHandler("access.log")
fh.setLevel(logging.WARNING)
# create formatter
formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘)
# add formatter to ch and fh
ch.setFormatter(formatter)
fh.setFormatter(formatter)
# add ch and fh to logger
logger.addHandler(ch)
logger.addHandler(fh)
# ‘application‘ code
logger.debug(‘debug message‘)
logger.info(‘info message‘)
logger.warn(‘warn message‘)
logger.error(‘error message‘)
logger.critical(‘critical message‘)
import logging
from logging import handlers
logger = logging.getLogger(__name__)
log_file = "timelog.log"
#fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3)
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3)
formatter = logging.Formatter(‘%(asctime)s %(module)s:%(lineno)d %(message)s‘)
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.warning("test1")
logger.warning("test12")
logger.warning("test13")
logger.warning("test14")
本文出自 “ygqygq2” 博客,转载请与作者联系!
Python学习记录day5