Python装饰器AOP 不定长参数 鸭子类型 重载(三)
1 可变长参数与关键字参数
*args
代表任意长度可变参数
**kwargs
代表关键字参数
用*args
和**kwargs
只是为了方便并没有强制使用它们.
缺省参数即是调用该函数时,缺省参数的值若未被传入,则传入默认预设的值。
注意 : 须将所有带有默认值的参数置于参数列表的末尾。
def print_info(name, age = 18,gender = True )
print_info("zhan", gender = False )
def demo(num, *nums ,**nums )
当你不确定你的函数里将要传递多少参数时你可以用*args
.例如,它可以传递任意数量的参数:
>>> def print_everything(*args):
for count, thing in enumerate(args):
... print '{0}. {1}'.format(count, thing)
...
>>> print_everything('apple', 'banana', 'cabbage')
0. apple
1. banana
2. cabbage
相似的,**kwargs
允许你使用没有事先定义的参数名:
>>> def table_things(**kwargs):
... for name, value in kwargs.items():
... print '{0} = {1}'.format(name, value)
...
>>> table_things(apple = 'fruit', cabbage = 'vegetable')
cabbage = vegetable
apple = fruit
*args
和**kwargs
可以同时在函数的定义中,但是*args
必须在**kwargs
前面.
当调用函数时你也可以用*
和**
语法.例如:
>>> def myPrint(a, b, c):
... print 'a = {0}, b = {1}, c = {2}'.format(a,b,c)
...
>>> mylist = ['aardvark', 'baboon', 'cat']
>>> myPrint(*mylist)
a = aardvark, b = baboon, c = cat
就像你看到的一样,它可以传递列表(或者元组)的每一项并把它们解包.注意必须与它们在函数里的参数相吻合.当然,你也可以在函数定义或者函数调用时用*.
2 面向切面编程AOP和装饰器
AOP实际就是面向切面编程,python实现方法是采用装饰器模式.
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
def makebold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped
def makeitalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
@makebold
@makeitalic
def hello():
return "hello world"
print hello() ## returns <b><i>hello world</i></b>
#通过两个装饰器实现对目标函数的包装
理解装饰器首先理解python函数同样是对象,既然是对象就可以作为函数的返回值,可以执行复制,添加属性,作为函数参数传递,这些就是实现装饰器的基础
def bread(func):
def wrapper():
print "</''''''\>"
func()
print "<\______/>"
return wrapper
def ingredients(func):
def wrapper():
print "#tomatoes#"
func()
print "~salad~"
return wrapper
def sandwich(food="--ham--"):
print food
sandwich()
#outputs: --ham--
sandwich = bread(ingredients(sandwich)) #装饰器实际就是函数调用
sandwich()
#输出:
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>
作为程序员必须学会偷懒,于是python采用@作为装饰器语法糖,并学习一些高级用法:
@bread
@ingredients
def sandwich(food="--ham--"):
print food
sandwich()
#输出: 是不是觉得简单很多啦!
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>
#改变顺序会有影响的,执行顺序是先里面@ingredients,在执行@bread
装饰器的传参
def a_decorator_passing_arguments(function_to_decorate):
def a_wrapper_accepting_arguments(arg1, arg2):
print "I got args! Look:", arg1, arg2
function_to_decorate(arg1, arg2)
return a_wrapper_accepting_arguments
# 当你调用装饰器返回的函数时,也就调用了包装器,把参数传入包装器里,
# 它将把参数传递给被装饰的函数里.
@a_decorator_passing_arguments
def print_full_name(first_name, last_name):
print "My name is", first_name, last_name
print_full_name("Peter", "Venkman")
# 输出:
#I got args! Look: Peter Venkman
#My name is Peter Venkman
装饰器装饰类方法
def method_friendly_decorator(method_to_decorate):
def wrapper(self, lie):
lie = lie - 3 # 女性福音 :-)
return method_to_decorate(self, lie)
return wrapper
class Lucy(object):
def __init__(self):
self.age = 32
@method_friendly_decorator#装饰类方法
def sayYourAge(self, lie):
print "I am %s, what did you think?" % (self.age + lie)
l = Lucy()
l.sayYourAge(-3)
#输出: I am 26, what did you think?
装饰器自己传参数
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2):
print("I make decorators! And I accept arguments:", decorator_arg1, decorator_arg2)
def my_decorator(func):
print("I am the decorator", decorator_arg1, decorator_arg2)
# 不要忘了装饰器参数和函数参数!
def wrapped(function_arg1, function_arg2) :
print ("\t- from the decorator: {0} {1}\n"
"\t- from the function call: {2} {3}\n"
"Then I can pass them to the decorated function"
.format(decorator_arg1, decorator_arg2,
function_arg1, function_arg2))
return func(function_arg1, function_arg2)
return wrapped
return my_decorator
@decorator_maker_with_arguments("Leonard", "Sheldon")
def decorated_function_with_arguments(function_arg1, function_arg2):
print ("I am the decorated function and only knows about my arguments: {0}"
" {1}".format(function_arg1, function_arg2))
decorated_function_with_arguments("Rajesh", "Howard") #调用函数
#输出:
#I make decorators! And I accept arguments: Leonard Sheldon
#I am the decorator. Leonard Sheldon
# - from the decorator: Leonard Sheldon
# - from the function call: Rajesh Howard
#Then I can pass them to the decorated function
#I am the decorated function and only knows about my arguments: Rajesh Howard
3 鸭子类型
“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
我们并不关心对象是什么类型,到底是不是鸭子,只关心行为。
比如在python中,有很多file-like的东西,比如StringIO,GzipFile,socket。它们有很多相同的方法,我们把它们当作文件使用。又比如list.extend()方法中,我们并不关心它的参数是不是list,只要它是可迭代的,所以它的参数可以是list/tuple/dict/字符串/生成器等.
鸭子类型在动态语言中经常使用,非常灵活,使得python不像java那样专门去弄一大堆的设计模式。
class duck():
def walk(self):
print('I walk like a duck')
def swim(self):
print('i swim like a duck')
class person():
def walk(self):
print('this one walk like a duck')
def swim(self):
print('this man swim like a duck')
def watch_duck(animal): #定义一个函数,接受animal参数,需要具有walk swim两项本领
animal.walk()
animal.swim()
small_duck = duck() #实例化鸭子
watch_duck(small_duck) #能调用就认为是鸭子类型
输出 >>
I walk like a duck
i swim like a duck
duck_like_man = person() #实例化人,但是人同样有walk swim方法
watch_duck(duck_like_man) #同样被认为是鸭子类型
输出 >>
this one walk like a duck
this man swim like a duck
class Lame_Foot_Duck():
def swim(self):
print('i am lame but i can swim')
lame_duck = Lame_Foot_Duck() #实例化蹩脚的鸭子,类下只具有swim方法
watch_duck(lame_duck) #虽然是鸭子,但是不被认为是鸭子类型
输出 >>
AttributeError: Lame_Foot_Duck instance has no attribute 'walk'
4 python中重载
函数重载主要是为了解决两个问题。
- 可变参数类型
- 可变参数个数
一个对象的特征不是由它的类型决定,而是通过对象中的方法决定,所以函数重载在动态语言中就显得没有意义.
另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两个函数的功能其实不同,那么不应当使用重载,而应当使用一个不同名的函数。
那么对于情况 1 ,函数功能相同,但是参数类型不同,python 如何处理?答案是根本不需要处理,因为 python 可以接受任何类型的参数,如果函数的功能相同,那么不同的参数类型在 python 中很可能是相同的代码,没有必要做成两个不同函数。
那么对于情况 2 ,函数功能相同,但参数个数不同,python 如何处理?大家知道,答案就是缺省参数。对那些缺少的参数设定为缺省参数即可解决问题。因为你假设函数功能相同,那么那些缺少的参数终归是需要用的。
好了,鉴于情况 1 跟 情况 2 都有了解决方案,python 自然就不需要函数重载了
class Write:
@staticmethod
def write(output,content):
#output对象只要实现write方法,不管接受的类型
output.write(content)
#stringIO类型
output = StringIO.StringIO()
Write.write(output,'helloworld')
#file类型
output = open('out.txt','w')
Write.write(output,'helloworld')
Python装饰器AOP 不定长参数 鸭子类型 重载(三)的更多相关文章
- python——装饰器(不定长参数,闭包,装饰器)示例
def func(functionName): print("正在装饰") def func_in(*args, **kargs): print("------func_ ...
- python 装饰器修改调整函数参数
简单记录一下利用python装饰器来调整函数的方法.现在有个需求:参数line范围为1-16,要求把9-16的范围转化为1-8,即9对应1,10对应2,...,16对应8. 下面是例子: def fo ...
- python函数中的不定长参数
python自定义函数中有两中不定长参数,第一种是*name,第二种是**name.加了星号 * 的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数.加了两个星号 ** 的参数会以字典的 ...
- python中函数的不定长参数
例1: #定义一个含有不定长参数的函数,本例第三个参数*args def sum_nums(a,b,*args): print('_'*30) print(a) print(b) print(args ...
- python装饰器同时支持有参数和无参数的练习题
''' 预备知识: …… @decorator def f(*args,**kwargs): pass # 此处@decorator 等价于 f = decorator(f) @decorator2 ...
- python 装饰器 (多个参数的函数,带参数的装饰器)
最简单的模板是这样的 #-*-coding:utf-8-*- def outer(func): def inner(): print 'before' func() print 'after' # r ...
- Python装饰器:套层壳我变得更强了
Python装饰器:套层壳我变得更强了 Python装饰器:套层壳我变得更强了 关于作用域和闭包可以聊点什么? 什么是作用域 什么是闭包 装饰器:套层壳我变得更强了 参考资料 昨天阅读了<Pyt ...
- python不定长参数 *argc,**kargcs(19)
在 python函数的声明和调用 中我们简单的了解了函数的相关使用,然而在函数传递参数的时候,我们埋下了一个坑,关于不定长参数的传递我们还没有讲,今天这篇文章主要就是讲解这个问题. 一.函数不定长参数 ...
- python函数中的参数(关键字参数,默认参数,位置参数,不定长参数)
默认参数:定义函数的时候给定变量一个默认值. def num(age=1): 位置参数:调用函数的时候根据定义函数时的形参位置和实参位置进行引用. 关键字参数:如果定义的函数中含有关键字参数,调用函数 ...
随机推荐
- 在windows10下vs2017配置opencv4.0.0
第一次配置时,有些.dll文件出错,所以用重新下载opencv配置了一遍,终于可以了,喜极而泣! 一.下载OpenCV4.0 直接到官网https://opencv.org/下载 然后在下个页面选择 ...
- pip安装时的异常,找不到lib2to3\\Grammar.txt
[From] http://jahu.iteye.com/blog/2353325 异常 : [Errno 2] No such file or directory: 'd:\\python\\pyt ...
- html自定义垂直导航菜单(多级导航菜单,去掉font-awesome图标,添加自己的箭头图标)
这次在原先html自定义垂直导航菜单的基础上做了比较大的改动: 1.去掉了font-awesome图标,上级菜单右边的箭头是自己用css写的,具体参考<css三角箭头>. 2.去掉了初始化 ...
- MySql——安装与配置与启动和停止
在Linux上安装mysql数据库,我们可以去其官网上下载mysql数据库的rpm包,http://dev.mysql.com/downloads/mysql/5.6.html#downloads,大 ...
- Angular4+NodeJs+MySQL 入门-01
有一定的后台开发经验ES6语法.后台没有用框架来,纯自己写.会sql语句 安装NodeJS的安装 从网上下载 https://nodejs.org/en/ 选择自己,我用的是最新版本 Angular ...
- (转)Shell中read的用法详解
Shell中read的用法详解 原文:http://blog.csdn.net/jerry_1126/article/details/77406500 read的常用用法如下: read -[pstn ...
- HttpServlet的请求转发理解
一个http请求的流转,其实主要涉及到五部分的内容,第一部分就是request所包含的参数,也就是request.getAttribute能获取的东西:第二部分是request所携带的内容实体,这部分 ...
- 揭秘TDSQL全时态数据库系统的核心技术
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由腾讯技术工程官方号发表在腾讯云+社区 Design 本节讨论T-TDSQL的关键之处,即影响T-TDSQL架构的设计之处.一是新的数据 ...
- 解决引入外部文件(图片、js等)出现 403 net::ERR_ABORTED 的问题
页面中引入外网的链接资源,会产生一个新的http请求.为了安全(URL里可能包含用户信息),浏览器一般都会给这写请求头加上表示来源的referrer 字段. 所以,此时我们需要隐藏外部链接中的refe ...
- python网络编程——简单例子
客户端(client.py) import socket import sys port = 70 host = sys.argv[1] filename = sys.argv[2] s = sock ...