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()

函数调用顺序:其他高级语言类似,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)

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()        #不修改函数的调用方式

3、嵌套函数

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

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

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

 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()

二、装饰器

定义:本质是函数(装饰其他函数)就是为其他函数添加附加功能
原则
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()     #没有修改被装饰的函数的源代码,也没有修改被装饰的函数的调用方式,并且添加了新功能

加入参数:

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

真正的装饰器:

 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()

三、生成器

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)

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>

创建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

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 ‘‘‘

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

同样的,把函数改成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 ‘‘‘

特性: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

可以被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

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

1 isinstance(iter([]), Iterator)  #True
2 isinstance(iter(‘abc‘), Iterator)  #True

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

五、目录结构 

规范的目录结构能更好的控制程序结构,让程序具有更高的可读性。
"项目目录结构"其实也是属于"可读性和可维护性"的范畴,设计一个层次清晰的目录结构,就是为了达到以下两点:
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.常见问题说明。

原文地址:https://www.cnblogs.com/hy0822/p/9064695.html

时间: 2024-11-09 02:20:35

python基础06的相关文章

Python基础06 循环

Python基础06 循环 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 循环用于重复执行一些程序块.从上一讲的选择结构,我们已经看到了如何用缩进来表示程序块的隶属关系.循环也会用到类似的写法. for循环 for循环需要预先设定好循环的次数(n),然后执行隶属于for的语句n次. 基本构造是 for 元素 in 序列: statement 举例来说,我们编辑一个叫forDemo.py的文件 for a in [3,4.4,

Python基础06 - 生成器、迭代器

@@@文章内容参照老男孩教育 Alex金角大王,武Sir银角大王@@@ 一.生成器 列表生成式 1 a = [i * 2 for i in range(10)] 2 print(a) 3 # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的,而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大数元素占用的空间都是浪费的. 所以,

python基础-06

is 和 == 的区别 is 比较的是内存地址 == 比较的是值 id(变量)  返回给你这个变量的内存地址 例子:s="周杰伦" s1=s print(id(s),id(s1)) 特殊的: lst1=[1,4,7] lst2=[1,4,7] lst1.append("小白") print(lst1,lst2) print(id(lst1),id(lst2))  #内存地址不同 小数据池(常量池): 把我们使用过的值存储在小数据池中.供其他的变量使用. 小数据池给数

Python基础课:一起学习python基础题

python最近老火了,万能开发语言,很多小伙伴们要么初学,要么从别的开发语言转过来的,如果你能把下面几道基础题不费劲的写出来,基础应该可以打80分,可以进行进阶的学习了,如果下面的题目如果做不出来,拜托不要耽误时间,赶快打好基础,勿在浮沙筑高台. 题目出给新鸟打基础的,实现答案的方法千千万,如果老鸟有更厉害的答案就不要喷了,先谢谢了. 还有新鸟先不要看答案,不要看答案,不要看答案,(重要的事情说三遍)自己先去解,用自己最简单的想法去实现,能用python自带的方法就不要自己造轮子. 好啦,开始

python基础教程_学习笔记14:标准库:一些最爱——re

标准库:一些最爱 re re模块包含对正则表达式的支持,因为曾经系统学习过正则表达式,所以基础内容略过,直接看python对于正则表达式的支持. 正则表达式的学习,见<Mastering Regular Expressions>(精通正则表达式) re模块的内容 最重要的一些函数 函数 描述 compile(pattern[,flags]) 根据包含正则表达式的字符串创建模式对象 search(pattern,string[,flags]) 在字符串中寻找模式 match(pattern,st

python 基础(一)

一.Python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承. 1.1.Python应用领域: l 云计算: 云计算最火的语言, 典型应用OpenStack l WEB开发: 众多优秀的WEB框架,众多大型网站均为Python开发,Youtube, Dropbox, 豆瓣..., 典型WEB框架有Django l 科学运算.人工智能: 典型库N

python基础学习(一)

一,Python介绍 1,python的出生与应用 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆(中文名字:龟叔)为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC语言的一种继承. (龟叔:2005年加入谷歌至2012年,2013年加入Dropbox直到现在,依然掌握着Python发展的核心方向,被称为仁慈的独裁者). 2018年10月的TIOBE排行榜,Python已经占据第四的位置, Python崇尚优美.清

linux+jmeter+python基础+抓包拦截

LINUX 一 配置jdk 环境 *需要获取root权限,或者切换为root用户 1.windows下载好,去 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 官方网站下载jdk(linux相应版本) 2.在usr目录下创建java路径文件夹 [root bin]cd /usr mkdir java 3.将jdk-8u60-linux-x64.tar.gz放到刚才创建的文件夹下

Python基础教程(第九章 魔法方法、属性和迭代器)

本文内容全部出自<Python基础教程>第二版,在此分享自己的学习之路. ______欢迎转载:http://www.cnblogs.com/Marlowes/p/5437223.html______ Created on Marlowes 在Python中,有的名称会在前面和后面都加上两个下划线,这种写法很特别.前面几章中已经出现过一些这样的名称(如__future__),这种拼写表示名字有特殊含义,所以绝不要在自己的程序中使用这样的名字.在Python中,由这些名字组成的集合所包含的方法称