装饰器

Posted alan-song

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了装饰器相关的知识,希望对你有一定的参考价值。

目录

装饰器

@ 装饰器函数名

myfun = 装饰器函数名(myfun)


函数的文档字符串
函数的文档字符串由函数的 __doc__ 属性绑定

模块
模块的分类:
内建模块  标准库模块  第三方模块

用户自己编写的模块

模块的导入语句有三种:
import 语句
from import 语句
from import * 语句


dir() 函数 返回当前作用域内有哪儿些变量

内建模块:
math   sys   time

 

装饰器

decorators(专业提高篇)
函数名是变量,它绑定一个函数
函数名 / 函数名()的区别

什么是装饰器
  装饰器是一个函数,主要作用是用来包装另一个函数或类(后面会讲)

作用:
  装饰的目的是在不改变原函数名(或类名)的情况下,改变被包装对象的行为

 


函数装饰器

指装饰器传入的是一个函数, 返回的也是一个函数

语法:
def 装饰器函数名(参数):
语句块
return 函数对象


@装饰器函数名1<换行>
@装饰器函数名2<换行>
def 函数名(形参列表):
语句块


例:

函数装饰器的定义用调用

技术分享图片
 1 def mydeco(fn):
 2     def fx():
 3         print("======这是myfunc调用前=======")
 4         fn()
 5         print(------这是myfunc调用后-------)#加fn()后, 闭包,def fx()
 6     return fx
 7 
 8 @mydeco#@等
 9 def myfunc():
10     print("myfunc被调用")
11 
12 # myfunc = mydeco(myfunc)#@等#原理就是改变原来变量绑定的函数
13 
14 
15 myfunc()
16 myfunc()
17 myfunc()
mydeco.py
技术分享图片
 1 [email protected]:~/python/20180717$ python3 mydeco.py 
 2 myfunc被调用
 3 myfunc被调用
 4 myfunc被调用
 5 
 6 [email protected]:~/python/20180717$ python3 mydeco.py 
 7 =============
 8 -------------
 9 =============
10 -------------
11 =============
12 -------------
13 [email protected]:~/python/20180717$ python3 mydeco.py 
14 =============
15 -------------
16 =============
17 -------------
18 =============
19 -------------
20 
21 [email protected]:~/python/20180717$ python3 mydeco.py 
22 ======这是myfunc调用前=======
23 myfunc被调用
24 ------这是myfunc调用后-------
25 ======这是myfunc调用前=======
26 myfunc被调用
27 ------这是myfunc调用后-------
28 ======这是myfunc调用前=======
29 myfunc被调用
30 ------这是myfunc调用后-------
31 
32 [email protected]:~/python/20180717$ python3 mydeco.py 
33 myfunc被调用
34 myfunc被调用
35 myfunc被调用
运行效果

 

 

函数的文档字符串
函数内第一次未被赋值给任何变量的字符串是次函数的文档字符串
不会被解释执行器忽略, 注释会, 所以不是注释是文档字符串
语法:
def 函数名(参数列表):
’函数文档字符串‘
函数语句块

例:
def myfun(name, x):
‘‘‘这是函数的文档字符串
name 表示人名
x 表示钱
‘‘‘
pass

>>> help(myfun)#查看

技术分享图片
 1 def myfunc():
 2     print("myfunc被调用")
 3 
 4 myfunc = lambda: print("hello")
 5 
 6 
 7 myfunc()
 8 myfunc()
 9 myfunc()
10 
11 
12 
13 myfunc()
14 myfunc()
myfunc

 

说明:
文档字符串通常用来说明本函数的功能和使用方法
在交互模式下输入:help(函数名)可以查看函数的‘文档字符串‘
函数的文档字符串绑定在函数的__doc__属性上


函数的 __doc__ 属性
  用于绑定函数的文档字符串
  __doc__ 属性用于记录文档字符串
  函数名.__doc__

函数的__name__ 属性
  __name__  用于记录函数的名称 x.__name__

 

 

>>> def infos(name:‘姓名‘, age:‘年龄‘=1, address:‘家庭住址‘=‘未填写‘) -> None:
... ‘这是帮注文档‘
... pass
...
>>> help(infos)

[1]+ Stopped python3

 

函数定义语句(def 语句) 的完整语法:
[@装饰器1]
[@装饰器2]
[...]
def 函数名([位置形参], [*元组形参], [命名关键字形参])
‘‘‘文档字符串‘‘‘
   语句块

注:[]代表其内部可以省略

>>>help("def") # 有兴趣的话可以看看,我是拒绝的.

L=[1,2,3]
def f(n=0,lst=[]):
lst.append(n)
print(lst)
f(4,L) # 打印结果是什么? [1,2,3,4]
f(5,L) # 打印结果是什么? [1,2,3,4,5]
f(100) [100]
f(100) # 打印结果是什么?为什么?[100,100]
f(200) [100,200]

 

交互退出exit()

装饰器的应用场景及用法

银行的存取款系统

技术分享图片
 1 # 一个函数被两个装饰器先后顺序装饰
 2 def massage_send(fn):
 3     def fy(name, x):
 4         fn(name, x)#先办理业务
 5         print(name, "办理了", x, 元的业务![工商银行])
 6     return fy#闭包
 7 
 8 
 9 
10 def privileged_check(fn):
11     def fx(name, x):#形参调用规则一致
12         print("正在检查权限...  通过")
13         fn(name, x)#调用被装饰函数save_money和withdraw
14     return fx
15 
16 @privileged_check
17 def save_money(name, x):
18         print(name, 存钱, x, )
19 
20 @massage_send  #先调用法送消息, 然后是权限, 最后是取钱  
21 @privileged_check
22 def withdraw(name, x):
23     print(name, 取钱, x, )
24 
25 save_money(小张, 200)
26 save_money(小杨, 500)
27 withdraw(小赵, 300)
28 withdraw(小洪, 1000)
29 
30 # 运行结果显示,存在对比,细看
31 # 正在检查权限...  通过
32 # 小张 存钱 200 元
33 # 正在检查权限...  通过
34 # 小杨 存钱 500 元
35 # 正在检查权限...  通过
36 # 小赵 取钱 300 元
37 # 小赵 办理了 300 元的业务![工商银行]
38 # 正在检查权限...  通过
39 # 小洪 取钱 1000 元
40 # 小洪 办理了 1000 元的业务![工商银行]
存取钱

 

 

模块 Module

模块是一个包含有一系列数据、函数、类等组成的程序组
模块是一个文件, 模块文件名通常以.py结尾

作用:
让一些相关 的数据, 函数,类等有逻辑的组织在一起, 使逻辑结构更加清晰
模块中的数据, 函数, 类等可提供给其他模块或程序使用
模块的分类:
1.内置模块(builtins)在解析器的内部可以直接使用(通常用C语言写的)
2.标准库模块,安装python时已安装且可以直接使用
3.第三方模块(通常为开源),需要自己安装
4.用户自己编定的模块(可以作为其他人的第三方模块)

 

模块的导入

import 语句
语法:
import 模块名1 [as 模块新名1], 模块名2 [as 模块新名2], .....


例:
import math #导入math模块
import sys, os

import copy
import sys
作用:
 将一个(某)模块整体导入到当前模块中

属性用法:
  模块名.属性名 
  或
  模块名.函数属性名(实参)
如:
math.factorial(5)

例:
math.factorial(5)#阶乘120
dir(odj)函数返回所有属性的字符串列表
help(obj)函数可以查看模块的相关文档字符串

 


 练习:
1.输入一个圆的半径, 打印出这个圆的面积
2.输入元的面积, 打印出这个圆的半径
(要求用math模块内的函数和变量

>>> import math as m, sys as s, os as o

技术分享图片
 1 import math
 2 r = float(input("请输入圆的半径:"))#float浮点数
 3 area = (math.pi)*r**2
 4 print("圆面积", area)
 5 
 6 
 7 import math as m
 8 area = float(input("请输入圆面积:"))
 9 r = m.sqrt(area/m.pi)
10 print("圆半径", r)
11 
12 import math
13 r = float(input("请输入圆的半径:"))
14 z = 2*(math.pi)*r
15 print(圆周长, z)
math模块

 


from import

语法:
form 模块名 import 模块属性名1[as 属性新名1], 模块属性名2 [as 属性新名2], ...
@从..     @导入


例:
import math as m,sys as s ...


作用:
将某模块的一个或多个属性导入到当前模块的作用域
示例:
from math import pi
from math import sin
from math import factorial as fac

python官方建议首选 import 语句(整体导入)
             再次 from import 语句
             最后 from import * 语句(可能导致变量名冲突)

 

from import * 语句

语法:
from 模块名 import *

作用:
将某模块的所有属性导入到当前的模块
例:
from math import *
print(sin(pi/2))
print(factorial)


dir 函数
dir([对象])      返回一个字符串的列表(变量名)

说明:
如果没有给参数调用, 则返回当前作用域内的所有变量的列表, 如果给定一个对象作为参数, 则返回这个对象的所有变量的列表

1)对于一个模块,返回这个模块的全部属性
    2)对于一个类对象,返回这个类的所有变量,并递归基类对象的所有变量
    3)对于其他对象,返回所有变量,类变量和基类变量


例:

>>> dir()
[‘__builtins__‘, ‘__doc__‘, ‘__loader__‘, ‘__name__‘, ‘__package__‘, ‘__spec__‘]
>>> pi = ‘派克笔‘
>>> dir()
[‘__builtins__‘, ‘__doc__‘, ‘__loader__‘, ‘__name__‘, ‘__package__‘, ‘__spec__‘, ‘pi‘]
>>> a = 100
>>> b = 200
>>> dir()
[‘__builtins__‘, ‘__doc__‘, ‘__loader__‘, ‘__name__‘, ‘__package__‘, ‘__spec__‘, ‘a‘, ‘b‘, ‘pi‘]
>>> import math#在本地建立模块
>>> dir()
[‘__builtins__‘, ‘__doc__‘, ‘__loader__‘, ‘__name__‘, ‘__package__‘, ‘__spec__‘, ‘a‘, ‘b‘, ‘math‘, ‘pi‘]
>>> from math import sin, cos, sqrt
>>> dir()
[‘__builtins__‘, ‘__doc__‘, ‘__loader__‘, ‘__name__‘, ‘__package__‘, ‘__spec__‘, ‘a‘, ‘b‘, ‘cos‘, ‘math‘, ‘pi‘, ‘sin‘, ‘sqrt‘]
>>> sqrt(100)
10.0
>>> from math import *
>>> dir()
[‘__builtins__‘, ‘__doc__‘, ‘__loader__‘, ‘__name__‘, ‘__package__‘, ‘__spec__‘, ‘a‘, ‘acos‘, ‘acosh‘, ‘asin‘, ‘asinh‘, ‘atan‘, ‘atan2‘, ‘atanh‘, ‘b‘, ‘ceil‘, ‘copysign‘, ‘cos‘, ‘cosh‘, ‘degrees‘, ‘e‘, ‘erf‘, ‘erfc‘, ‘exp‘, ‘expm1‘, ‘fabs‘, ‘factorial‘, ‘floor‘, ‘fmod‘, ‘frexp‘, ‘fsum‘, ‘gamma‘, ‘gcd‘, ‘hypot‘, ‘inf‘, ‘isclose‘, ‘isfinite‘, ‘isinf‘, ‘isnan‘, ‘ldexp‘, ‘lgamma‘, ‘log‘, ‘log10‘, ‘log1p‘, ‘log2‘, ‘math‘, ‘modf‘, ‘nan‘, ‘pi‘, ‘pow‘, ‘radians‘, ‘sin‘, ‘sinh‘, ‘sqrt‘, ‘tan‘, ‘tanh‘, ‘trunc‘]

 

技术分享图片
1 phone_number = input(‘‘1386-666-0006‘‘)
2 hiding_number = phone_number.replace(phone_number[:9],* * 9)#replace字符串替换
3 print(hiding_number)
电话号码运行
技术分享图片
1 print({} a word she can get what she {} for..format(With,came))
2 print({preposition} a word she can get what she {verb} for.format(preposition = With,verb = came))
3 print({0} a word she can get what she {1} for..format(With,came))
format占位符

 

内建模块

math 模块

数学模块用法:

import math
# 或
from math import *

变量 描述
math.e 自然对数的底e
math.pi 圆周率pi

函数名           描述
math.ceil(x) 对x向上取整,比如x=1.2,返回2
math.floor(x) 对x向下取整,比如x=1.2,返回1
math.sqrt(x) 返回x的平方根
math.factorial(x) 求x的阶乘
math.log(x[, base]) 返回以base为底x的对数, 如果不给出base,则以自然对数e为底
math.log10(x) 求以10为底x的对数
math.pow(x, y) 返回 x**y (x的y次方)
math.fabs(x) 返回浮点数x的绝对值
角度和弧度degrees互换
math.degree(x) 将弧度x转换为角度
math.radians(x) 将角度x转换为弧度
三角函数
math.sin(x) 返回x的正弦(x为弧度)
math.cos(x) 返回x的余弦(x为弧度)
math.tan(x) 返回x的正切(x为弧度)
math.asin(x) 返回x的反正弦(返回值为为弧度)
math.acos(x) 返回x的反余弦(返回值为为弧度)
math.atan(x) 返回x的反正切(返回值为为弧度)

 

>>> log(25,5)
2.0
>>> log(8, 2)
3.0
>>> log(2.71828)
0.999999327347282

 

时间模块


模块名 time
详见

时间模块 time

此模块提供了时间相关的函数,且一直可用

时间简介

公元纪年是从公元 0000年1月1日0时开始的

计算机元年是从1970年1月1日0时开始的,此时时间为0,之后每过一秒时间+1

UTC 时间 (Coordinated Universal Time) 是从Greenwich时间开始计算的.
UTC 时间不会因时区问题而产生错误

DST 阳光节约时间(Daylight Saving Time),又称夏令时, 是一个经过日照时间修正后的时间

时间元组

时间元组是一个9个整型元素组成的,这九个元素自前至后依次为:
四位的年(如: 1993)
月 (1-12)
日 (1-31)
时 (0-23)
分 (0-59)
秒 (0-59)
星期几 (0-6, 周一是 0)
元旦开始日 (1-366)
夏令时修正时间 (-1, 0 or 1).
注:
如果年份值小于100,则会自动转换为加上1900后的值

模块名: time
时间模块用法:

import time
# 或
from time import xxx
# 或
from time import *

变量 描述
time.altzone 夏令时时间与UTC时间差(秒为单位)
time.daylight 夏令时校正时间
time.timezone 本地区时间与UTC时间差(秒为单位)
time.tzname 时区名字的元组, 第一个名字为未经夏令时修正的时区名,
第一个名字为经夏令时修正后的时区名

注: CST为中国标准时间(China Standard Time UTC+8:00)
函数名 描述
time.time() 返回从计算机元年至当前时间的秒数的浮点数(UTC时间为准)
time.sleep(secs) 让程序按给定秒数的浮点数睡眠一段时间
time.gmtime([secs]) 用给定秒数转换为用UTC表达的时间元组
(缺省返回当前时间元组)
time.asctime([tuple]) 将时间元组转换为日期时间字符串
time.mktime(tuple) 将本地日期时间元组转换为新纪元秒数时间(UTC为准)
time.localtime([secs]) 将UTC秒数时间转换为日期元组(以本地时间为准)


import time
print("hello")
time.sleep(10)
print("world")


写一个程序, 输入你的出生日期
1.算出你已经出生多少天
2.算出你的出生那天是星期几

技术分享图片
 1 a = int(input("请输入你的生日年:"))
 2 b = int(input("请输入你的生日月:"))
 3 c = int(input("请输入你的生日日:"))
 4 import time
 5 s = time.time()#UTC
 6 h = time.mktime((a, b, c, 0, 0, 0, 0, 0, 0))#UTC
 7 print(h)
 8 t = (s -h)/(3600*24)#天数
 9 print(t)
10 w = time.localtime(s - h)
11 print(w)
12 
13 
14 import time
15 
16 year = int(input("请输入你的生日年:"))
17 month = int(input("请输入你的生日月:"))
18 day = int(input("请输入你的生日日:"))
19 
20 tuple_birth = (year, month, day, 0, 0, 0, 0, 0, 0)
21  
22 birth_second = time.mktime(tuple_birth)#得到出生时计算机内部的秒数
23 
24 second = time.time() - birth_second
25 #你一共活了多少秒
26 
27 print("您已经出生", second/60/60//24, )
28 
29 t = time.localtime(birth_second)#元组
30 print(t)
31 weeks ={0:"星期一", 1:"星期二", 2:"星期三", 3:"星期四", 4:"星期五", 5:"星期六", 6:"星期日"}
32 
33 print("您的出生那天是:",weeks[t[6]])
出生计算

 

 

系统模块 sys

运行时系统相关的信息

sys模块的属性
属性 描述
sys.path 模块搜索路径 path[0] 是当前脚本程序的路径名,否则为 ‘‘
sys.modules 已加载模块的字典
sys.version 版本信息字符串
sys.version_info 版本信息的命名元组
sys.platform 操作系统平台名称信息
sys.argv 命令行参数 argv[0] 代表当前脚本程序路径名
sys.copyright 获得Python版权相关的信息
sys.builtin_module_names 获得Python内建模块的名称(字符串元组)

 

sys模块的函数
函数名 描述
sys.exit([arg]) 退出程序,正常退出时sys.exit(0)
sys.getrecursionlimit() 得到递归嵌套层次限制(栈的深度)
sys.setrecursionlimit(n) 得到和修改递归嵌套层次限制(栈的深度)

技术分享图片
1 import sys
2 print("curversion_is", sys.version, sys.version_info)
3 # print(sys.modules)
4     sys.version_info>(2.7)
5 >>> import sys
6 >>> sys.platform
7 linux
sys.path列表

计算输入的参数个数

技术分享图片
 1 import sys
 2 print("当前您输入了", len(sys.argv), 个参数)
 3 print("这些参数是", sys.argv)#用户敲命令的时候输入的
 4 
 5 
 6 [email protected]:~/python/20180717$ python3 mydeco.py 
 7 当前您输入了 1 个参数
 8 这些参数是 [mydeco.py]
 9 [email protected]:~/python/20180717$ python3 mydeco.py  -l/home/tarena
10 当前您输入了 2 个参数
11 这些参数是 [mydeco.py, -l/home/tarena]
myargv.py
1 import sys
2 print("hello")
3 sys.exit(0)
4 print("world")

 


练习:
1.精编写函数fun, 其功能是计算下列多项式的和:
fn = 1 + 1/1! + 1/2! + 1/3! + 1/4! + .. + 1/n!
(建议用数学模型的factorial实现)
求当n 等于100时,fn的值
看一下fn(100)的值是什么

技术分享图片
 1 # 循环
 2 import math
 3 def fun(n):
 4     s = 0
 5     for i in range(0, n+1):
 6         s += 1/math.factorial(i)
 7     return s
 8 
 9 print(fun(100))
10 # 递归
11 import math
12 def fun(n):
13     if n == 0:
14         return 1
15     return 1/math.factorial(n)+fun(n-1)
16 
17 print(fun(100)
循环递归方式精编函数fun

2.写一个程序,以电子时钟格式:
HH:MM:SS格式显示时间
要求每隔一秒变化一次

技术分享图片
1 import time
2 def run():
3     while True:
4         t = time.localtime()
5         # print("%02d:%02d:%02d" % (t[3], t[4], t[5]), end=‘
‘)
6         print("%02d:%02d:%02d" % t[3:6], end=
)
7         time.sleep(1)
8 run()
简易版方式
技术分享图片
 1 import os
 2 import time
 3 def run():
 4     while True:
 5         t = time.localtime()
 6         # print("%02d:%02d:%02d" % (t[3], t[4], t[5]), end=‘
‘)
 7         print(+-----------------+)
 8         print("%02d:%02d:%02d" % (t[3:6]), end=
)
 9         os.system(clear)
10         print(+-----------------+)
11         time.sleep(1)
12 
13 print(Jack牌时钟)
14 run()
15 
16 from time import*
17 import os
18 def clock():
19     while True:
20         now_time=localtime()
21         t_clock=now_time[3:6]
22         os.system(clear)
23         time=%d时%d分%d秒%t_clock
24         print(Alan牌时钟)
25         print(+-------------+)
26         print(|+time.center(10)+|)
27         print(+-------------+)
28         sleep(1)
29 clock()
时钟显示,可跳转

3.写函数f(n)求下多项式的和
fn = 1/1 - 1/3 +1/5 -1/7 +1/9 ....1/(2*n-1)的和

求当n 取值为1000000
1)打印 f(1000000) 的值
2)打印 f(1000000)*4 的值,看看是什么

技术分享图片
1 def f(n):
2     s = 0
3     sign = 1#符号(正负)
4     for i in range(1, n+1):
5         s += sign * 1 /(2*i-1)#(-1)**(i+1) / (2 * x - 1)
6         sign *= -1
7 
8     return s
多项式的求和

 

装饰器为什么一定是闭包函数???

 

以上是关于装饰器的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象学习之八,装饰器

thymeleaf 片段渲染后重新加载 javascript

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码