Python运维开发从入门到精通学习 Day4
目录
Day 4 本节内容:
一、生成器(只有被调用时才会生成对应数据;将函数创建为生成器可以随时中断函数,去同时做一些其他的功能,然后再进入函数继续执行。)
1.列表生成式
2.生成器定义
3.生成器创建方法1:
4.生成器创建方法2:
5.生成器用例:通过yield实现在单线程的情况下实现并发运算的效果,异步IO
6.额外知识点:异常处理中try,except用法。
二、迭代器(可以被next()函数调用并不断返回下一个值的对象称为迭代器,生成器也是一个迭代器)
1.定义
2.小结
三、装饰器(不修改被装饰函数的源代码和调用方式,实现附加功能的添加)
1.定义:
2.原则:函数感知不到装饰器的存在
3.实现装饰器知识点:1.函数即变量 2.高阶函数 3.嵌套函数
四、内置函数
五、json & pickle数据序列化
1.序列化与反序列化定义,及json和pickle的使用
2.json与pickle的区别(属性用法一致)
六、软件目录结构规范
七、作业:
Day 4 本节内容:
1.迭代器 & 生成器
2.装饰器
3.内置函数
4.json & pickle数据序列化
5.软件目录结构规范
6.作业:ATM项目开发
一、生成器(只有被调用时才会生成对应数据;将函数创建为生成器可以随时中断函数,去同时做一些其他的功能,然后再进入函数继续执行。)
1.列表生成式
#使用列表生成式创建列表 [2,4,6,8,10]
# 方式1.
list1 = [a * 2 for a in range(1,6)]
print(list1)# 方式2.
def functest(num):b = 2return(num * b)
list2 = [functest(a) for a in range(1,6)]
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,直接创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
2.生成器定义
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
列表表达式:直接把列表所有元素全部生成;
生成器:1.只有在调用时才会生成对应数据
2.只记录当前位置,不可取前面过去的数据
3.只有一个 __next__() 方法,用来获取下一个数据;python2中为 next()
3.生成器创建方法1:
只要把一个列表生成式的[]
改成()
,就创建了一个generator:
# 创建生成器
generator = (a * 2 for a in range(1,6))
print(generator) # <generator object <genexpr> at 0x00000190A44D94A0># 调用生成器
generator.__next__() # 第一次调用,值为2,但是不会输出
print(generator.__next__()) # 第二次调用,输出4
print('hello') # hello
for i in generator:print(i) # 输出 6 8 10,因为生成器只记录当前位置,不会重新调用
4.生成器创建方法2:
如果一个函数定义中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator。将函数变为生成器的好处,可以随时中断函数(去同时做一些其他的功能)然后再进入函数继续执行。
def func():for n in range(1,4):print('hello')yieldprint(f'你好这是生成器{n}')gener = func()
gener.__next__()
gener.__next__()
gener.__next__()# 执行逻辑
1. def func() 定义函数
2. gener = func() 创建生成器gener
3. gener.__next__() # n=1;---输出“hello”;---遇到yield中断退出
4. gener.__next__() # 返回继续执行生成器;---输出“你好这是生成器1”;---n=2;---输出“hello”;---遇到yield中断退出
5. gener.__next__() # 返回继续执行生成器;---输出“你好这是生成器2”;---n=3;---输出“hello”;---遇到yield中断退出
yield:保存当前生成器函数状态并可以返回值(yield 10,类似return 10),中断函数退出。
__next__() :回来继续执行生成器函数
send():可以传递值给yield,然后回来继续执行生成器函数
5.生成器用例:通过yield实现在单线程的情况下实现并发运算的效果,异步IO
#通过生成器实现协程并行运算,吃包子和做包子两个配合同步进行
import time
def consumer(name):print("%s 准备吃包子啦!" %name)while True: # 确保生成器可以一直被调用执行下去baozi = yieldprint("包子[%s]来了,被[%s]吃了!" %(baozi,name))def make():c1 = consumer('A')c2 = consumer('B')c1.__next__()c2.__next__()print("老子开始准备做包子啦!")for i in range(1,4):time.sleep(1)print("做了2个包子!")c1.send(i)c2.send(i)make()
6.额外知识点:异常处理中try,except用法。
每当在运行时检测到程序错误时,python就会引发异常。对待异常有两种方法:一是可以在程序中捕捉和响应错误;或者忽略已发生的异常。
例如:生成器如果只有3个数据,通过next方法取多余的数据,例第4个数据,就会抛出一个异常 StopIteration。
例:通过异常处理,使程序运行不报错。
def func():for n in range(1,4):print('hello')yield 10print(f'你好这是生成器{n}')return '这里遇到一个生成器调用错误信息!!!'
gener = func()
while True:try:gener.__next__()gener.__next__()gener.__next__()gener.__next__()except StopIteration as errorinfo:print('程序运行返回StopIteration错误:',errorinfo.value)break
二、迭代器(可以被next()
函数调用并不断返回下一个值的对象称为迭代器,生成器也是一个迭代器)
1.定义
我们已经知道,可以直接作用于for
循环的数据类型有以下几种:一类是集合数据类型,如list
、tuple
、dict
、set
、str
等;一类是generator
,包括生成器和带yield
的generator function。
1.1这些可以直接作用于for
循环的对象统称为可迭代对象:Iterable
。
# 可以使用isinstance()
判断一个对象是否是Iterable可迭代
对象:
from collections.abc import Iterable
isinstance([1,2,3],Iterable)
# True
isinstance(100,Iterable)
# False
而生成器不但可以作用于for
循环,还可以被next()
函数不断调用并返回下一个值,直到最后抛出StopIteration
错误表示无法继续返回下一个值了。
1.2可以被next()
函数调用并不断返回下一个值的对象称为迭代器:Iterator
# 可以使用isinstance()
判断一个对象是否是Iterator
对象:
from collections.abc import Iterable,Iterator
isinstance([1,2,3],Iterator)
# False
isinstance((x for x in range(10)),Iterator)
# True
2.小结
凡是可作用于for
循环的对象都是Iterable可迭代对象
类型;
凡是可作用于next()
函数的对象都是Iterator迭代器
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable可迭代对象
但不是Iterator迭代器
,不过可以通过iter()
函数获得一个Iterator
对象。
from collections.abc import Iterable,Iterator
isinstance([1,2,3],Iterator)
# False
num = iter([1,2,3]) # 通过iter()函数,将可迭代对象列表变为迭代器
isinstance(num,Iterator)
# True
print(num.__next__()) # 1
print(num.__next__()) # 2
三、装饰器(不修改被装饰函数的源代码和调用方式,实现附加功能的添加)
1.定义:
本质是函数(装饰其它函数),就是为其他函数添加附加功能。
高阶函数 + 嵌套函数 =》装饰器
2.原则:函数感知不到装饰器的存在
*1.不能修改被装饰的函数的源代码
*2.不能修改被装饰的函数的调用方式
3.实现装饰器知识点:1.函数即变量 2.高阶函数 3.嵌套函数
*1.函数即变量:函数调用之前都有定义就可以执行成功(定义函数相当于定义一个变量,将函数体在内存中指向一个地址;)
定义、调用变量
x = 1
y = 2
print(y,x)定义、调用函数
def x():print(1)y()def y():print(2)
x()
# 1
# 2
*2.高阶函数:a.把一个函数名当做实参传给另外一个函数(在不修改被装饰函数的源代码情况下为其添加功能);b.返回值中包含函数名(不修改被装饰函数的调用方式)
a.在不修改被装饰函数的源代码情况下为其添加功能
import time
def func1():time.sleep(3)print('in the func1')def func2(func_name):start_time = time.time()func_name()stop_time = time.time()print(f'the func1 run time is {stop_time-start_time} !')
func2(func1)# 输出
in the func1
the func1 run time is 3.0013177394866943 !
# 实现一个查看程序运行时间的附加功能############################################################b.不修改被装饰函数的调用方式
import time
def func1():print('in the func1')def func2(func_name):print('hello')return func_name1.
func2(func1) #相当于要实现的附加功能
#输出
hello2.
test1 = func2(func1)
print(test1) #实现附加功能,同时返回要被装饰函数func1的内存地址 用于调用函数
#输出
hello
<function func1 at 0x000002AD8F68E160>test1() #调用test1,同时实现附加功能和被修饰函数的功能
#输出
hello
in the func1***3.覆盖掉要被装饰的函数,实现不改变其调用方式
func1 = func2(func1)
func1()
#输出
hello
in the func1
*3.嵌套函数:在一个函数体内创建另外一个函数(创建新函数,并非调用),这种函数就叫嵌套函数。
高阶函数 + 嵌套函数 =》装饰器
例:装饰器timer,为test1和test2函数增加显示运行时间的功能import time
# 嵌套函数 + 高阶函数 = 组成装饰器 timer
def timer1(func):def deco():start_time = time.time()func()stop_time = time.time()print('the function run time is %s'% (stop_time-start_time))return deco@timer1 # 调用timer装饰器装饰test1函数;相当于执行 test1=timer(test1)
def test1():time.sleep(3)print('It is test1 func')
test1()# 执行步骤:
# 1.定义函数timer --》 2.执行@timer,相当于执行test1 = timer(test1) --》
# 3.test1 = timer(test1) = deco;返回deco函数的内存地址 --》4.执行test1() = 执行deco()
_____________________timer1_____________________注意:
当test1函数无参数,test2函数需要参数时,用装饰器同时装饰这两个函数;给deco函数添加'*args,**kwargs'参数def timer2(func):def deco(*args,**kwargs):start_time = time.time()func(*args,**kwargs)stop_time = time.time()print('the function run time is %s'% (stop_time-start_time))return deco@timer2
def test2(name,age):time.sleep(3)print('It is test2 func')print(name,age)test2('XiaoZz',18)@timer2
def test3():time.sleep(3)print('It is test3 func')test3()
_____________________timer2_____________________
装饰器例子:
# 给三个页面添加登录验证功能,并且使用不同的登录方式
# 1.定义三种不同登录方式的账号密码
local_name,local_password = 'local','password'
ldap_name,ldap_password = 'ldap','password'
other_name,other_password = 'other','password'# 2.定义装饰器login函数,添加参数login_type判断不同的登录方式
def login(login_type):# 一级嵌套函数,func参数传递'被装饰的函数'def out_deco(func):# 二级嵌套函数,实现新增的功能与'被装饰的函数'功能def deco(*args,**kwargs):user_username = input('请输入你的用户名称:').strip()user_password = input('请输入你的用户密码:').strip()# 判断不同的登录方式,实现不同的效果if login_type == 'local':default_username = local_namedefault_password = local_passwordif user_username == default_username and user_password == default_password:print('欢迎你,登陆成功!')func(*args,**kwargs) # 执行被装饰参数else:print('账号或密码错误,退出!')return# 判断不同的登录方式,实现不同的效果if login_type == 'ldap':default_username = ldap_namedefault_password = ldap_passwordif user_username == default_username and user_password == default_password:print('欢迎你,登陆成功!')func(*args,**kwargs) # 执行被装饰参数else:print('账号或密码错误,退出!')return# 判断不同的登录方式,实现不同的效果if login_type == 'other':default_username = other_namedefault_password = other_passwordif user_username == default_username and user_password == default_password:print('欢迎你,登陆成功!')func(*args,**kwargs) # 执行被装饰参数else:print('账号或密码错误,退出!')returnreturn deco # 返回deco函数内存地址return out_deco # 返回out_deco函数内存地址@login(login_type='local') # 添加参数login_type选择不同的对应登录方式
def page1():print('hello,there is page 1 !')
print('---------- page1 function local ----------')
page1()@login(login_type='ldap') # page2 = login()
def page2(name):print('hello %s,there is page 2 !!' % name)
print('---------- page2 function ldap ----------')
page2('XiLong')@login(login_type='other')
def page3(name1,name2):print('hello %s and %s,there is page 3 !!!' %(name1,name2))
print('---------- page3 function other ----------')
page3('XiaoLong','XiaoJin')
四、内置函数
1.数学运算
abs:求数值的绝对值
>>> abs(-2)
2
max/min:返回可迭代对象中的元素中的最大值/ 最小值 或者所有参数的最大值/ 最小值
>>> max(1,2,3) # 传入3个参数 取3个中较大者
3
>>> max('1234') # 传入1个可迭代对象,取其最大元素值
'4'
>>> max(-1,0) # 数值默认去数值较大者
0
>>> max(-1,0,key = abs) # 传入了求绝对值函数,则参数都会进行求绝对值后再取较大者
-1
pow:返回两个数值的幂运算值或其与指定整数的模值
>>> pow(2,3)
>>> 2**3
8
>>> pow(2,3,5)
>>> pow(2,3)%5
>>> 2**3%5
3
round:对浮点数进行四舍五入求值
>>> round(1.1314926,1)
1.1
>>> round(1.1314926,5)
1.13149
sum:对元素类型是数值的可迭代对象中的每个元素求和
# 传入可迭代对象
>>> sum((1,2,3,4))
10
# 元素类型必须是数值型
>>> sum((1.5,2.5,3.5,4.5))
12.0
>>> sum((1,2,3,4),-9)
1
2.类型转换
bool:根据传入的参数的逻辑值创建一个新的布尔值
>>> bool() #未传入参数
False
>>> bool(0) #数值0、空序列等值为False
False
>>> bool(1)
True
int:根据传入的参数创建一个新的整数
>>> int() #不传入参数时,得到结果0。
0
>>> int(3)
3
>>> int(3.6)
3
float:根据传入的参数创建一个新的浮点数
>>> float() #不提供参数的时候,返回0.0
0.0
>>> float(3)
3.0
>>> float('3')
3.0
str:返回一个对象的字符串表现形式(给用户)
>>> str()
''
>>> str(None)
'None'
>>> str('abc')
'abc'
>>> str(123)
'123'
bytearray:根据传入的参数创建一个新的字节数组
>>> bytearray('中文','utf-8')
bytearray(b'\xe4\xb8\xad\xe6\x96\x87')
bytes:根据传入的参数创建一个新的不可变字节数组
>>> bytes('中文','utf-8')
b'\xe4\xb8\xad\xe6\x96\x87'
ord:返回Unicode字符对应的整数
>>> ord('a')
97
chr:返回整数所对应的Unicode字符
>>> chr(97) #参数类型为整数
'a'
bin:将整数转换成2进制字符串
>>> bin(3)
'0b11'
oct:将整数转化成8进制数字符串
>>> oct(10)
'0o12'
hex:将整数转换成16进制字符串
>>> hex(15)
'0xf'
iter:根据传入的参数创建一个新的可迭代对象
tuple:根据传入的参数创建一个新的元组
list:根据传入的参数创建一个新的列表
set:根据传入的参数创建一个新的集合
frozenset:根据传入的参数创建一个新的不可变集合
enumerate:根据可迭代对象创建枚举对象
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1)) #指定起始值
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
3.序列操作
all:判断可迭代对象的每个元素是否都为True值
any:判断可迭代对象的元素是否有为True值的元素
sorted:对可迭代对象进行排序,返回一个新的列表
>>> a = ['a','b','d','c','B','A']
>>> a
['a', 'b', 'd', 'c', 'B', 'A']>>> sorted(a) # 默认按字符ascii码排序
['A', 'B', 'a', 'b', 'c', 'd']>>> sorted(a,key = str.lower) # 转换成小写后再排序,'a'和'A'值一样,'b'和'B'值一样
['a', 'A', 'b', 'B', 'c', 'd']
4.对象操作
help:返回对象的帮助信息
dir:返回对象或者当前作用域内的属性列表
id:返回对象的唯一标识符
hash:获取对象的哈希值
type:返回对象的类型,或者根据传入的参数创建一个新的类型
len:返回对象的长度
ascii:返回对象的可打印表字符串表现方式
vars:返回当前作用域内的局部变量和其值组成的字典,或者返回对象的属性列表
内置参数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii
五、json & pickle数据序列化
1.序列化与反序列化定义,及json和pickle的使用
序列化:将对象转换成易传输或易保存的数据的过程称为序列化;即把Python对象转换成JSON字符串。例如将内存上的对象变成字符串可以存到硬盘上。
json.dumps()
json.dump() 将Python对象转换成json字符串并存储到文件中
反序列化:将一定的数据格式转成可用的对象称为反序列化;即把JSON字符串转换成python对象。例如将硬盘上的数据对象变成原来格式,可以再恢复到内存中。
json.loads()
json.load() 读取指定文件中的json字符串并转换成Python对象
# 如果需要序列化的数据中存在中文,就需要将dumps方法的 ensure_ascii 参数设置为False,否则显示的中文会乱码。
import json
# 序列化:
name = ['校长','老师']
test1 = json.dumps(name,ensure_ascii=False)
print(test1) #["校长", "老师"]
print(type(test1)) # <type 'str'>file = open('abc.txt','w')
json.dump(name,file)# 反序列化
test2 = json.loads(test1)
print(test2[0]) # 校长
print(type(test2)) #<type 'list'>json.load(file)
2.json与pickle的区别(属性用法一致)
json序列化之后得到的是字符串,仅支持字典和列表对象,各种编程语言几乎都能支持 json。
pickle序列化之后得到的是字节,支持Python中大部分对象,仅被Python支持。
pickle序列化不会改变字典键的数据类型;json序列化,如果键是数字会转为字符串。
六、软件目录结构规范
1.例如开发一个 App 项目,目录结构应该如下:
App/
|-- bin/ # 存放项目的一些可执行文件
| |-- app.py # 项目启动脚本,调用程序入口 main.py
|
|-- app/ # 存放项目的所有源代码
| |-- tests/ # 存放单元测试代码
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py # 程序的入口
|
|-- conf/ # 存放一些配置文档
| |-- app_conf.py # 配置文件
| |-- abc.rst
|
|-- log/ # 存放日志文件
| |-- app.log # 运行日志
| |-- error.log # 错误日志
|
|-- setup.py # 安装、部署、打包的脚本
|-- requirements.txt # 存放软件依赖的外部Python包列表
|-- README # 项目说明文件
2.如何通过 bin/app.py 启动脚本去直接调用 main.py 呢?
# 在 bin/app.py 中
import os
import sys
print(__file__) # 打印相对路径
print(os.path.abspath(__file__)) # 打印绝对路径
print(os.path.dirname(os.path.abspath(__file__))) # 获取路径名,去掉文件名
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # 再使用一次path.dirname方法获取上一级路径sys.path.append(BASE_DIR) # 添加环境变量,这时就可以直接调用 main.py 和 app_conf.py 中的函数了
from conf import app_conf
from app import main
3.注意:不应当在代码中直接 import
来使用"app_conf.py"或"main.py"。应该可以通过给 main.py
启动参数 -c 指定配置路径的方式来让程序读取配置内容。
七、作业:
作业需求:模拟实现一个ATM + 购物商城程序
- 额度 15000或自定义
- 实现购物商城,买东西加入 购物车,调用信用卡接口结账
- 可以提现,手续费5%
- 每月22号出账单,每月10号为还款日,过期未还,按欠款总额 万分之5 每日计息
- 支持多账户登录
- 支持账户间转账
- 记录每月日常消费流水
- 提供还款接口
- ATM记录操作日志
- 提供管理接口,包括添加账户、用户额度,冻结账户等。。。
- 用户认证用装饰器
示例代码 https://github.com/triaquae/py3_training/tree/master/atm
简易流程图:https://www.processon.com/view/link/589eb841e4b0999184934329
Python运维开发从入门到精通学习 Day4相关推荐
- python web开发入门_python大佬整理的python web开发从入门到精通学习笔记
原标题:python大佬整理的python web开发从入门到精通学习笔记 Python(发音:英[?pa?θ?n],美[?pa?θɑ:n]),是一种面向对象.直译式电脑编程语言,也是一种功能强大的通 ...
- 阅后即焚,Python 运维开发99速成
2019独角兽企业重金招聘Python工程师标准>>> -欢迎大家订阅微信公众号:Python从程序猿到程序员 导读 本文篇幅较长,请收藏并耐心阅读 首先请读者原谅这个文章标题有些唬 ...
- Python运维开发基础01-语法基础【转】
开篇导语 整个Python运维开发教学采用的是最新的3.5.2版,当遇到2.x和3.x版本的不同点时,会采取演示的方式,让同学们了解. 教学预计分为四大部分,Python开发基础,Python开发进阶 ...
- day01.介绍python运维开发
第1节:介绍python运维开发 课程的开场白: 学完次课程可以开发出高效的自动化软件.运维监控.聊天软件.网站等内容. 这个运维开发跟实际上的开发是有区别的,区别在我们是实现功能,但是不能向开发那样 ...
- Python运维开发工程师养成记(循环语句)
图示 循环语句类型 while循环 for循环 嵌套循环 循环控制语句 break语句:在语句块执行过程中终止循环,并且跳出整个循环 continue语句:在语句块执行过程中终止当前循环,跳出该次循环 ...
- Python运维开发基础09-函数基础【转】
上节作业回顾 #!/usr/bin/env python3 # -*- coding:utf-8 -*- # author:Mr.chen # 实现简单的shell命令sed的替换功能import s ...
- Python运维开发基础10-函数基础【转】
一,函数的非固定参数 1.1 默认参数 在定义形参的时候,提前给形参赋一个固定的值. #代码演示: def test(x,y=2): #形参里有一个默认参数 print (x) print (y) t ...
- Revit二次开发从入门到精通学习之路, (含Revit二次开发教程下载)
Revit二次开发从入门到精通学习之路 Autodesk Joe Ye叶雄进 2. 18 2014 yexiongjin@hotmail.com Revit在国内的应用越来越广泛, Revit ...
- 第1课 EOS开发从入门到精通学习导航
第1课 EOS开发从入门到精通学习导航 柚子(EOS)可以理解为Enterprise Operation System,即为商用分布式应用设计的一款区块链操作系统.EOS是EOS软件引入的一种新的区块 ...
最新文章
- 大数据时代 | 数据分析方法及理论详解
- leetcode 504. 七进制数(Java版)
- 怎样在sqlite3上执行SQL语句
- [MySQL]关于amd.dll后门病毒入侵3306端口的临时解决方案
- uva 10559——Blocks
- thinkcmf ajax,thinkcmfx 中如何用jquery ajax提交数据,自己尝试去做之后,还是没法提交,求助!...
- (王道408考研操作系统)第二章进程管理-第三节2:实现进程互斥的软件方法
- outlook客户端接收邮件报错0x80040600
- 编译OpenJDK8:Your cygwin is too old. You are running but at least cygwin 1.7 is required
- 《Shell脚本学习指南》笔记--2011-12-17
- mysql是用啥语言写的_mysql源码是什么语言
- 电影海报页面设计Html5,如何设计电影海报
- 史上最全后端技术介绍
- 新版白话空间统计(24):中位数中心
- 意在寥廓观鸿蒙 什么意思,“滴滴寒露凋芙蓉”的意思及全诗出处和翻译赏析...
- java存根_Java方法存根
- 机器学习环境配置(Tesla K80安装PyTorch的全过程)
- “为了买台手机,研究大半个月后仍然无从选择”
- 文章开始同步到我的微信公众号
- PHP除数取余数,php相除取余数的实现方法