学习python_day5

本节内容:

  • 常用的几个内置函数
  • 列表生成式
  • 迭代器
  • 生成器
  • 软件目录结构规范
  • 常用的模块

一、几个内置函数

# a= [0,1,2,3,4,5,6,7,8,9]
# #取a中大于5的 filter 对值进行操作
# filter(lambda x:x>6,a)
# b=filter(lambda x:x>6,a)
# for i in b:
#     print(i)
# #map 对操作运算结果进行操作
# c=map(lambda x:x*x,a)
# for i in c:
#     print(i)
# #如果是对值进行判断只会返回True or False
# c=map(lambda x:x>6,a)
# for i in c:
#     print(i)
# from functools import reduce
# d = reduce(lambda x,y:x+y,a)#reduce 需要两个参数,第一次循环先把a中的0赋给x,1赋给y然后计算结果,
# # 然后把结果再赋给x,在把2赋给y,在计算结果,然后把结果赋给x 再把3 赋给y 依次类推
# print(d)
# #eval()把字符串形式的表达式 解析并执行 b = "1+4/2" eval(b)
# # exec 把字符串形式的代码,解析并执行
# # compile()把一个代码问价加载进来,按 exec 或eval的方式解析执行

#print()
# import time
# for i in range(10):
#     time.sleep(1)
#     print("#",end="",flush=True)

 

二、列表生成式

现在有一需求,把列表[0,1,2,3,4,5,6,7,8,9]中的每个值都加1,怎么实现

a= [0,1,3,4,5,6,7,8,9]
b = []
for i in a :
    b.append(i+1)
a= b
print(a)
for index, i in enumerate(a):
    a[index]+=1
print(a)
a= [0,1,2,3,4,5,6,7,8,9]
a=map(lambda x:x+1,a)
for i in a:
    print(i)

还有一种方法

a= [i+1 for i in range(10)]
b= [i+1 if i >5 else i for i in range(10)]
print(a)

这种叫列表生成

三、生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

>>> L = [i*i for i in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g =(i*i for i in range(10))
>>> g
<generator object <genexpr> at 0x02C25780>
>>> 

创建Lg的区别仅在于最外层的[]()L是一个list,而g是一个generator。

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

如果要一个一个打印出来,可以通过next()函数获得generator的下一个返回值:

>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
....

我们讲过,generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

当然,上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:

>>> g =(i*i for i in range(10))
>>> for i in g:print(i)

0
1
4
9
16
25
36
49
64
81
>>> 

所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

def fib(number):
    n,a,b = 0,0,1
    while n <number:
        print(b)
        a,b=b,a+b
        n+=1
fib(10)
1
1
2
3
5
8
13
21
34
55

可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

1 def fib(number):
2     n,a,b = 0,0,1
3     while n <number:
4         # print(b)
5         yield b
6         a,b=b,a+b
7         n+=1

这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:

f = fib(10)
print(f)
<generator object fib at 0x005AB090>

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,相当于函数中的return ,再次执行时从上次返回的yield语句处继续执行。生成器yield 保存了函数的中断状态

f = fib(10)
print(f)
print(f.__next__())
print(f.__next__())
print(f.__next__())
print("干点别的事")
print(f.__next__())
print(f.__next__())
print(f.__next__())
#输入的结果:
<generator object fib at 0x0063B0C0>
1
1
2
干点别的事
3
5
8

在上面fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。

同样的,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:

for i in fib(10):
    print(i)
#输出:
1
1
2
3
5
8
13
21
34
55

还可通过yield实现在单线程的情况下实现并发运算的效果:

import time
def consumer(name):
    print("%s 准备吃包子了"%name)
    while True:
        baozi=yield #保存函数的中断状态,可以接受传进来的值,(遇到yield说明它就是个生成器,调用next()才能执行)
                    #接收到producer send过来的包子,并赋值给包子变量
        print("包子[%s]来了,被[%s]吃了"%(baozi,name))
def producer(name):
    c = consumer("A")
    c2= consumer("B")
    c.__next__()
    c2.__next__()
    print("老子开始做包子了")
    for i in range(10):
        time.sleep(1)
        print("做了2个包子")
        c.send(i) #唤醒生成器并传值(调用next 并传了一个值给yield)
        c2.send(i)
producer("alex")

四、迭代器
我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

可以使用isinstance()判断一个对象是否是Iterable对象:

1
2
3
4
5
6
7
8
9
10
11
>>>  from  collections import Iterable
>>>  isinstance ([], Iterable)
True
>>>  isinstance ({}, Iterable)
True
>>>  isinstance ( 'abc' , Iterable)
True
>>>  isinstance ((x  for  x in range(10)), Iterable)
True
>>>  isinstance ( 100 , Iterable)
False

 而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

可以使用isinstance()判断一个对象是否是Iterator对象:

1
2
3
4
5
6
7
8
9
>>>  from  collections import Iterator
>>>  isinstance ((x  for  x in range(10)), Iterator)
True
>>>  isinstance ([], Iterator)
False
>>>  isinstance ({}, Iterator)
False
>>>  isinstance ( 'abc' , Iterator)
False

 生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

1
2
3
4
>>>  isinstance ( iter ([]), Iterator)
True
>>>  isinstance ( iter ( 'abc' ), Iterator)
True

你可能会问,为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

五、常用的几个模块

模块,用一砣代码实现了某个功能的代码集合。 

类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合。而对于一个复杂的功能来,可能需要多个函数才能完成(函数又可以在不同的.py文件中),n个 .py 文件组成的代码集合就称为模块。

如:os 是系统相关的模块;file是文件操作相关的模块

模块分为三种:

  • 自定义模块
  • 内置标准模块(又称标准库)
  • 开源模块

time 和datetime

import time

print(time.time())#时间戳 距离计算机系统诞生元年的时间单位s (1970.1.1)
# 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对象格式
t = time.localtime()
print(t.tm_year,t.tm_mon,t.tm_mday) #可以定制的显示时间
# 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 格式, 同上

print(time.strftime("%Y-%m-%d %H:%M:%S"))#自定义时间格式
struct_time = time.localtime(time.time() - 86400)
print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time)) #显示前一天的时间

# 日期字符串 转成  时间戳
# 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)) #时间替换
 
DirectiveMeaningNotes
%aLocale’s abbreviated weekday name. 
%ALocale’s full weekday name. 
%bLocale’s abbreviated month name. 
%BLocale’s full month name. 
%cLocale’s appropriate date and time representation. 
%dDay of the month as a decimal number [01,31]. 
%HHour (24-hour clock) as a decimal number [00,23]. 
%IHour (12-hour clock) as a decimal number [01,12]. 
%jDay of the year as a decimal number [001,366]. 
%mMonth as a decimal number [01,12]. 
%MMinute as a decimal number [00,59]. 
%pLocale’s equivalent of either AM or PM.(1)
%SSecond as a decimal number [00,61].(2)
%UWeek number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0.(3)
%wWeekday as a decimal number [0(Sunday),6]. 
%WWeek number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0.(3)
%xLocale’s appropriate date representation. 
%XLocale’s appropriate time representation. 
%yYear without century as a decimal number [00,99]. 
%YYear with century as a decimal number. 
%zTime zone offset indicating a positive or negative time difference from UTC/GMT of the form +HHMM or -HHMM, where H represents decimal hour digits and M represents decimal minute digits [-23:59, +23:59]. 
%ZTime zone name (no characters if no time zone exists). 
%%A literal '%' character.

 

 random 模块

import  random
print(random.randint(1,10)) #生成随机数
print(random.randrange(1,10))#同上,只不过生成的随机数不包含10
print(random.randrange(1,20,2))#可以加步长
print(random.sample([1,2,3,4,5],2)) #可以随机取两个数
print(random.sample(range(100),2))

生成随机验证码:

import random
chek_code = ""
for i in range(4):
    current=random.randrange(0,4)
    if current != i:
        tem = chr(random.randint(65,90))
    else:
        tem = random.randint(0,9)
    chek_code += str(tem)
print(chek_code)

另一种方法:

1 import random,string
2 print(string.ascii_letters) #显示所有大小写字母
3 print(string.ascii_lowercase)#显示所有小写字母
4 print(string.ascii_uppercase)#显示所有大写字母
5 print(string.digits) #显示0-9的所有数字
6 source = string.digits + string.ascii_uppercase
7 print("".join(random.sample(source,6)))

 pickle&json模块

pickle模块

import pickle
#写到文件时
account = {
    "id":12324,
    "credit":15000,
    "banlance":8000
}
f = open("account","wb")
# f.write(account)
f.write(pickle.dumps(account)) #是以bytes格式写的所以打开问件时要以“wb”的方式
#pickle.dump(account,f)同上
f.close()
import pickle
#读到内存时
f= open("account","rb")
account = pickle.loads(f.read()) # 等同于account = pickle.load(f)
print(account)
print(account["id"])

json模块
json的用法和pickle完全相同只是在写到文件时是以str字符串的形式而不是bytes

pickle是python解释器自己可以把内存中所有的数据类型转到硬盘,而json是大多数语言通用的支持的数据类型:srt,int,list,set,dict,tuple

小结:用于序列化的工具:pickle和json同时提供了四个功能:dumps、dump、loads、load

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

如果想把日志写到文件里,也很简单

import logging
logging.basicConfig(filename='example.log', level=logging.INFO) #example,log 日志的文件名 logging.debug('This message should not go to the log file') logging.info('So should this') logging.warning('And this, too') #输出 INFO:root:So should this WARNING:root:And this, too

其中下面这句中的level=loggin.INFO意思是,把日志纪录级别设置为INFO,也就是说,只有比日志是INFO或比INFO级别更高的日志才会被纪录到文件里,在这个例子, 第一条日志是不会被纪录的,如果希望纪录debug的日志,那把日志级别改成DEBUG就行了。

日志记录加上日期时间

import logging
logging.basicConfig(filename='example.log',
                    level=logging.INFO,
                    format="%(asctime)s %(message)s",
                    datefmt='%m/%d/%Y %I:%M:%S %p'
                    )
logging.debug('This message should not go to the log file')
logging.info('So should this')
logging.warning('And this, too')
###shuchu 
02/23/2017 04:16:57 PM So should this
02/23/2017 04:16:57 PM And this, too

 日志格式

%(name)sLogger的名字
%(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模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:

logger提供了应用程序可以直接使用的接口;

handler将(logger创建的)日志记录发送到合适的目的输出;

filter提供了细度设备来决定输出哪条日志记录;

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:
1) logging.StreamHandler
使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
StreamHandler([strm])
其中strm参数是一个文件对象。默认是sys.stderr


2) logging.FileHandler
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
FileHandler(filename[,mode])
filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。

3) 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并不会被更名,而是被删除。


4) 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")

 

转载于:https://www.cnblogs.com/plc-python/p/6420641.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值