Python学习week4
装饰器:本质是函数,用来装饰其他的函数,为其它函数添加附加功能。
原则:不能改变被装饰函数的源代码和调用方式。
1、函数即‘变量’,定义一个函数相当于把函数体赋值给函数名,匿名函数相当于只有函数体没有函数名
def func1(): print('in the function') func2=func1 #和普通的整数赋值一样:a=2 b=a print(b) func2()
2、高阶函数
3、嵌套函数
装饰器=高阶函数+嵌套函数
高阶函数:
1、把一个函数名当作实参传递给另外一个函数;(在不修改被装饰函数源代码的情况下为其添加功能)
2、返回值中包含函数名。(不修改函数的调用方式)
import time def bar(): time.sleep(2) print('in the bar') def timer(func): start_time=time.time() func() stop_time=time.time() print('the time of running is %s'%(stop_time-start_time)) timer(bar) 输出: in the bar the time of running is 2.0002079010009766
import time def bar(): time.sleep(2) print('in the bar') def test(func): print(func) #如果参数是函数,则此处打印的是函数在内存中的位置信息 func() return func test(bar) #将函数名作为实参传递给调用函数 #test(bar()) #错误用法,将函数返回值传递给调用函数,不符合高阶函数定义 输出: <function bar at 0x000001717B027F28> in the bar
嵌套函数:在一个函数的函数体内定义另一个函数,不是调用,是def定义
def test(): print('in the test') def inner(): #内部函数,相当于局部变量,只能在test()内部调用 print('in the inner') inner() test() 输出: in the test in the inner
装饰器:
import time def timer(func): #嵌套函数 def decorator(*args): start_time=time.time() func(*args) stop_time=time.time() print('the running time of this function is %s'%(stop_time-start_time)) return decorator #返回函数名,不能带有括号 @timer #相当于test=timer(test),timer(test)返回decorator()函数。 def test1(): time.sleep(2) print('in the test1') @timer def test2(name,age): print('in the test2:', name, age) test1() test2('刚田武',22) 输出: in the test1 the running time of this function is 2.000319242477417 in the test2: 刚田武 22 the running time of this function is 0.0
username,password='zhhy','123' def auth(auth_type): print('auth type:',auth_type) def outer_wrapper(func): def wrapper(*args, **kwargs): print('wrapper args:',*args,**kwargs) if auth_type == 'local': user_name = input('please input your name:').strip() pass_word = input('please input your password:').strip() if username == user_name and password == pass_word: print('\033[32;1mUser pass authentication\033[0m ') result = func(*args, **kwargs) print('after authentication') return result else: exit('\033[32;1mInvalid username or password\033[0m ') elif auth_type=='ldap': print('using ldap') return wrapper return outer_wrapper def index(): print('welcome to index page') @auth(auth_type='local') def home(): print('welcome to home page') return 'from home' @auth(auth_type='ldap') def bbs(): print('welcome to bbs page') home()
列表生成式:生成列表的简便方法。
print([i*2 for i in range(10)]) 输出: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
i*2可以换成func()。
生成器:generator=(i*2 for i in range(10))
1、数据较多并且有规律时,可以减少内存占用,要调用的数据才会产生;
2、不支持切片操作;
3、只有__next__()方法;
4、只保存当前调用数据。
generator=(i*2 for i in range(10)) print(generator.__next__()) print(generator.__next__()) 输出: 0 2
斐波那契数列:
def fib(max): n,a,b=0,0,1 while n<max: a,b=b,a+b n+=1 return b print(fib(10))
其中,a,b=b,a+b相当于:
tuple=(b,a+b) a=tuple[0] b=tuple[1]
改为生成器:yield b
def fib(): a,b=0,1 while True: yield b a,b=b,a+b f=fib() print(f.__next__())
含有yield的函数称为生成器,生成器的return语句和函数的不同,其return的值赋给异常StopIteration,用try可以捕获异常,避免程序出错。
如果一个函数定义中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator;
函数是顺序执行,遇到return
语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行;
用for
循环调用generator时,发现拿不到generator的return
语句的返回值。如果想要拿到返回值,必须捕获StopIteration
错误,返回值包含在StopIteration
的value
中。
def fib(max): n,a,b=0,0,1 while n<max: yield b a,b=b,a+b n+=1 return '---------done---------' f=fib(5) while True: try: # x=next(f) # print('f:',x) print(f.__next__()) except StopIteration as e: print('生成器返回值:',e.value) break 输出: 1 1 2 3 5 生成器返回值: ---------done---------
yield可以在单线程环境中进行类似并行计算,称为协程。
import time def consumer(name): #不断吃包子 print('[%s]来吃包子,'%name) while True: baozi=yield #baozi的值由send()方法传来 print('[%s]包子被[%s]吃了'%(baozi,name)) def producer(name): a=consumer('刚田武') #consumer是生成器,不会执行 b=consumer('胖虎') a.__next__() #调用next()后才会执行,consumer运行到baozi=yield处退出此生成器,等待send()方法传值。 b.__next__() print('[%s]开始做包子'%name) for i in range(5): time.sleep(2) print("做了2个包子") a.send('白菜馅') #send()传值给baozi后,a运行print('[%s]包子被[%s]吃了'%(baozi,name)),然后循环运行到baozi=yield跳出 b.send('番茄馅') producer("朱二娃") 输出: [刚田武]来吃包子, [胖虎]来吃包子, [朱二娃]开始做包子 做了2个包子 [白菜馅]包子被[刚田武]吃了 [番茄馅]包子被[胖虎]吃了
迭代器:
可以直接作用于for
循环的数据类型有以下几种:一类是集合数据类型,如list
、tuple
、dict
、set
、str
等;一类是generator
,包括生成器和带yield
的generator function。
这些可以直接作用于for
循环的对象统称为可迭代对象:Iterable
。
而生成器不但可以作用于for
循环,还可以被next()
函数不断调用并返回下一个值,直到最后抛出StopIteration
错误表示无法继续返回下一个值了。
可以被next()
函数调用并不断返回下一个值的对象称为迭代器:Iterator
。
生成器都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator,可以通过
。[http://www.cnblogs.com/alex3714/articles/5765046.html]iter()
函数获得一个Iterator
对象
from collections import Iterator from collections import Iterable print(isinstance([],Iterator)) #列表不是迭代器对象,返回False print(isinstance([],Iterable)) #列表是可迭代对象,返回True print(isinstance(iter([]),Iterator)) #iter()后的列表是可迭代对象,返回True 输出: False True True
json序列化和反序列化:可以把内存中的数据存储到硬盘中,便于下次从硬盘中读取数据,相当于把程序暂停。
只能进行简单的数据类型序列化,可以在不同编程语言或者程序之间交互数据。
import json info={"name":"刚田武",'age':20} f=open('test.text','w') print(json.dumps(info)) f.write(json.dumps(info))
import json f=open('test.text','r') data=json.loads(f.read()) print(data['name'])
pickle和json类似,优点是可以序列化所有数据类型,包括函数。序列化函数时,反序列化只能得到函数名,没有函数体,需要把函数体复制到反序列化中。可以更改函数体。
import pickle def hello(name): print('hello,',name) info={'name':'刚田武','age':20,'func':hello} f=open('test.text','wb') f.write(pickle.dumps(info)) #pickle.dump(info,f)效果相同
import pickle def hello(name): print('hello,',name) f=open('test.text','rb') data=pickle.loads(f.read()) #data=pickle.load(f) data['func']('刚田武')
软件目录结构规范:层次清晰的目录结构规范有助于提高程序的可读性和可维护性。
Foo/
|-- bin/
| |-- foo
|
|-- foo/
| |-- tests/
| | |-- __init__.py
| | |-- test_main.py
| |
| |-- __init__.py
| |-- main.py
|
|-- docs/
| |-- conf.py
| |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README
简要解释一下:
bin/
: 存放项目的一些可执行文件,当然你可以起名script/
之类的也行。foo/
: 存放项目的所有源代码。(1) 源代码中的所有模块、包都应该放在此目录。不要置于顶层目录。(2) 其子目录tests/
存放单元测试代码; (3) 程序的入口最好命名为main.py
。docs/
: 存放一些文档。setup.py
: 安装、部署、打包的脚本。requirements.txt
: 存放软件依赖的外部Python包列表。README
: 项目说明文件。[https://www.cnblogs.com/alex3714/articles/5765046.html]
从atm文件夹下的atm.py文件中调用core文件夹下的main.py的方法:
import os,sys BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #找到程序的根目录 sys.path.append(BASE_DIR) #添加环境变量,BASE_DIR是当前程序的根目录,便于调用其他文件夹下的程序文件。 from core import main from conf import setting main.login('刚田武')
其中main.py为:
def login(name): print('welcome to atm ,',name)
输出为:
welcome to atm , 刚田武