python之路第四天

这是第四天的博客了。在紧张的一周的开发后,终于完成了作业 ATM+购物商城的系统  虽然还是有些瑕疵,来不及了,容错先不做了 哈哈 整理下今天学的内容吧,在用过后反而会有一些自己的感悟

今天我们学到了一个特别牛逼的东西 就是我们下面介绍的这个

一、装饰器

1.1 定义:

本质上是个函数,功能是装饰其他函数—就是为其他函数添加附加功能

1.2 装饰器原则:

1)  不能修改被装饰函数的源代码;

2)  不能修改被装饰函数的调用方式;

下面是一个简单的装饰使用方法、结合我们这周的开发项目,来说一下这个装饰器的使用方法

很多人学会了装饰器、也会写了,但是就是不知如何使用。实际上这就是一层窗户纸,只要你发力捅破他,你就会发现,他真的很牛逼,并且很酷炫。

首先说下我们的项目需求

作业需求:

模拟实现一个ATM + 购物商城程序

  1. 额度 15000或自定义
  2. 实现购物商城,买东西加入 购物车,调用信用卡接口结账
  3. 可以提现,手续费5%
  4. 每月22号出账单,每月10号为还款日,过期未还,按欠款总额 万分之5 每日计息
  5. 支持多账户登录
  6. 支持账户间转账
  7. 记录每月日常消费流水
  8. 提供还款接口
  9. ATM记录操作日志
  10. 提供管理接口,包括添加账户、用户额度,冻结账户等。。。
  11. 用户认证用装饰器  

首先我们来分析下下面装饰器的组成部分:

1.3 实现装饰器知识储备:

1.3.1 函数即“变量”

定义一个函数相当于把函数体赋值给了函数名

>>> def func():
......    print("这是一个函数")
>>> print(func)
>>> func()
<function func at 0x0000000000D2CD08>
这是一个函数
#func()是函数调用,而func是函数本身。

#要获得函数调用结果,我们可以把结果赋值给变量:
>>> a = func()
这是一个函数

#函数本身赋值给变量
>>> a = func
<function func at 0x0000000000D2CD08>

#结论:函数本身也可以赋值给变量,即:变量可以指向函数。

#猜想:是否可以通过变量直接调用函数?
>>> a=func
>>> a()
这是一个函数
#说明变量指向了func函数本身,直接调用a()和func()完全相同

1.3.2 高阶函数

高阶函数:能接收函数作为参数的函数。

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

  1. 某一函数当做参数传入另一个函数中(用处:在不修改被装饰函数源代码的情况下为其添加功能)

 

>>> def bar():

    ......print(‘in the bar‘)

>>> def foo(func):

    ......res=func()

    ......return res

>>> foo(bar)

in the bar

2、函数的返回值包含n个函数,n>0(用处:不修改函数调用方式)

>>>def bar():

    ......time.sleep(3)

    ......print("in the bar")

>>> def test2(func):

    ......print(func)

    ......return func

>>> print(test2(bar))

>>> bar = test2(bar)

>>> bar()

<function bar at 0x0000000000D6CD08>

<function bar at 0x0000000000D6CD08>

<function bar at 0x0000000000D6CD08>

in the bar 

高阶函数示例

  • map()

map函数会根据提供的函数对指定序列做映射。

map函数的定义:
map(function, sequence[, sequence, ...]) -> list
通过定义可以看到,这个函数的第一个参数是一个函数,剩下的参数是一个或多个序列,返回值是一个集合。
function可以理解为是一个一对一或多对一函数,map的作用是以参数序列中的每一个元素调用function函数,返回包含每次function函数返回值的list。

>>> def f(x):

   ...... return x*x

>>> r = map(f,[1,2,3,4,5,6,7,8,9])

>>> print(list(r))

[1, 4, 9, 16, 25, 36, 49, 64, 81]
  • reduce()

reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)    

>>> from functools import reduce

>>> def add(x, y):

    ......return x + y

>>> print(reduce(add, [1, 3, 5, 7, 9]))
  • filter()

filter函数会对指定序列执行过滤操作。
filter函数的定义:
filter(function or None, sequence) -> list, tuple, or string
function是一个谓词函数,接受一个参数,返回布尔值True或False。
filter函数会对序列参数sequence中的每个元素调用function函数,最后返回的结果包含调用结果为True的元素。
返回值的类型和参数sequence的类型相同。

>>> def is_odd(n):

        ...return n % 2 == 1

>>> print(list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])))

[1, 5, 9, 15]
  • sorted()

对列表内容进行正向排序,即可以保留原列表,又能得到已经排序好的列表;

>>> a = {6:2,8:0,1:4,-5:6,99:11,4:22}

>>> print(sorted(a.items())) #按key排序

[(-5, 6), (1, 4), (4, 22), (6, 2), (8, 0), (99, 11)]

>>> print(sorted(a.items(),key=lambda x:x[1])) #按value排序

[(8, 0), (6, 2), (1, 4), (-5, 6), (99, 11), (4, 22)]

1.3.3 嵌套函数

定义:在一个函数体内用def去声明一个新函数

>>> def foo():         #定义函数foo()

     ...m=3            #定义变量m=3;

     ...def bar():     #在foo内定义函数bar()

         ...n=4        #定义局部变量n=4

         ...print(m+n)  #m相当于函数bar()的全局变量

     ...bar()         #foo()函数内调用函数bar()

>>> foo()             #调用foo()函数

7  

1.3.4 装饰器

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

不带参数的装饰器

#装饰器
import time
def timer(func):
    def deco():
        start_time=time.time()
        func()                    #执行形参func()
        end_time=time.time()
        print("func runing time is %s"%(end_time-start_time))
    return deco                #返回函数deco的内存地址
def test1():
    print("in the test1")
    time.sleep(1)

test1 = timer(test1)            #重新赋值test1  此时test1=deco的内存地址
test1()                         #执行test1
###########打印输出###########
#in the test1
#func runing time is 1.0000572204589844

带固定参数的装饰器:

#装饰器
import time
def timer(func):
    def deco(name):
        start_time=time.time()
        func(name)                    #执行形参func()
        end_time=time.time()
        print("func runing time is %s"%(end_time-start_time))
    return deco                #返回函数deco的内存地址
@timer                          #test1 = timer(test1)  test1=deco
def test1(name):
    print("in the test1 name %s"%name)
    time.sleep(1)

test1("cc")                         #执行test1
###########打印输出###########
#in the test1 name cc
#func runing time is 1.0000572204589844

带返回值的装饰器:

#装饰器
import time
def timer(func):
    def deco(*args,**kwargs):
        start_time=time.time()
        res = func(*args,**kwargs)                    #执行形参func()
        end_time=time.time()
        print("func runing time is %s"%(end_time-start_time))
        return res
    return deco                #返回函数deco的内存地址
@timer                          #test1 = timer(test1)  test1=deco
def test1(name):
    print("in the test1 name %s"%name)
    time.sleep(1)
    return "return form test1"

print(test1("cc"))                  #执行test1
###########打印输出###########
#in the test1 name cc
#func runing time is 1.0000572204589844
#return form test1

通过以上我们会发现一个问题,选用的装饰器只能选择统一带形参或者统一不带形参;那么问题来了,我想要用一个装饰器,带形参的能调用,不带形参的也能调用,可不可以呢?

带不固定参数的装饰器:

# 装饰器
import time

def timer(func):
    def deco(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)  # 执行形参func()
        end_time = time.time()
        print("func runing time is %s" % (end_time - start_time))
    return deco  # 返回函数deco的内存地址
@timer  # test1 = timer(test1)  test1=deco
def test1(name):
    print("in the test1 name %s" % name)
    time.sleep(1)

@timer
def test2():
    print("in the test2 no name")
    time.sleep(1)

test1("cc")  # 执行test1
test2()        # 执行test2
###########打印输出###########
in the test1 name cc
func runing time is 1.0010571479797363
in the test2 no name
func runing time is 1.0000572204589844

终极版装饰器:

# Author:houyafan
import time

‘‘‘装饰器demo‘‘‘

def auth(type):  # 接受装饰器的变量
    def timer(func):  # 装饰器 接受源代码的方法内存地址
        def deco(*args, **kwargs):  # 新加的功能
            if type == ‘file‘:
                start = time.time()  # 新增的功能
                func(*args, **kwargs)  # 通过传过来的地址调用  为了兼容有参数的 和无参数的函数 可以默认填写上*args和**kwargs
                stop = time.time()  # 新增的功能
                print(stop - start)
            elif type == ‘abc‘:
                print("type is abc")

        return deco

    return timer

@auth(type=‘file‘)
def test1():
    time.sleep(1)
    print(‘test1‘)

@auth(type=‘abc‘)
def test2(name, age):
    time.sleep(1)
    print(‘test2‘, name, age)

test1()
test2(‘houyafan‘, 22)

我们根据上面的作业需求,和下面的装饰器代码思考下,这个作业中什么地方会用到装饰器,首先我们ATM系统最注重的就是,安全问题,首先校验的就是我们是否有登陆ATM,

然后我们才会有权限去操作我们的银行卡,这时就有一个问题出现了,我如何在每次选择一个功能是让他去校验我是否登陆了呢?

我们的装饰器的牛逼之处就出现了,如果我定义一个装饰器他是判断我是否有登陆?如果登陆了就执行我的功能逻辑代码,如果没登陆,就先登录后在执行我的代码。这样是不是就实现了在每个功能操作前,都校验下我是否已经登陆了呢? 答案是肯定的  好的 对于装饰器 通过我这个例子我想你应该能够举一反三在开发过程中想到如何用装饰器了吧。。。。

二、迭代器&生成器

时间: 2024-10-10 13:52:24

python之路第四天的相关文章

Python之路(第四十二篇)线程相关的其他方法、join()、Thread类的start()和run()方法的区别、守护线程

一.线程相关的其他方法 Thread实例对象的方法 # isAlive(): 返回线程是否活动的. # getName(): 返回线程名. # setName(): 设置线程名. ? threading模块提供的一些方法: # threading.currentThread(): 返回当前的线程对象. # threading.enumerate(): 返回一个包含正在运行的线程的list.正在运行指线程启动后.结束前,不包括启动前和终止后的线程. # threading.activeCount(

Python之路(第四十五篇)线程Event事件、 条件Condition、定时器Timer、线程queue

一.事件Event Event(事件):事件处理的机制:全局定义了一个内置标志Flag,如果Flag值为 False,那么当程序执行 event.wait方法时就会阻塞,如果Flag值为True,那么event.wait 方法时便不再阻塞. Event其实就是一个简化版的 Condition.Event没有锁,无法使线程进入同步阻塞状态. Event() set(): 将标志设为True,并通知所有处于等待阻塞状态的线程恢复运行状态. clear(): 将标志设为False. wait(time

Python之路(第四十七篇) 协程

一.协程介绍 协程:是单线程下的并发,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的. 协程相比于线程,最大的区别在于,协程不需要像线程那样来回的中断切换,也不需要线程的锁机制,因为线程中断或者锁机制都会对性能问题造成影响,所以协程的性能相比于线程,性能有明显的提高,尤其在线程越多的时候,优势越明显. 协程的好处: 无需线程上下文切换的开销 无需原子操作锁定及同步的开销 "原子操作(atomic operation

python之路十四

概述 HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,他是一种制作万维网页面标准语言(标记).相当于定义统一的一套规则,大家都来遵守他,这样就可以让浏览器根据标记语言的规则去解释它. 浏览器负责将标签翻译成用户"看得懂"的格式,呈现给用户!(例:djangomoan模版引擎) HTML文档 文档树 Doctype Doctype告诉浏览器使用什么样的html或xhtml规范来解析html文档 有和无的区别 BackCompat:标准兼容模式

Python之路【第三篇】:Python基础(二)

Python之路[第三篇]:Python基础(二) 内置函数 一 详细见python文档,猛击这里 文件操作 操作文件时,一般需要经历如下步骤: 打开文件 操作文件 一.打开文件 1 文件句柄 = file('文件路径', '模式') 注:python中打开文件有两种方式,即:open(...) 和  file(...) ,本质上前者在内部会调用后者来进行文件操作,推荐使用 open. 打开文件时,需要指定文件路径和以何等方式打开文件,打开后,即可获取该文件句柄,日后通过此文件句柄对该文件操作.

Python之路【第二篇】:Python基础(一)

Python之路[第二篇]:Python基础(一) 入门知识拾遗 一.作用域 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. 1 2 3 if 1==1:     name = 'wupeiqi' print  name 下面的结论对吗? 外层变量,可以被内层变量使用 内层变量,无法被外层变量使用 二.三元运算 1 result = 值1 if 条件 else 值2 如果条件为真:result = 值1如果条件为假:result = 值2 三.进制 二进制,01 八进

Python之路【第八篇】:堡垒机实例以及数据库操作

Python之路[第八篇]:堡垒机实例以及数据库操作 堡垒机前戏 开发堡垒机之前,先来学习Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作 SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: + import paramiko transport = paramiko.Transport(('hostname', 22)) transport.connect(username='wupeiqi', password='123') ssh

Python之路【第十六篇】:Django【基础篇】

Python之路[第十六篇]:Django[基础篇] Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. 基本配置 一.创建django程序 终端命令:django-admin startproject sitename IDE创建Django程序时,本质上都是自动执行上述命令 其他常用命令: python manage.py runserver

Python之路【第六篇】:socket

Python之路[第六篇]:socket Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. socket起源于Unix,而Unix/Linux基本哲学之一就是"一切皆文件",对于文件用[打开][读写][关闭]模式来操作.socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO.打开.关闭