python基础06

Posted 水无

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python基础06相关的知识,希望对你有一定的参考价值。

Python基础学习06


实现装饰器知识储备

装饰器

生成器

迭代器

目录结构


一、实现装饰器知识储备

1、函数即“变量

技术分享图片
 1 x = 1
 2 y = 2
 3 print(x,y)
 4 
 5 y = 2
 6 x = 1
 7 print(x,y)
 8 
 9 def bar():
10     print("in the bar")
11 def foo():
12     print("in the foo")
13     bar()
14 foo()
15 
16 def foo():
17     print("in the foo")
18     bar()
19 def bar():
20     print("in the bar")
21 foo()
View Code

函数调用顺序:其他高级语言类似,Python 不允许在函数未声明之前,对其进行引用或者调用

python为解释执行,函数foo在调用前已经声明了bar和foo,所以bar和foo无顺序之分(和变量的调用相同)

2、高阶函数

满足下列条件之一就可成函数为高阶函数:

a:把一个函数名当做实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)

技术分享图片
 1 #把一个函数名当做实参传给另外一个函数
 2 def bar():
 3     print("in the bar")
 4 def test_1 (func):
 5     print(func)
 6 test_1(bar)    #输出:<function bar at 0x00000264BDEED488>  即bar()函数的内存地址
 7 
 8 def bar():
 9     print("in the bar")
10 def test_1 (func):
11     print(func)   #<function bar at 0x00000264BDEED488>
12     func()        #in the bar    (bar()函数的运行结果)
13 test_1(bar)
14 
15 #应用:统计函数运行时间
16 import time
17 def bar():
18     print("in the bar")
19     time.sleep(1)
20 def test_1 (func):
21     start_time = time.time()
22     func()        #in the bar    (bar()函数的运行结果)
23     stop_time = time.time()
24     print("the func run time:%s "%(stop_time - start_time))
25 test_1(bar)
View Code

b:返回值中包含函数名(不修改函数的调用方式)

技术分享图片
 1 import time
 2 def bar():
 3     print("in the bar")
 4     time.sleep(1)
 5 def test_2(func):
 6     print(func)
 7     return func
 8 t = test_2(bar)   #获取bar()函数的内存地址,把其当做返回值传给变量t
 9 t()        #运行函数
10 
11 def bar():
12     print("in the bar")
13     time.sleep(1)
14 def test_2(func):
15     print(func)
16     return func
17 bar = test_2(bar)   #获取bar()函数的内存地址,把其当做返回值传给变量bar
18 bar()        #不修改函数的调用方式
View Code

3、嵌套函数

定义:在一个函数体内创建另外一个函数;即在一个函数的函数体内用def去声明一个新的函数(而不是去调用)

技术分享图片
1 #最简单的嵌套函数
2 def foo():
3     print("in the foo")
4     def bar():         #相当于局部变量
5         print("in the bar")
6     bar()            #调用bar()函数
7 foo()      #调用函数
View Code

局部作用域和全局作用域的访问顺序:

技术分享图片
 1 x=0
 2 def grandpa():
 3     # x=1
 4     def dad():
 5         x=2
 6         def son():
 7             x=3
 8             print(x)
 9         son()
10     dad()
11 grandpa()
View Code

二、装饰器

定义:本质是函数(装饰其他函数)就是为其他函数添加附加功能
原则
a、不能修改被装饰的函数的源代码
b、不能修改被装饰的函数的调用方式
即装饰器对其装饰的函数是完全透明的

高阶函数+嵌套函数=》装饰器

简单装饰器:(不能传参)

技术分享图片
 1 #统计运行时间
 2 import time
 3 def timer(func):
 4     def deco ():
 5         start_time = time.time()
 6         func()        
 7         stop_time = time.time()
 8         print("the func run time:%s "%(stop_time - start_time))
 9     return deco
10 def test_1 ():
11     time.sleep(1)
12     print("in the test_1")
13 def test_2 ():
14     time.sleep(2)
15     print("in the test_2")
16 
17 test_1 = timer(test_1)    #即:@timer
18 test_2 = timer(test_2)    #即:@timer
19 test_1()     #没有修改被装饰的函数的源代码,也没有修改被装饰的函数的调用方式,并且添加了新功能
20 test_2()     #没有修改被装饰的函数的源代码,也没有修改被装饰的函数的调用方式,并且添加了新功能
21 
22 #正规写法
23 import time
24 def timer(func):
25     def deco ():
26         start_time = time.time()
27         func()       
28         stop_time = time.time()
29         print("the func run time:%s "%(stop_time - start_time))
30     return deco
31 @timer      #即:test_1 = timer(test_1)
32 def test_1 ():
33     time.sleep(1)
34     print("in the test_1")
35 @timer      #即:test_2 = timer(test_2)
36 def test_2 ():
37     time.sleep(2)
38     print("in the test_2")
39 
40 test_1()     #没有修改被装饰的函数的源代码,也没有修改被装饰的函数的调用方式,并且添加了新功能
41 test_2()     #没有修改被装饰的函数的源代码,也没有修改被装饰的函数的调用方式,并且添加了新功能
View Code

加入参数:

技术分享图片
 1 import time
 2 def timer(func):
 3     def deco (*args,**kwargs):      #deco() 即 test_1、test_2 在此传入参数
 4         start_time = time.time()
 5         func(*args,**kwargs)
 6         stop_time = time.time()
 7         print("the func run time:%s "%(stop_time - start_time))
 8     return deco
 9 @timer      #即:test_1 = timer(test_1)
10 def test_1 ():
11     time.sleep(1)
12     print("in the test_1")
13 @timer      #即:test_2 = timer(test_2)
14 def test_2 (name):
15     time.sleep(0.5)
16     print("test_2",name)
17 
18 test_1()
19 test_2("zz")
View Code

真正的装饰器:

技术分享图片
 1 #在原来函数上添加认证登录功能,并且允许用户选择多种方式进行登录
 2 import time
 3 user,passwd = zz,123
 4 def auth(auth_type):
 5     def out_wrapper(func):
 6         def wrapper(*args,**kwargs):
 7             if auth_type == "local":
 8                 username = input("username:").strip()
 9                 password = input("password:").strip()
10                 if username == user and password ==passwd:
11                     print("login!!")
12                     res = func(*args,**kwargs)
13                     return res                #之前的装饰器没有返回值,如果有返回值则需要定义返回值
14                 else:
15                     exit("认证失败")
16             elif auth_type == "ldap":
17                 print("还不会ldap!")
18         return wrapper
19     return out_wrapper
20 
21 def index():
22     print("welcome to index page!")
23 @auth(auth_type = "local")  #home = auth()
24 def home():
25     print("welcome to home page!")
26     return "from home"
27 @auth(auth_type = "ldap")
28 def bbs():
29     print("welcome to bbs page!")
30 
31 index()
32 print(home())  #有返回值的调用
33 bbs()
View Code

三、生成器

1、列表生成式

技术分享图片
1 a = [1,2,3]       #正常定义列表(数据是写死的)
2 b = [i*2 for i in range(5)]   #列表生成式
3 print(b)     #[0, 2, 4, 6, 8]
4 
5 b = []      #与上面效果一样但是代码量大
6 for i in range(5):
7     b.append(i*2)
8 print(b)
View Code

2、生成器

在Python中一边循环一边计算的机制,称为生成器:generator。

要创建一个generator,有很多种方法。

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

技术分享图片
1 L = [x * x for x in range(10)]
2 g = (x * x for x in range(10))
3 print(g)   #<generator object <genexpr> at 0x0000022A5A330AF0>
View Code

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

 我们可以直接打印出list的每一个元素,但我们需要通过next()函数获得generator的下一个返回值:

技术分享图片
1 L = [x * x for x in range(10)]
2 g = (x * x for x in range(10))
3 print(g)   #<generator object <genexpr> at 0x0000022A5A330AF0>
4 
5 print(g.__next__())  # 0
6 print(g.__next__())  # 1
7 print(g.__next__())  # 4
8 print(g.__next__())  # 9
9 print(g.__next__())  # 16
View Code

generator也是可迭代对象,可以用for循环:

技术分享图片
 1 g = (x * x for x in range(10))
 2 print(g)   #<generator object <genexpr> at 0x0000022A5A330AF0>
 3 for i in g :
 4     print(i)
 5 print(g.__next__())  
 6 ‘‘‘
 7 Traceback (most recent call last):
 8     print(g.__next__())  # 0
 9 StopIteration
10 ‘‘‘
View Code


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

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

技术分享图片
 1 #用函数生成斐波那契数列
 2 def fib(max):
 3     n, a, b = 0, 0, 1
 4     while n < max:
 5         print(b)
 6         a, b = b, a + b
 7         ‘‘‘a, b = b, a + b相当于:
 8         t = (b, a + b) # t是一个tuple
 9         a = t[0]
10         b = t[1]
11         ‘‘‘
12         n = n + 1
13     return done
14 fib(10)
15 
16 #print(b)改为yield b 就变成了生成器
17 def fib(max):
18     n, a, b = 0, 0, 1
19     while n < max:
20         yield b
21         a, b = b, a + b
22         n = n + 1
23     return done
24 print(fib(10))  #<generator object fib at 0x000002371FC30AF0>
25 f = fib(10)
26 print(f.__next__())  # 1
27 print(f.__next__())  # 1
28 print(f.__next__())  # 2
29 print("_____")      #_____
30 print(f.__next__())  # 3
View Code


同样的,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代,但是用for循环调用generator时,发现拿不到generator的return语句的返回值,计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误,如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:

技术分享图片
 1 def fib(max):
 2     n, a, b = 0, 0, 1
 3     while n < max:
 4         yield b
 5         a, b = b, a + b
 6         n = n + 1
 7     return done
 8 g = fib(5)
 9 while True:
10     try:
11         x = next(g)
12         print(g:, x)
13     except StopIteration as e:
14         print(Generator return value:, e.value)
15         break
16 ‘‘‘
17 g: 1
18 g: 1
19 g: 2
20 g: 3
21 g: 5
22 Generator return value: done
23 ‘‘‘
View Code

特性:a、生成器只有在调用时才会生成数据。

b、只记录当前位置。

c、只有一个__next__()方法。

四、迭代器

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

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

技术分享图片
1 from collections import Iterable
2 print(isinstance([], Iterable))  #True
3 print(isinstance({}, Iterable))  #True
4 print(isinstance(abc, Iterable))  #True
5 print(isinstance((x for x in range(10)), Iterable))  #True
6 print(isinstance(100, Iterable))  #False
View Code

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

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

技术分享图片
1 from collections import Iterator
2 print(isinstance((x for x in range(10)), Iterator))  #True
3 print(isinstance([], Iterator))  #False
4 print(isinstance({}, Iterator))  #False
5 print(isinstance(abc, Iterator))  #False
View Code

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator,把list、dict、str等Iterable变成Iterator可以使用iter()函数: 

技术分享图片
1 isinstance(iter([]), Iterator)  #True
2 isinstance(iter(abc), Iterator)  #True
View Code

Python的for循环本质上就是通过不断调用next()函数实现的:

技术分享图片
 1 for x in [1, 2, 3, 4, 5]:
 2     pass
 3 #等价于:
 4 # 首先获得Iterator对象:
 5 it = iter([1, 2, 3, 4, 5])
 6 # 循环:
 7 while True:
 8     try:
 9         # 获得下一个值:
10         x = next(it)
11     except StopIteration:
12         # 遇到StopIteration就退出循环
13         break
View Code

五、目录结构 

规范的目录结构能更好的控制程序结构,让程序具有更高的可读性。
"项目目录结构"其实也是属于"可读性和可维护性"的范畴,设计一个层次清晰的目录结构,就是为了达到以下两点:
1.可读性高: 不熟悉这个项目的代码的人,一眼就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等。从而非常快速的了解这个项目。
2.可维护性高: 定义好组织规则后,维护者就能很明确地知道,新增的哪个文件和代码应该放在什么目录之下。这个好处是,随着时间的推移,代码/配置的规模增加,项目结构不会混乱,仍然能够组织良好。

 常用目录树:

项目名/
|-- bin/
|   |-- 可执行文件
|
|-- 项目/
|   |-- tests/
|   |   |-- __init__.py
|   |   |-- test_main.py
|   |
|   |-- __init__.py
|   |-- main.py
|
|-- docs/
|   |-- conf.py
|   |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README

1.bin/: 存放项目的一些可执行文件。
2.项目/: 存放项目的所有源代码。(1) 源代码中的所有模块、包都应该放在此目录。不要置于顶层目录。(2) 其子目录tests/存放单元测试代码; (3) 程序的入口最好命名为main.py。
3.docs/: 存放一些文档。
4.setup.py: 安装、部署、打包的脚本。
5.requirements.txt: 存放软件依赖的外部Python包列表。
6.README: 项目说明文件。

README需要说明以下几个事项:
1.软件定位,软件的基本功能。
2.运行代码的方法: 安装环境、启动命令等。
3.简要的使用说明。
4.代码目录结构说明,更详细点可以说明软件的基本原理。
5.常见问题说明。

 




















以上是关于python基础06的主要内容,如果未能解决你的问题,请参考以下文章

python基础训练营06

[vscode]--HTML代码片段(基础版,reactvuejquery)

Python基础-week06 面向对象编程进阶

常用python日期日志获取内容循环的代码片段

python 有用的Python代码片段

Python 向 Postman 请求代码片段