Python装饰器AOP 不定长参数 鸭子类型 重载(三)

简介: 1 可变长参数与关键字参数*args代表任意长度可变参数**kwargs代表关键字参数用*args和**kwargs只是为了方便并没有强制使用它们.缺省参数即是调用该函数时,缺省参数的值若未被传入,则传入默认预设的值。

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')
相关文章
|
1天前
|
存储 缓存 Python
野生的Python装饰器案例
野生的Python装饰器案例
|
1天前
|
开发者 Python
Python进阶--装饰器
Python进阶--装饰器
|
5天前
|
缓存 测试技术 数据处理
Python中的装饰器:优雅而强大的代码增强工具
在Python编程中,装饰器是一种强大的工具,可以用来增强函数和方法的功能,使其更加灵活和可复用。本文将深入探讨Python中装饰器的基本概念、使用方法和实际应用,帮助读者更好地理解和利用装饰器来提升代码的效率和可维护性。
|
5天前
|
缓存 开发者 Python
Python中的装饰器应用及性能优化
本文探讨了Python中装饰器的作用以及如何应用装饰器来提高代码的可读性和灵活性。同时,我们还将介绍一些性能优化的技巧,帮助开发者更好地理解和利用装饰器来提升Python程序的执行效率。
|
6天前
|
机器学习/深度学习 数据可视化 API
Python适合做哪些类型的项目?
【6月更文挑战第9天】Python适合做哪些类型的项目?
9 2
|
7天前
|
缓存 测试技术 Python
Python中的装饰器:优雅而强大的函数修饰工具
在Python编程中,装饰器是一种强大的工具,它可以让我们在不改变函数结构的情况下,对函数进行修饰和扩展。本文将深入探讨Python中装饰器的作用、原理及实际运用,帮助读者更好地理解和运用这一技术。
|
7天前
|
缓存 Python
Python中的装饰器:提升代码可读性和灵活性
在Python编程中,装饰器是一种强大的工具,它允许我们动态地修改函数或类的行为。本文将深入探讨Python中装饰器的使用方法以及如何利用装饰器提升代码的可读性和灵活性。通过实际示例,我们将展示装饰器在不同场景下的应用,帮助读者更好地理解和运用这一重要的编程技术。
|
8天前
|
监控 Python
探索Python装饰器:优雅地增强函数功能
探索Python装饰器:优雅地增强函数功能
|
8天前
|
机器学习/深度学习 算法 数据挖掘
掌握 Python 数字类型:从基础到高级应用的全面指南
掌握 Python 数字类型:从基础到高级应用的全面指南
|
8天前
|
Python
Python的类型对象
【6月更文挑战第5天】
11 3