Python学习week4

五迷三道 提交于 2020-02-08 22:50:14

装饰器:本质是函数,用来装饰其他的函数,为其它函数添加附加功能。

原则:不能改变被装饰函数的源代码和调用方式。

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

 


 

列表生成式:生成列表的简便方法。

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错误,返回值包含在StopIterationvalue中。

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循环的数据类型有以下几种:一类是集合数据类型,如listtupledictsetstr等;一类是generator,包括生成器和带yield的generator function。

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

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

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

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator,可以通过iter()函数获得一个Iterator对象。[http://www.cnblogs.com/alex3714/articles/5765046.html]

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))
序列化json.dumps()
import json
f=open('test.text','r')
data=json.loads(f.read())
print(data['name'])
反序列化json.loads()

 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)效果相同
序列化pickle.dumps()
import pickle
def hello(name):
    print('hello,',name)
f=open('test.text','rb')
data=pickle.loads(f.read())     #data=pickle.load(f)
data['func']('刚田武')
反序列化pickle.loads()

 

软件目录结构规范:层次清晰的目录结构规范有助于提高程序的可读性和可维护性。

Foo/
|-- bin/
|   |-- foo
|
|-- foo/
|   |-- tests/
|   |   |-- __init__.py
|   |   |-- test_main.py
|   |
|   |-- __init__.py
|   |-- main.py
|
|-- docs/
|   |-- conf.py
|   |-- abc.rst
|
|-- setup.py
|-- requirements.txt
|-- README

简要解释一下:

  1. bin/: 存放项目的一些可执行文件,当然你可以起名script/之类的也行。
  2. foo/: 存放项目的所有源代码。(1) 源代码中的所有模块、包都应该放在此目录。不要置于顶层目录。(2) 其子目录tests/存放单元测试代码; (3) 程序的入口最好命名为main.py
  3. docs/: 存放一些文档。
  4. setup.py: 安装、部署、打包的脚本。
  5. requirements.txt: 存放软件依赖的外部Python包列表。
  6. 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 , 刚田武

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!