内容html
装饰器:本质就是函数,定义函数器装饰其余函数,就是为其余函数添加附加功能。python
原则:一、不能修改被装饰的函数的源代码
二、不能修改被装饰的函数的调用方式
实现装饰器,涉及到的知识量:
一、函数既“变量”
二、高阶函数
三、嵌套函数
高阶函数+嵌套函数 =》完成装饰器的使用
一、装饰器的调用方式:@

二、函数既是“变量”的理解
举例说明:
python 内部回收的地址说明
三、高阶函数
函数返回值
四、嵌套函数
分清,嵌套跟函数内部调用的区别
五、根据不一样验证输入,走不一样的验证方式 算法
装饰高潮版数据库
列表生成式:能够直接建立一个列表,做用使代码更简洁,数据量大的话,不适合去用,比较受内存的限制。数据量大的话,不只占用很大的存储空间,若是整个列表里面,咱们只须要几元素,那么后面元素占用的空间都浪费了。
举例:目前有一列表[0,1,2,3,4,5,6,7,8,9],须要在每一个元素上加1,看实现的方法
第一种方法: >>> a = [0,1,2,3,4,5,6,7,8,9] >>> b = [] >>> for i in a:b.append(i+1) #定义b的空列表,把a的值加1后赋給b ... >>> print (b) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> a = b >>>print (a) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 第二种方法: >>> a = [0,1,2,3,4,5,6,7,8,9] >>> for index,i in enumerate(a): ... a[index] += 1 #利用索引的切片取值,在循环加1,打印 ... >>> print (a) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 第三种方法: >>> a = [0,1,2,3,4,5,6,7,8,9] >>> b = [i+1 for i in a] >>> print (b) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
生成器(generator):列表生成式,是把列表里面的全部元素完整的进行打印。生成器就是这种没必要建立完整的list,从而节 省大量的内存空间。在python环境中,这种一边循环一边计算的机制就成称之为生成器。
一、简单的生成器建立,只须要把列表生成式的[]换成(), 就建立完成:
1 列表生成式: 2 >>> a = [ i*2 for i in range(10) ] 3 >>> print (a) 4 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 5 备注:做用使代码更简洁,数据量大的话,不适合去用,比较耗空间 8 =============================== 9 生成器: 10 >>> b = ( i*2 for i in range(10) ) 11 >>> print (b) 12 <generator object <genexpr> at 0x1021e0938> 13 >>> b.__next__() 14 0 15 >>> b.__next__() 16 2 17 >>> b.__next__() 18 4 备注:只有调用时才会生成相应的数据;只记录当前的位置,并且方法只有一个__next__(),不能返回去取用,(python 2.7版本是 next()),直到把数值取完为止。数据取完以后,进行往下取数值,就会报错。
不断的使用__next()__,取数值,比较麻烦,能够结合for的循环使用,由于生成器能够是迭代的对象:编程
观察如下,两个的变化:json
打印了内存的地址: >>> d = ( i +1 for i in range(10)) >>> for i in d: ... print (d) ... <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> <generator object <genexpr> at 0x1019e09e8> 打印输出内容: >>> d = ( i +1 for i in range(10)) >>> for i in d: ... print (i) ... 1 2 3 4 5 6 7 8 9 10
因此,建立了一个生成器,基本上永远不会调用__,而是经过循环来迭代它,而且不须要关心的错误。next()__forStopIteration
二、利用函数进行算法推算,并改为生成器的形式数组
若有推算的算法比较复杂,用相似的列表生成式的for 循环没法实现的时候,还能够用函数来实现。并发
以下:除第一个数,第二个数外。任意一个数均可以由前两个数相加获得:app
a = [1,1,2,3,5,8,13,21,34,55.......]ssh
要计算得出以上的数学列表,单独使用列表生成式,很难实现。用函数进行打印:
def fib(max): n,a,b = 0,0,1 while n < max: print(b) # 还不是生成器,目前的执行输出仍是所有打印,数据量大会卡死 a, b = b, a+b #注意赋值的写法,其中左边"a"的值等于右边"b"的值,左边 ”b“的值等于右边“a+b”的值。 n = n + 1 return 'done' f=fib(10)
print(f) 输出: 1 1 2 3 5 8 13 21 34 55
done
以上函数实现了数列的推算,但种逻辑还不是生成器的写法,如下把print(b)改成yield b就能够实现。以下:
def fib(max): n,a,b = 0,0,1 while n < max: #print(b) yield b a, b = b, a+b # n = n + 1 return 'done' f = fib(10) print(f) 输出: <generator object fib at 0x102180888> 打印出生成器的内存地址。
注意:以上是生成器的另一种定义的方式,若是一个函数的定义中包含yield关键字,那么这个函数不是再是普通的函数,而是一个生成器函数。
三、生成器和函数的执行流程
重点理解:生成器和函数的执行流程不同。函数是顺序执行,遇到return 语句或者最后一句函数语句就返回。而变成生成器的函数,在每次调用__next__ 的时候执行,遇到yield语句返回,再次执行时会从上次返回的yield语句处继续执行。函数测试最好加入断点的方法验证。
对比,如下两个断点判断执行的例子,观察执行顺序:
A、使print(b) 打印
def fib(max): #第二步,函数体处理过程 n,a,b = 0,0,1 #第三步 while n < max: #第四步,执行while循环,直到计算10次,完成整个循环退出。 print(b) #yield b a, b = b, a+b n = n + 1 return 'done' f = fib(10) #熟悉调用函数体 ,第一步 print(f) #第五步,调用打印 print("来个断点判断") print(f) #第六步,只会打印函数的return返回值,并不执行while 循环。
输出:
1
1
2
3
5
8
13
21
34
55
done
来个断点
done
B、使yield来打印
def fib(max): n,a,b = 0,0,1 while n < max: yield b a, b = b, a+b n = n + 1 return 'done' f = fib(10) #f:<generator object fib at 0x1020808e0> print(f.__next__()) #第一步,执行输出,调用函数进行计算,第一次执行完以后跳出,执行第二print的输出 print(f.__next__()) #第二步,执行输出,接上个print 执行后,调用函数进行计算,往下继续计算,不重复。 print("来个断点") #第三步,加个隔断 print(f.__next__()) #第四步,接着后面没有打印数值,进行传参,进行打印 print("来个断点2") print(f.__next__()) 输出:
1
来个断点1
1
2
来个断点2
3
在循环过程当中不断调用yield
,就会不断中断。固然要给循环设置一个条件来退出循环,否则就会产生一个无限数列出来。
C、使用for循环来迭代,进行对生成器的取值:
把函数变成生成器,基本上不会使用__next()__来获取下一个返回值,都是经过for循环取值
def fib(max): n,a,b = 0,0,1 while n < max: yield b a, b = b, a+b n = n + 1 return 'done' f = fib(10) for i in (f): print (i) 输出: 1 1 2 3 5 8 13 21 34 55
备注:使用for
循环调用生成器时,拿不到生成器的return
语句的返回值。若是想要拿到返回值,必须捕获StopIteration
错误,返回值包含在StopIteration
的value
中,要进行异常输出:
异常处理,异常捕获:
def fib(max): n,a,b = 0,0,1 while n < max: yield b a, b = b, a+b n = n + 1 return 'done' f = fib(10) for i in (f): while True: try: x = next(f) print('f:',x) except StopIteration as e: print('Generator return value:', e.value) break 输出: f: 1 f: 2 f: 3 f: 5 f: 8 f: 13 f: 21 f: 34 f: 55 Generator return value: done
D、yield实如今单线程的状况下实现并发运算的效果
以下:
1 import time 2 def consumer(name): 3 print("%s 准备吃包子啦!" % name) 4 while True: 5 baozi = yield #定义生成器位置 6 7 print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) 8 9 10 def producer(name): 11 c = consumer('A') 12 c2 = consumer('B') 13 print(dir(c)) 14 c.__next__() 15 c2.__next__() 16 print("老子开始准备作包子啦!") 17 for i in range(5): 18 time.sleep(1) 19 c.send(i) #可使用dir(c),查看生成器的调用方式 20 c2.send(i) #send跟baozi = yield是什么关系 21 22 producer("chen1203") 23 输出: 24 ['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw'] 25 A 准备吃包子啦! 26 B 准备吃包子啦! 27 老子开始准备作包子啦! 28 包子[0]来了,被[A]吃了! 29 包子[0]来了,被[B]吃了! 30 包子[1]来了,被[A]吃了! 31 包子[1]来了,被[B]吃了! 32 包子[2]来了,被[A]吃了! 33 包子[2]来了,被[B]吃了! 34 包子[3]来了,被[A]吃了! 35 包子[3]来了,被[B]吃了! 36 包子[4]来了,被[A]吃了! 37 包子[4]来了,被[B]吃了!
一、迭代器定义
注意区分,可迭代对象与迭代器的区别:能够直接做用于 for
语句进行循环的对象称之为可迭代对象;能够被next()
函数调用并不断返回下一个值的对象称为迭代器:Iterator
。生成器必定是迭代器,但迭代器不必定是生成器。
a = [1,2] for i in a: print (i) 输出: 1 2 b = {"a":123,"b":456} for i in b: print(i) 输出: a b
由上可述,能够直接做用于for
循环的数据类型有如下几种:一类是集合数据类型,如list
、tuple
、dict
、set
、str
等; 一类是generator
,包括生成器和带yield
的generator function。能够直接做用于 for
语句进行循环的对象称之为可迭代对象。
内置的数据类型(列表、元组、字符串、字典等)能够经过 for
语句进行迭代,咱们也能够本身建立一个容器,包含一系列元素,能够经过 for
语句依次循环取出每个元素,这种容器就是 迭代器(iterator)。
建立迭代器对象的好处是当序列长度很大时,能够减小内存消耗,由于每次只须要记录一个值即刻。
二、使用isinstance()
判断一个对象是不是迭代(Iterable)
对象:
>>> from collections import Iterable #导入Iterable(可迭代对象模块) >>> isinstance([],Iterable) True >>> isinstance((),Iterable) True >>> a = "abc" >>> isinstance("abc",Iterable) True >>> isinstance('b',Iterable) True >>> isinstance(100,Iterable) False
>>> isinstance((x for x in range(3)),Iterable)
True
使用isinstance()
判断一个对象是不是迭代器:
from collections import Iterator print (isinstance([],Iterator)) print (isinstance((),Iterator)) print (isinstance((x for x in range(3)),Iterator)) 输出: False False True
总结:由上得出,生成器、列表、元组、字符串都是可迭代对象,生成器必定是迭代器。数字是非可迭代对象。
三、除了用for遍历,迭代器还能够经过next()方法逐一读取下一个元素。要建立迭代器有3种方法,其中前两种分别是:
A、list
、dict
、str
虽然是Iterable(可迭代对象)
,却不是Iterator(迭代器)。但
内置函数 iter()
将可迭代对象转化为迭代器
列表迭代器
ita = iter([1,2,3,4]) print(type(ita)) #列表迭代器 print(next(ita)) print(next(ita)) print(next(ita)) 输出: <class 'list_iterator'> 1 2 3 逐一取值。注:把ita = iter([1,2,3,4])改成ita = iter((1,2,3,4)),则为元组迭代器。
B、 为容器对象添加 __iter__()
和 __next__()
方法(Python 2.7 中是 next()
);__iter__()
返回迭代器对象自己 self
,__next__()
则返回每次调用 next()
或迭代时的元素;
class Container: def __init__(self, start = 0, end = 0): self.start = start self.end = end def __iter__(self): print("[LOG] I made this iterator!") return self def __next__(self): print("[LOG] Calling __next__ method!") if self.start < self.end: i = self.start self.start += 1 return i else: raise StopIteration() c = Container(0, 3) for i in c: print(i) 输出: [LOG] I made this iterator! [LOG] Calling __next__ method! 0 [LOG] Calling __next__ method! 1 [LOG] Calling __next__ method! 2 [LOG] Calling __next__ method!
总结:
凡是可做用于for
循环的对象都是Iterable
类型;
凡是可做用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列(惰性计算,就是计算到的时候才打印出来,没计算到距不打印),查看迭代类型是否可使用next(),使用dir()去判断;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过能够经过iter()
函数得到一个Iterator
对象。
内置函数
abs()#绝对值 all()#只要一个为假,都是假 any()#只要一个为真,都是真 ascii()#把一个内存形式打印成字符串的格式 bin()#一个整数,十进制转二进制 bool()#布尔值,判断真假 bytearray() bytes() callable()#判断可调用的信息 chr()#利用数字打印asscii码 ord()#利用asscii码取对应的数字 compile()#用于底层,把代码进行编译的工具 complex() dict()#字典 dir()#查使用方法 divmod()#相除,返回余数 enumerate() eval() exec() filter()#一组数据里面,过滤你想要的数值,打印出来 如: res = filter(lambda n:n>5,range(10)) for i in res: print (i) map()#把后面的值放给前面出来,并把结果打印 res = map(lambda n:n*n,range(10)) for i in res: print (i) reduce()#2.7版本仍是能够直接调用,3版本之后都是放在模块里面了 import functools res = functools.reduce(lambda x,y:x+y,range(10)) print (res) frozenset()#冻结,不可变的集合 globals()#返回当前整个程序里面全部变量的key/values模式 hash()#中文名散列,处理过程,须要找到一个固定的映射关系,经过递归的二分查找进行划分归类查找。 hex()#把一个数字转成16进制 locals()#用于函数内部本地打印 object()#对象,用类的时候使用。一个个体,就是对象。每一个对象都有属于本身的属性。 oct()#八进制,逢8进1 pow()#多少次方 repr()#与ascii()一致 reversed()#反转 round()# round(1.222,2) 保留两位小数点 slice()#切片 如:d=range(10) t = d[slice(2,5)] sorted() #把字典排序,按key或values 来排序 如: a = {6:2,9:0,3:4,6:5,10:7,11:22} print (sorted(a.items())) 输出: [(3, 4), (6, 5), (9, 0), (10, 7), (11, 22)] print (sorted(a.items(),key = lambda n:n[1])) 输出: [(9, 0), (3, 4), (6, 5), (10, 7), (11, 22)] zip()#拉链式组合 如: a = [1,2,3,4] b = ["a","b","c","d"] for i in zip(a,b): print (i) 输出: (1, 'a') (2, 'b') (3, 'c') (4, 'd') __import__() #模块导入, 如:__import__("chen1203") 其余常见的内置函数不列举
对应函数的官网连接:https://docs.python.org/3/library/functions.html?highlight=built#ascii
一、序列化与反序列化的做用:
有两种方式json和pickle:json适合用其余的平台,pickle只能在python中应用。pickle 与json 模块一般是将python对象序列化为二进制流或文件,计算机底层是跟的二进制进行交互的。几
能够被序列化的类型有:
* None,True 和 False;
* 整数,浮点数,复数;
* 字符串,字节流,字节数组;
* 包含可pickle对象的tuples,lists,sets和dictionaries;
* 定义在module顶层的函数:
* 定义在module顶层的内置函数;
* 定义在module顶层的类;
* 拥有__dict__()或__setstate__()的自定义类型;
注意:对于函数或类的序列化是以名字来识别的,因此须要import相应的module。
序列化与反序列化,就是在内存之间进行数据翻译。pickle与json的功能效果差很少。但json并不彻底能序列化,因此出现python专用的pickle,pickle 只能在python中使用。
二、json 序列化与反序列化
A、第一步:经过序列化,把info信息从内存写到文件中底
#json 序列化 import json info = { "name": "chenchangqing", "work":"IT", "number":"400-100-119" } f = open("test.txt","w+") f.write(json.dumps(info)) #把info信息序列化 f.close()
B、第二步,查看test.txt 文件
#test.txt 文件内容的存储信息 {"number": "400-100-119", "work": "IT", "name": "chenchangqing"}
C、第三步、json 反序列化
#json 反序列化 import json file = open("test.txt","r") data = json.load(file)#经过使用json.load对文件信息反序列化出来。 print (data) file.close()
三、pickle 序列化与反序列化
pickle 是python通用的包括类、字典、对象、列表均可以序列化,json \ xml 都是平台通用。
# pickle 序列化语法 import pickle info = { "name": "chenchangqing", "work": "IT", "number": "400-100-119" } f = open("test_pickle.txt", "wb") #因为pickle是使用二进制,因此使用wb f.write(pickle.dumps(info)) f.close()
B、第二步、查看test_pickle 文件
#文件内容�}q(XnumberqX400-100-119qXworkqXITqXnameqX chenchangqingqu.
C、第三步、pickle 反序列化
#pikcel 反序列化 import pickle file = open("test_pickle.txt","rb") data = pickle.load(file) print (data) file.close() 输出: {'work': 'IT', 'name': 'chenchangqing', 'number': '400-100-119'}
总结:pickle 序列化,以下
为何要设计好目录结构?
设计一个层次清晰的目录结构,就是为了达到如下两点:
目录组织方式
Foo/
|-- bin/
| |-- foo
|
|-- foo/
| |-- tests/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- docs/
| |-- conf.py
| |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README
解析一下:
这里重点解析关于README的内容
它须要说明如下几个事项:
不一样目录间的模块调用。使用 from .. import .. 的模式导入
以上利用系统的环境变量,找到相对路径BASE_DIR ,使用from 导入模块。
做业需求:
模拟实现一个ATM + 购物商城程序
做业规划:
shopping.py buy 调用信用卡接口 直接扣款 ATM.py 提款 还款 查余额 查帐单 1 2 3 4 5 容许多个帐号登陆 容许帐号之间的登陆 提供还款接口 记录操做日志 提供管理接口,包括添加帐户、用户额度,冻结帐户等 用户认证用装饰器
实现ATM经常使用功能 功能所有用python的基础知识实现,用到了time\os\sys\json\open\logging\函数\模块知识, 主要帮给你们一个简单的模块化编程的示例 注意:只实现了"还款"和"取现功能" 程序结构: day5-atm/ ├── README ├── atm #ATM主程目录 │ ├── __init__.py │ ├── bin #ATM 执行文件 目录 │ │ ├── __init__.py │ │ ├── atm.py #ATM 执行程序 │ │ └── manage.py #ATM 管理端,未实现 │ ├── conf #配置文件 │ │ ├── __init__.py │ │ └── settings.py │ ├── core #主要程序逻辑都 在这个目录 里 │ │ ├── __init__.py │ │ ├── accounts.py #用于从文件里加载和存储帐户数据 │ │ ├── auth.py #用户认证模块 │ │ ├── db_handler.py #数据库链接引擎 │ │ ├── logger.py #日志记录模块 │ │ ├── main.py #主逻辑交互程序 │ │ └── transaction.py #记帐\还钱\取钱等全部的与帐户金额相关的操做都 在这 │ ├── db #用户数据存储的地方 │ │ ├── __init__.py │ │ ├── account_sample.py #生成一个初始的帐户数据 ,把这个数据 存成一个 以这个帐户id为文件名的文件,放在accounts目录 就好了,程序本身去会这里找 │ │ └── accounts #存各个用户的帐户数据 ,一个用户一个文件 │ │ └── 1234.json #一个用户帐户示例文件 │ └── log #日志目录 │ ├── __init__.py │ ├── access.log #用户访问和操做的相关日志 │ └── transactions.log #全部的交易日志 └── shopping_mall #电子商城程序,需单独实现 └── __init__.py
做业讲解