180114 用装饰器实现在不改变函数调用者的代码基础上,实现在函数执行前后分别打印"before" 和 "after"
def bef_aft(func): #定义一个名为bef_aft的函数名 ,()里的是函数的参数,设置为func, 函数的参数分为实参和形参,有个参数传递的概念 ,下面有很多的解释
def PRint(*arg,**kwarg): #再度定义一个PRint函数,里面的参数列表()是*arg 和**kwarg;关于*arg **kwarg。下面有详细的解释
print("before".center(50,"-")) # 输出内容()字符串before ,center 是内置函数,居中对齐的意思,()50,"-" ??什么意思?50个——?
res=func(*arg,**kwarg) #res 等于什么? res是定义的变量吗? 又出现了kwarg ,kw是key word arg呢?最常见的是出现在参数列表里面,实际上这个符号没有任何意义只是一个名称,它指向传递给这个方法来使用的参数,就像你的名字一样,比如你叫张三,可能你同事都习惯叫你小张,你弟弟妹妹都叫你哥,实际上都是
print(res) #输出:res
print("after".center(50,"-")) #好吧,这是和上上一行一起配合夹着res显示的。
return res #请问:print 和return 有什么区别??
return PRint #又见return 返回输出定义的PRint的内容。 @bef_aft #嵌入语法糖
def f1(arg): #函数定义 f1 参数(arg)
return arg + 1 #返回 arg+1 @bef_aft #一样嵌入语法糖
def f2(arg1, arg2): #函数定义f2 ()参数列表arg1,arg2
return arg1 + arg2 #返回值 arg1+arg2 f1(2) #问题来了,这是什么意思? 函数f1 参数2??位置2
f2(5,2) #同上,5,2
def f1(arg):
return arg + 1
def f2(arg1, arg2):
return arg1 + arg2
这要用装饰器来实现。
先说说函数定义,我们都知道,下面的代码定义了一个函数funcA
def funcA():
pass
显然,函数funcA没有参数(同时啥也不干:D)。
ps因为()里的是空的,没有参数。。。
下面这个函数funcB就有两个参数了, ps 分别是a 和 b ,括号里是参数列表。
def funcB(a, b):
print a
print b
调用的时候,我们需要使用函数名,加上圆括号扩起来的参数列表,比如 funcB(100, 99),执行结果是:
100
99
看下面一行
很明显,参数的顺序和个数要和函数定义ps funcB中一致,如果执行funcB(100),Python会报错的:
TypeError: funcB() takes exactly 2 arguments (1 given)
我们可以在函数定义中使用参数默认值,比如
def funcC(a, b=0):
print a
print b
在函数funcC的定义中,参数b有默认值,是一个可选参数,如果我们调用funcC(100),b会自动赋值为0。
OK,目前为止,我们要定义一个函数的时候,必须要预先定义这个函数需要多少个参数(或者说可以接受多少个参数)。一般情况下这是没问题的,但是也有在定义函数的时候,不能知道参数个数的情况(想一想C语言里的printf函数),在Python里,带*的参数就是用来接受可变数量参数的。看一个例子:
ps,简单的例子如下:
def funcD(a, b, *c):
print a
print b
print "length of c is: %d " % len(c) # ps :注意,这里我不是很懂,output是 4 ……哦,明白了!! 就是除了 1,2 之外的所有数字。
print c #同样不懂,返回了一个小括号的元组(3,4,5,6)
调用funcD(1, 2, 3, 4, 5, 6)结果是
1
2
length of c is: 4
(3, 4, 5, 6)
我们看到,前面两个参数被a、b接受了,剩下的4个参数,全部被c接受了,c在这里是一个tuple。我们在调用funcD的时候,至少要传递2个参数,2个以上的参数,都放到c里了,如果只有两个参数,那么c就是一个empty tuple。
好了,一颗星我们弄清楚了,下面轮到两颗星。
上面的例子里,调用函数的时候,传递的参数都是根据位置来跟函数定义里的参数表匹配的,比如funcB(100, 99)和funcB(99, 100)的执行结果是不一样的。在Python里,还支持一种用关键字参数(keyword argument)调用函数的办法,也就是在调用函数的时候,明确指定参数值付给那个形参。比如还是上面的funcB(a, b),我们通过这两种方式调用
funcB(a=100, b=99)
和
funcB(b=99, a=100)
结果跟funcB(100, 99)都是一样的,因为我们在使用关键字参数调用的时候,指定了把100赋值给a,99赋值给b。也就是说,关键字参数可以让我们在调用函数的时候打乱参数传递的顺序!
另外,在函数调用中,可以混合使用基于位置匹配的参数和关键字参数,前题是先给出固定位置的参数,比如
def funcE(a, b, c):
print a
print b
print c
调用funcE(100, 99, 98)和调用funcE(100, c=98, b=99)的结果是一样的。
好了,经过以上铺垫,两颗星总算可以出场了:
如果一个函数定义中的最后一个形参有 ** (双星号)def funcF(a, **b):前缀,
所有正常形参之外的其他的关键字参数都将被放置在一个字典中传递给函数,比如:
def funcF(a, **b): #定义一个函数 funcF ,参数列表是()里的 a 和 **b
print a #输出 a
for x in b: #生成器 for in ,用一个x来遍历b里面的数据。
print x + ": " + str(b[x]) #输出 ,x 然后 拼接 :号 再拼接 字符串类型的 列表。 这里有点不懂 + str(b[x]) b【x】??
调用funcF(100, c='你好', b=200),执行结果
100
c: 你好
b: 200
大家可以看到,b是一个dict对象实例,它接受了关键字参数b和c。
常规参数,*参数及**参数可以同时使用,具体怎么用?看看Python Reference Manual吧,关于Function definitions的那些章节。其实,笨想也能猜出来啊,o(∩_∩)o...
- 关于*arg和**kwarg
首先我们可以定一个简单的函数, 函数内部只考虑required_arg
这一个形参(位置参数)
def exmaple(required_arg):
print required_arg
exmaple("Hello, World!")
>> Hello, World!
那么,如果我们调用函数式传入了不止一个位置参数会出现什么情况?当然是会报错!
exmaple("Hello, World!", "another string")
>> TypeError: exmaple() takes exactly 1 argument (2 given)
def exmaple2(required_arg, *arg, **kwarg):
if arg:
print "arg: ", arg
if kwarg:
print "kwarg: ", kwarg
exmaple2("Hi", 1, 2, 3, keyword1 = "bar", keyword2 = "foo")
>> arg: (1, 2, 3)
>> kwarg: {'keyword2': 'foo', 'keyword1': 'bar'}
从上面的例子可以看到,当我传入了更多实参的时候
- *arg会把多出来的位置参数转化为
tuple
- **kwarg会把关键字参数转化为
dict
再举个例子,一个不设定参数个数的加法函数
def sum(*arg):
res = 0
for e in arg:
res += e
return res
print sum(1, 2, 3, 4)
print sum(1, 1)
>> 10
>> 2
当然,如果想控制关键字参数,可以单独使用一个*,作为特殊分隔符号。限于Python 3
,下面例子中限定了只能有两个关键字参数,而且参数名为keyword1
和keyword2
def person(required_arg, *, keyword1, keyword2):
print(required_arg, keyword1, keyword2)
person("Hi", keyword1="bar", keyword2="foo")
>> Hi bar foo
如果不传入参数名keyword1
和keyword2
会报错,因为都会看做位置参数!
person("Hi", "bar", "foo")
>> TypeError: person() takes 1 positional argument but 3 were given
调用函数时使用*arg和**kwarg
直接上例子,跟上面的情况十分类似。反向思维。
def sum(a, b, c):
return a + b + c
a = [1, 2, 3]
# the * unpack list a
print sum(*a)
>> 6
def sum(a, b, c):
return a + b + c
a = {'a': 1, 'b': 2, 'c': 3}
# the ** unpack dict a
print sum(**a)
>> 6
*arg是非关键字参数,用于元组,
**kwarg是关键字参数,用于字典
其中的 KW 代表关键字 可以看到,这两个是python中的可变参数。
*args表示任何多个无名参数,它是一个tuple;
**kwargs表示关键字参数,它是一个dict。并且同时使用*args和**kwargs时,必须*args参数列要在**kwargs前
180114 用装饰器实现在不改变函数调用者的代码基础上,实现在函数执行前后分别打印"before" 和 "after"的更多相关文章
- 谈谈Python中的decorator装饰器,如何更优雅的重用代码
众所周知,Python本身有很多优雅的语法,让你能用一行代码写出其他语言很多行代码才能做的事情,比如: 最常用的迭代(eg: for i in range(1,10)), 列表生成式(eg: [ x* ...
- python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解
1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题 ...
- python 内置函数和函数装饰器
python内置函数 1.数学相关 abs(x) 取x绝对值 divmode(x,y) 取x除以y的商和余数,常用做分页,返回商和余数组成一个元组 pow(x,y[,z]) 取x的y次方 ,等同于x ...
- python函数(3):装饰器
昨天学了很多函数方面的概念和知识其中有一个闭包的函数.很多人都对闭包的作用不是很清楚,今天我们就来认识一个新的知识点装饰器.它就是闭包函数的一个经典应用. 预习: 编写装饰器,为多个函数加上认证的功能 ...
- python装饰器小计
1.装饰器:本质是函数,是用来给其他函数添加附加扩展功能的函数,其返回值是一个函数(函数指针) 2.装饰器作用:不改变函数源代码和函数调用方式的前提下添加函数的附加功能. 3.装饰器储备知识点: A. ...
- Python全栈开发之---装饰器
1.装饰器的形成过程 import time def func1(): print('in func1') def timer(func): def inner(): start = time.tim ...
- python之装饰器函数
本章内容 引入 装饰器的形成过程 开放封闭原则 谈装饰器主要功能和装饰器固定结构 带参数的装饰器 多个装饰器装饰一个函数 引入 作为一个会写函数的python开发,我们从今天开始要去公司上班了.写了一 ...
- Python小白学习之路(二十四)—【装饰器】
装饰器 一.装饰器的本质 装饰器的本质就是函数,功能就是为其他函数添加附加功能. 利用装饰器给其他函数添加附加功能时的原则: 1.不能修改被修饰函数的源代码 2.不能修改被修饰函数的调用 ...
- python三大神器之装饰器
装饰器的形成过程 假如你要写一个计算函数执行时间的函数,代码如下: import time def func1(): print('in func1') def timer(func): def in ...
随机推荐
- 自学Zabbix3.8.2-可视化Visualisation-maps网络地图
自学Zabbix3.8.2-可视化Visualisation-maps网络地图 可以简单的理解为动态网络拓扑图,可以针对业务来配置zabbix map,通过map可以了解应用的整体状况:服务器是否异常 ...
- iKcamp出品微信小程序教学共5章16小节汇总(含视频)
- 封装一个button上带图片的,图片在上,文字在下的按钮
#import "CJShoppingDetailButton.h" @implementation CJShoppingDetailButton - (void)layoutSu ...
- CSS文字不换行,溢出省略
white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
- SpringMVC 返回json的两种方式
前后台数据交互使用json是一种很重要的方式.本文主要探讨SpringMVC框架使用json传输的技术. 请注意,本文所提到的项目使用Spring 版本是4.1.7,其他版本在具体使用上可能有不一样的 ...
- Linux 学习记录 一(安装、基本文件操作).
Linux distributions主要分为两大系统,一种是RPM方式安装软件的系统,包括Red Hat,Fedora,SuSE等都是这类:一种则是使用Debian的dpkg方式安装软件的 ...
- ucore lab1练习2 qemu+gdb 不能协作调试的问题make lab1-mon
本练习是qemu结合gdb调试,但是我做实验的时候并不能像视频输入make lab1-mon那样顺利调试,期间有各种error,后来我找到原因,请看解决方法. 请先把ucore_lab文件删除,以下全 ...
- csdn博客被删除联系客服恢复
前几天写了篇"如何使用shadowsocksFQ",居然被删除,我很郁闷,客服给我的回答是"影响了客户体验,网安查的严,不能带有FQ的信息出现" 我一直很郁闷, ...
- bzoj 4444: [Scoi2015]国旗计划
Description A国正在开展一项伟大的计划--国旗计划.这项计划的内容是边防战士手举国旗环绕边境线奔袭一圈.这 项计划需要多名边防战士以接力的形式共同完成,为此,国土安全局已经挑选了N名优秀的 ...
- 关于vue 框架与后台框架的混合使用的尝试------转载
这几天我在研究前台框架和后台框架融合的问题,进行了一些尝试; 我前台选择的是 vue,当然也可以选择 react 等其他 mvvm 框架,不过 vue 对于我来说是最熟悉的; 后台话,我选择的是 ph ...