装饰器
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()
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()
说明:
文档字符串通常用来说明本函数的功能和使用方法
在交互模式下输入: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)
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‘))
内建模块
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‘
计算输入的参数个数
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‘]
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)
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
装饰器为什么一定是闭包函数???
以上是关于装饰器的主要内容,如果未能解决你的问题,请参考以下文章