Decorators 裝飾器

預備知識:

*args的使用方法,

  *args 用來將參數打包成tuple給函數體調用

  例子一:
>>> def function(*args):
    print(args, type(args))

    
>>> 
>>> function(1)
(1,) <class 'tuple'>
>>> function(2)
(2,) <class 'tuple'>

例子二:

def function(x, y, *args):
    print(x, y, args)

function(1, 2, 3, 4, 5)

output :

在這裏插入圖片描述

**kwargs的使用方法

  **kwargs 打包關鍵字參數成dict給函數體調用
def function(**kwargs):
    print( kwargs, type(kwargs))

function(a=2)

output :

>>> function(a=2)
{'a': 2} <class 'dict'>
>>> 

例子二:

def function(**kwargs):
    print(kwargs)

function(a=1, b=2, c=3)

output :

>>> function(a=1, b=2, c=3)
{'b': 2, 'a': 1, 'c': 3}
>>> 

注意點:參數arg、*args、**kwargs三個參數的位置必須是一定的。必須是(arg,*args,**kwargs)這個順序,否則程序會報錯。

def function(arg,*args,**kwargs):
    print(arg,args,kwargs)

function(6,7,8,9,a=1, b=2, c=3)

output :

>>> function(6,7,8,9,a=1, b=2, c=3)
6 (7, 8, 9) {'b': 2, 'a': 1, 'c': 3}
>>> 

Everything in Python is an object:
First of all let’s understand functions in Python:

def hi(name="yasoob"):
    return "hi " + name

print(hi())

在這裏插入圖片描述
若print (hi) #不帶括號,會打印什麼:
在這裏插入圖片描述
沒錯,它就是一個函數。
when you put a pair of parentheses after it, the function gets executed; whereas if you don’t put parenthesis after it, then it can be passed around and can be assigned to other variables without executing it. Did you get it?

def hi(name="yasoob"):
    return "hi " + name

print(hi())
# We can even assign a function to a variable like
greet = hi
# We are not using parentheses here because we are not calling the function hi
# instead we are just putting it into the greet variable. Let's try to run this

print(greet())
# output: 'hi yasoob'
print(greet)
#output :<function hi at 0x0000023D1411D7B8>
# Let's see what happens if we delete the old hi function!
del hi
print(hi())
#outputs: NameError: name 'hi' is not defined

print(greet())
#outputs: 'hi yasoob'

既然我們可以assign a function to a variable,那不妨試試:

>>> f = greet
>>> g = greet
>>> print (f)
<function hi at 0x0000023D1411D7B8>
>>> print (g)
<function hi at 0x0000023D1411D7B8>
>>> 

可見都指向了同一塊內存。

def hi(name="yasoob"):
    print("now you are inside the hi() function")

    def greet():
        return "now you are in the greet() function"

    def welcome():
        return "now you are in the welcome() function"

   
    print(welcome())#故意先寫welcome()
    print(greet())
    print("now you are back in the hi() function")

hi()

#output:now you are inside the hi() function
#       now you are in the welcome() function
#       now you are in the greet() function
#       now you are back in the hi() function

# This shows that whenever you call hi(), greet() and welcome()
# are also called. However the greet() and welcome() functions
# are not available outside the hi() function e.g:

greet()
#outputs: NameError: name 'greet' is not defined 在外面greet()就不可見了。

So now we know that we can define functions in other functions. In other words: we can make nested functions. Now you need to learn one more thing, that functions can return functions too.

It is not necessary to execute a function within another function, we can return it as an output as well:

def hi(name="yasoob"):
    def greet():
        return "now you are in the greet() function"

    def welcome():
        return "now you are in the welcome() function"

    if name == "yasoob":
        return greet
    else:
        return welcome

a = hi()
print(a)
#outputs: <function greet at 0x7f2143c01500>

#This clearly shows that `a` now points to the greet() function in hi()
#Now try this

print(a())
#outputs: now you are in the greet() function

既然函數可以傳遞給其他變量,那也是說可把函數作爲一個參數傳遞給另外一個函數:

def hi():
    return "hi yasoob!"

def doSomethingBeforeHi(func):
    print("I am doing some boring work before executing hi()")
    print(func())

doSomethingBeforeHi(hi)
#outputs:I am doing some boring work before executing hi()
#        hi yasoob!

好可,真正的裝飾器來了:

def a_new_decorator(a_func):

    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()")

        a_func()

        print("I am doing some boring work after executing a_func()")

    return wrapTheFunction

def a_function_requiring_decoration():
    print("I am the function which needs some decoration to remove my foul smell")

a_function_requiring_decoration()
#outputs: "I am the function which needs some decoration to remove my foul smell"

a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()

a_function_requiring_decoration()
#outputs:I am doing some boring work before executing a_func()
#        I am the function which needs some decoration to remove my foul smell
#        I am doing some boring work after executing a_func()

其實下面的纔是真正的:
哈哈哈.

def a_new_decorator(a_func):

    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()")

        a_func()

        print("I am doing some boring work after executing a_func()")

    return wrapTheFunction

def a_function_requiring_decoration():
    print("I am the function which needs some decoration to remove my foul smell")



print ("*******************************************************")

@a_new_decorator
def a_function_requiring_decoration():
    """Hey you! Decorate me!"""
    print("I am the function which needs some decoration to "\
          "remove my foul smell")

a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
#         I am the function which needs some decoration to remove my foul smell
#         I am doing some boring work after executing a_func()

#the @a_new_decorator is just a short way of saying:
#a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

參考:
http://book.pythontips.com/en/latest/decorators.html

再看一個例子:

import time
def calc_square(numbers):
    start = time.time()
    result = []
    for number in numbers:
        result.append (number*number)
    end = time.time()
    print ("calc_square took " + str((end-start)*1000) + "mil sec")
    return result

def calc_cube(numbers):
    start = time.time()
    result = []
    for number in numbers:
         result.append (number*number*number)
    end = time.time()
    print ("calc_cube took " + str((end-start)*1000) + "mil sec")
    return result


array = range(1,100000)
out_square = calc_square(array)
out_cube = calc_cube(array)

看下用了多久:calc_square 10ms
在這裏插入圖片描述

再對比下用裝飾器的效果:

import time

def timer(func):
    def wrapper(*args, **kwargs): 
        #https://www.geeksforgeeks.org/decorators-in-python/
        start = time.time()
        #result = []
        result = func(*args, **kwargs)
        end = time.time()
        print (func.__name__ +"took"  + str((end-start)*1000) + "mil sec")
        return result

    return wrapper

@timer
def calc_square(numbers):
    result = []
    for number in numbers:
        result.append (number*number)

    return result

@timer
def calc_cube(numbers):
    result = []
    for number in numbers:
         result.append (number*number*number)
    return result


#x= calc_square([1,2,3,4,5])
#print (x)

array = range(1,100000)
out_square = calc_square(array)
out_cube = calc_cube(array)

在這裏插入圖片描述
變長了一點點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章