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. 可变参数类型
  2. 可变参数个数

一个对象的特征不是由它的类型决定,而是通过对象中的方法决定,所以函数重载在动态语言中就显得没有意义.

另外,一个基本的设计原则是,仅仅当两个函数除了参数类型和参数个数不同以外,其功能是完全相同的,此时才使用函数重载,如果两个函数的功能其实不同,那么不应当使用重载,而应当使用一个不同名的函数。

那么对于情况 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‘)

原文地址:https://www.cnblogs.com/why957/p/9193877.html

时间: 2024-11-05 11:57:29

Python装饰器AOP 不定长参数 鸭子类型 重载(三)的相关文章

python中函数的不定长参数

#定义一个含有不定长参数的函数,本例第三个参数*args def sum_nums(a,b,*args): print('_'*30) print(a) print(b) print(args) #调用函数: sum_nums(11,22,33,44,55,66,77) sum_nums(11,22,33) sum_nums(11,22) sum_nums(11)#错误调用,传递的参数不够 #输出结果: ______________________________ 11 22 (33, 44,

python装饰器同时支持有参数和无参数的练习题

''' 预备知识: …… @decorator def f(*args,**kwargs): pass # 此处@decorator  等价于 f = decorator(f) @decorator2(*args,**kwargs) def f2(*args,**kwargs): pass # 此处@decorator2(*args,**kwargs)  等价于: 第一步,执行函数decorator2(*args,**kwargs),获得中间结果temp;  第二步,执行装饰器函数(即@temp

Python装饰器示例

简单装饰器实现: import time #简单装饰器 def show_time(f): #嵌套函数 def inner(): begin = time.time() f() end = time.time() print('spend %s'%(end-begin)) return inner @show_time #foo=show_time(foo) def foo(): print('foo...') time.sleep(1) foo() 不定长参数装饰器: #不定长参数,功能函数加

python 装饰器与AOP

无高见 1.缓存 from functools import wraps lineseq = '==' * 20 def memo( func ): cache = {} @wraps( func ) def wrapper( *args ): result = cache.get( args ) if result is None: result = func( *args ) cache[args] = result return result return wrapper @memo de

一个关于python装饰器参数的问题

看到廖雪峰python教程上,python装饰器一章 https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318435599930270c0381a3b44db991cd6d858064ac0000 在最后的作业题上 再思考一下能否写出一个@log的decorator,使它既支持: @log def f(): pass 又支持: @log('execute') def f(

Java的不定长参数和Python的不定长参数对比

一:起因 (0)不定长参数,也叫可变的参数,就是再调用函数之前,并不确定到底需要传递多少个参数 (1)Java中的不定长参数用String... args / int... args等三个点来表示:Python中用*args元组来表示 / **args字典(map)来表示  (2)不定参数有两个规定:第一,方法的参数列表中最多只有一个不定长度的参数:第二,就是不定长度的数组的位置必须是最后一个参数.不然不能通过编译. 二:实例对比 (1)Python的不定长参数 第一种方法--以一个*开始的参数

python 装饰器 一 (简单不带参数的函数)

#coding=utf-8 #python 装饰器 '''     装饰器可以用def的形式来定义.装饰器接收一个可调用对象作为输入参数, 并返回一个新的可调用对象. 装饰器新建了一个可调用对象,也就是return 返回的函数funx, 在新增的函数中,可以添加我们需要的功能,并通过调用原有函数来实现原有函数的功能 ''' def deco(func):     '''         无参数装饰器,func为被装饰的函数     '''     def _deco():         pri

Python 不定长参数 *args, **dictargs

 1. 加了星号(*)的变量名会存放所有未命名的变量参数,不能存放dict,否则报错. 如: 1 def multiple(arg, *args): 2 print "arg: ", arg 3 #打印不定长参数 4 for value in args: 5 print "other args:", value 6 7 if __name__ == '__main__': 8 multiple(1,'a',True) 输出: 2. 加了星号(**)的变量名会存放所有

ZMAN的学习笔记之Python篇:函数可变长参数

ZMAN的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 这次来聊聊Python中函数的“可变长参数”,在实际中经常会用到哦~  一.什么是“可变长参数” “可变长参数”就是向一个函数传入不定个数的参数.比如我写一个函数:传入一个学生参加各科目考试的成绩,求平均分,如两个学生分别传入(92, 91, 88)和(88, 95),因为每个学生参加的考试个数不同,因此传入的参数个数也就不同了,遇到这种情况,我们在定义函数的时候,可以使用“可变长参数”. 二.在定义函数时使用“可变长参数