python【第二篇】函数

在 Python 中, 整数、 字符串、字典、函数、类都是一等对象(均可作为常规变量处理)

python函数定义

在 Python 中, 函数是一等对象。 
“一等对象”定义为满⾜下述条件的程序实体:
1.在运行时创建
2.能赋值给变量或数据结构中的元素
3.能作为参数传给函数
4.能作为函数的返回结果
由于以上4点特性,python具有函数式编程的风格

变量

变量解析

局部作用域-》外部嵌套作用域-》全局作用域-》内建作用域

a=1
def f():
    print a

f()
#########
1
def f():
    x=1
    def fun():
        print x
    return fun

f()()
#########
1
def f():
    m = 0
    def f2():
        m = 1
        print m

    print m
    f2()
    print m

f()
#########
0
1
0

变量修改

1.python默认按引用赋值,即使是数字等基本类型也是按引用赋值

2.函数内部默认不能修改函数外部变量的引用,使用global可以改变全局变量的引用,但无法改变函数外部作用域(即外层嵌套函数)的引用

3.函数内部可以修改外部容器变量的值

# python默认按引用赋值
a = 1
b = a

x = [1, 2]
y = x

print('id(a):', id(a), 'id(b):', id(b))
print('id(x):', id(x), 'id(y):', id(y))
print('\n')

b = 2
y = [3, 4]

print('id(a):', id(a), 'id(b):', id(b))
print('id(x):', id(x), 'id(y):', id(y))

###
id(a): 1445593552 id(b): 1445593552
id(x): 1913825104328 id(y): 1913825104328


id(a): 1445593552 id(b): 1445593584
id(x): 1913825104328 id(y): 1913825104264

 

# 修改引用

x = [1]
def f():
    print id(x),x
    def fun():
        global x
        x=[2]
        print id(x),x
    return fun

f()()

#######
60219080 [1]
60304264 [2]
# 修改引用
# global代表修改全局变量,不能修改外部做作用域的局部变量(如外层嵌套函数的局部变量)
x=100
def fun():
    global x
    x += 1
    print id(x), x

print id(x),x
fun()
#######
44329760 100
44329736 101
# 修改值而非引用

def f():
    x = [1]
    print id(x),x
    def fun():
        x[0]=2
        print id(x), x

    return fun

f()()
#######
54189768 [1]
54189768 [2]
# 修改值而非引用

x = [1]
def f():
    def fun():
        print id(x), x
        x[0]=2
        print id(x), x
    return fun

f()()
########
52485832 [1]
52485832 [2]

函数参数

默认参数

默认参数有个坑,如果是可变对象,每次调用函数会保存上次的数据,因为默认参数指向一个全局的对象

所以,定义默认参数要牢记一点:默认参数指向可变对象要注意可能出现的问题!至于什么是不可变对象,click this

 

示例一:这个很清楚,b是全局变量,每次调用函数时a都是指向b,即每次调用函数时a就是b

b = []
def fun1(a):
    a.append(1)
    print(a)

fun1(b)  # [1]
fun1(b)  # [1,1]
fun1(b)  # [1,1,1]

示例二:这个也很清楚,示例一的改版,b是全局变量,每次调用函数时a都是指向b,即每次调用函数时a就是b

b = []
def fun1(a=b):
    a.append(1)
    print(a)

fun1()  # [1]
fun1()  # [1,1]
fun1()  # [1,1,1]

示例三: 重点来了,a=[ ]中的[]其实就是全局对象,只不过这个对象没有全局变量b指向它

def fun1(a=[]):
    a.append(1)
    print(a)

fun1()  # [1]
fun1()  # [1,1]
fun1()  # [1,1,1]

print(id([1]))      # 1868746959944
print(id([1,1]))    # 1868746959944
print(id([1,1,1]))  # 1868746959944

多类型传值

(*解析非字典数据,**解析字典)

n [1]: def fun(x,y,z):
   ...:     return x+y+z
   ...: 

In [2]: t=(1,2,3)

In [3]: t2=(4,5)

In [4]: fun(*t)
Out[4]: 6

In [2]: l=[1,2,3]

In [3]: fun(*l)
Out[3]: 6

In [5]: fun(3,*t2)
Out[5]: 12

In [6]: d={'x':1,'y':3,'z':5}
In [7]: d2={'y':3,'z':5}

In [8]: fun(**d)
Out[8]: 9

In [9]: fun(1,**d2)
Out[9]: 9
View Code

冗余参数 

(*把参数封装成元组,**把参数封装成字典)

In [1]: def fun(x,*args,**kwargs):
   ...:         print x
   ...:         print args
   ...:         print kwargs
   ...:     

In [2]: fun(1)
()
{}

In [3]: fun(1,2)
(2,)
{}

In [4]: fun(1,2,'a')
(2, 'a')
{}

In [5]: fun(1,2,'a',[1,2,],y=2)
(2, 'a', [1, 2])
{'y': 2}

In [6]: fun(1,2,'a',[1,2,],y=2,z=3)
(2, 'a', [1, 2])
{'y': 2, 'z': 3}

In [7]: fun(1,2,'a',[1,2,],*(1,2))
(2, 'a', [1, 2], 1, 2)
{}

In [8]: fun(1,2,'a',[1,2,],a=3,**{'b':666})
(2, 'a', [1, 2])
{'a': 3, 'b': 666}
View Code

lambda表达式

定义:精简的函数

语法:lambda 参数:表达式

优点:1.省去定义函数的过程让代码更简洁;2.不会被重复使用的函数用lamba替代可省略函数的命名;3.有时让代码更容易理解

In [1]: def add(x,y):
    return x+y
   ....: 

In [2]: reduce(add,range(1,101))
Out[3]: 5050

In [4]: reduce(lambda a,b:a+b,range(1,101))
Out[5]: 5050

In [5]: reduce(lambda a,b:a*b,range(1,6))
Out[6]: 120

内建函数

 

查看内置函数:

官方文档: https://docs.python.org/2.7/library/index.html


常用内建函数

数学 abs max min len divmod pow round

callable type isinstance cmp range xrange

类型转换 int long float complex 

字符串处理函数:str.capitalize str.replace str.splite str.join string模块(和字符串内建函数功能类似但用法稍微更复杂)

 序列处理函数: filter zip map reduce 

In [9]: def f(x):
    if x%2 == 0:
        return True
   ...:     

In [10]: filter(f,range(10))  //或者filter(lambda x:x%2==0,range(10))
Out[10]: [0, 2, 4, 6, 8]  

In [11]: l1=[1,2,3]

In [13]: l2=['a','b','c']

In [14]: zip(l1,l2)
Out[14]: [(1, 'a'), (2, 'b'), (3, 'c')]

In [17]: def f(x):
    return x**2
   ....: 

In [18]: map(f,l1)  //或者map(lambda x: x**2, [1,2,3])
Out[18]: [1, 4, 9]  

In [20]: l2=[4,5,6]

In [24]: def f(x,y):
    return x*y
   ....: 

In [25]: map(f,l1,l2)  //或者map(lambda x,y: x*y, [1,2,3],[4,5,6])
Out[25]: [4, 10, 18]
View Code

推导式

推导式是C、C++、Java里面没有的语法,但是,是Python里面使用非常广泛,是特别推荐的用法,是for语句的一种简写形式。

列表推导

# [i*2+10 for i in range(10) if i%3==0] 
#等效于

l = []
for i in range(10):
    if i % 3 == 0:
        l.append(i * 2 + 10)

 

In[1]: [i * 2 + 10 for i in range(10) if i % 3 == 0]
Out[1]: [10, 16, 22, 28]

In [2]:  [i*2 if i%3==0 else i  for i in range(10) ]
Out[2]: [0, 1, 2, 6, 4, 5, 12, 7, 8, 18]

In[3]: [i for i in range(5) if i % 2 == 0]
Out[3]: [0, 2, 4]

In[4]: [i for i in range(5) if i % 2 == 0 and not i == 2]
Out[4]: [0, 4]

 

a=[1,2]
b=[a for i in range(4)]
print(b)
[[1, 2], [1, 2], [1, 2], [1, 2]] 

集合推导

In [1]: s={i*2+10 for i in range(10) if i%3==0}

In [2]: type(s)
Out[2]: set

In [3]: s
Out[3]: {10, 16, 22, 28}

字典推导

In [4]: dict={i:i*2+10 for i in range(10) if i%3==0}

In [5]: type(dict)
Out[5]: dict

In [6]: dict
Out[6]: {0: 10, 3: 16, 6: 22, 9: 28}

生成器列表推导式

作用:列表生成器如果数据过大,会造成内存压力,此时可用生成器推导式来处理

In [45]: a=(i*2+10 for i in range(10) if i%3==0)

In [46]: a
Out[46]: <generator object <genexpr> at 0x000000000445CC60>

In [47]: type(a)
Out[47]: generator

In [48]: a.next()
Out[48]: 10

In [49]: a.next()
Out[49]: 16

In [50]: a.next()
Out[50]: 22

In [51]: a.next()
Out[51]: 28

for本质

优点(和其它循环(whilei)相比的):比whlle等循环功能强大,不仅遍历的对象种类多,而且比普通循环效率更高(自动把遍历对象生成迭代器)

定义:遍历可迭代对象(string,list,dict等),如果是遍历可迭代对象,for会自动把in后面的可迭代对象转换成迭代器,把所有元素依次加载到内存,遍历完成后自动处理异常

for i in t:  # t被for转换成t.__iter__()
    print(i)

等效于

t = [1, 2, 3, 4, 5].__iter__()  # 可以通过__iter__()方法或iter()内建函数把Iterable类型变成Iterator对象。
# 循环:
while True:
    try:
        # 获得下一个值:
        i = t.next()
        print(i)
    except StopIteration:
        # 遇到StopIteration就退出循环
        break

函数的解析与调用

函数解析时,执行def 这行,调用时再继续往下执行

res = [lambda: x for x in range(1, 3)]
print(res[0]())

###
2

等效于

list = []
for x in range(1,3):
    def func():
        return x
    list.append(func)

print(list[0]())
###
2

修正bug

res = [lambda n=x: n for x in range(1, 3)]
print(res[0]())

list = []
for x in range(1,3):
    def func(n=x):
        return n
    list.append(func)

print(list[0]())


###
1
1

最终版

res = [lambda x=x: x for x in range(1, 3)]
print(res[0]())
 
list = []
for x in range(1,3):
    def func(x=x):
        return x
    list.append(func)
 
print(list[0]())

###
1
1

迭代器

为什么要用迭代器:
优点
 1:迭代器提供了一种不依赖于索引的取值方式,这样就可以遍历那些没有索引的可迭代对象了(字典,集合,文件)
 2:迭代器与列表比较,迭代器是惰性计算的,更节省内存(同一时刻只有一个值在内存中)

缺点:
 1:无法获取迭代器的长度,使用不如列表索引取值灵活
 2:一次性的,只能往后取值,不能倒着取值

#可迭代对象:只要对象本身有__iter__方法,那它就是可迭代对象
# d={'a':1,'b':2,'c':3}
# d.__iter__ #iter(d)
#
#
#执行对象下的__iter__方法,得到的结果就是迭代器
# i=d.__iter__()
#
# print(i.__next__())
# print(i.__next__())
# print(i.__next__())
# print(i.__next__())
from collections import Iterable,Iterator

s='hello'
l=[1,2,3]
t=(1,2,3)
d={'a':1}
set1={1,2,3,4}
f=open('a.txt')

#都是可迭代的
# s.__iter__()
# l.__iter__()
# t.__iter__()
# d.__iter__()
# set1.__iter__()
# f.__iter__()
# print(isinstance(s,Iterable))
# print(isinstance(l,Iterable))
# print(isinstance(t,Iterable))
# print(isinstance(d,Iterable))
# print(isinstance(set1,Iterable))
# print(isinstance(f,Iterable))

#查看是否是迭代器
print(isinstance(s,Iterator))
print(isinstance(l,Iterator))
print(isinstance(t,Iterator))
print(isinstance(d,Iterator))
print(isinstance(set1,Iterator))
print(isinstance(f,Iterator))
查看可迭代对象与迭代器对象 

生成器

作用:

1.逐步生成序列,不用像列表一样初始化时就要开辟所有的空间(相当于2.x的xrange

2.模拟并发:协程(Python实现协程最简单的方法,就是使用yield)

 

定义:如果函数中包含yield语法,那这个函数就会变成生成器,这个函数调用时返回一个迭代器,生成器属于迭代器

 

生成器与return有何区别?
  return只能返回一次函数就彻底结束了,而yield能返回多次值;生成器只能遍历一次


yield到底干了什么事情:
  1.yield把函数变成生成器-->迭代器
  用return返回值能返回一次,而yield返回多次
  函数在暂停以及继续下一次运行时的状态是由yield保存


总结yield的功能:
1.相当于把__iter__和__next__方法封装到函数内部
2.与return比,return只能返回一次,而yield能返回多次
3.函数暂停已经继续运行的状态是通过yield保存的

from collections import Iterator
#生成器就是一个函数,这个函数内包含有yield这个关键字
def test():
    print('one')
    yield 1 #return 1


g=test()
print(g)
print(isinstance(g,Iterator))

###
<generator object test at 0x000001E80F8F0780>
True
from collections import Iterator
#生成器就是一个函数,这个函数内包含有yield这个关键字
def test():
    print('one')
    yield 1 #return 1


g=test()
print(g)
print(isinstance(g,Iterator))

print(next(g))

###
<generator object test at 0x0000023F1F5E0780>
True
one  #调用next方法时,生成器才执行
1
def countdown(n):
    print('start coutdown')
    while n > 0:
        yield n #1
        n-=1
    print('done')

g=countdown(5)
# print(g)

# print(next(g))
# print(next(g))
# print(next(g))
# print(next(g))
# print(next(g))
# print(next(g))

# for i in g: #iter(g)
#     print(i)

# while True:
#     try:
#         print(next(g))
#     except StopIteration:
#         break
>>> def createGenerator() :
...    mylist = range(3)
...    for i in mylist :
...        yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
<generator object createGenerator at 0xb7555c34>
>>> for i in mygenerator:
...     print(i)
0
1
4

协程函数

当一个函数在执行过程中被阻塞时,就用yield挂起,然后执行另一个函数。当阻塞结束后,可以用next()或者send()唤醒。相比多线程,协程的好处是它在一个线程内执行,避免线程之间切换带来的额外开销,而且多线程中使用共享资源,往往需要加锁,而协程不需要,因为代码的执行顺序是你完全可以预见的,不存在多个线程同时写某个共享变量而导致出错的情况。

#如果在一个函数内部yield的使用方式是表达式形式的话,如x=yield,那么该函数成为协程函数
def eater(name):
    print('%s start to eat food' %name)
    food_list=[]
    while True:
        food=yield food_list
        print('%s get %s ,to start eat' %(name,food))
        food_list.append(food)

    print('done')


e=eater('钢蛋')
# print(e)

print(next(e))
print(e.send('包子'))
print(e.send('韭菜馅包子'))
print(e.send('大蒜包子'))

  

yield的表达式形式:
    food=yield
    
def eater(name):
    print('%s start to eat' %name)
    while True:
        food=yield
        print('%s eat %s' %(name,food))
        
e=eater('zhejiangF4')
    

    #e.send与next(e)的区别
        #1.如果函数内yield是表达式形式,那么必须先next(e)
        #2.二者的共同之处是都可以让函数在上次暂停的位置继续运行,不一样的地方在于
            send在触发下一次代码的执行时,会顺便给yield传一个值

 

def consumer():
    last = ''
    while True:
        receival = yield last
        if receival is not None:
            print 'Consume %s' % receival
            last = receival
 
def producer(gen, n):
    gen.next()
    x = 0
    while x < n:
        x += 1
        print 'Produce %s' % x
        last = gen.send(x)
 
    gen.close()
 
gen = consumer()
producer(gen, 5)

 

闭包

说明:闭包指的是内层函数,之所以叫闭包,闭是因为在外层函数内,包是因为和外层函数的变量绑定在一起。

定义:

1.外层函数返回内层函数,

2.外层函数的变量被内层函数引用(这个被引用的自由变量将和这个内层函数一同存在)

x = 1
def f1():
    x = 2
    y = 1

    def f2():
        print(x)
        y
    return f2

f = f1(x)
f()

print(f.__closure__[0].cell_contents)
print(f.__closure__[1].cell_contents)
print(f.__closure__)

###
2
2
1
(<cell at 0x0000015A36F16C78: int object at 0x0000000051A901F0>, <cell at 0x0000015A36F16CA8: int object at 0x0000000051A901D0>) 

 

def f1(x):
    # x = 2
    y = 1

    def f2():
        print(x)
        y
    return f2

f = f1(x)
f()

print(f.__closure__[0].cell_contents)
print(f.__closure__[1].cell_contents)
print(f.__closure__)

###
1
1
1
(<cell at 0x00000188B2B36C78: int object at 0x0000000051A901D0>, <cell at 0x00000188B2B36CA8: int object at 0x0000000051A901D0>) 

  

x = 1
def f1(x):
    x = 2
    y = 1

    def f2():
        print('ok')
    return f2

f = f1(x)
f()

print(f.__closure__)

###
ok
None

  

作用:和类一样抽象对象,闭包抽象了函数,目的都是减少函数代码,提高代码复用性。应用很多,举例如下

1.嵌套函数(用于先准备一个函数,即外层函数执行完后,内层函数仍可以使用外层函数的变量),装饰器就是这种应用

def line_conf(a, b):
    def line(x):
        return a*x + b

    return line

line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print line1(5)
print line2(5)

#######
6
25

这个例子中,函数line与环境变量a,b构 成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个环境变量的取值,这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。我们只需要变换参数a,b,就可以获得不同的直线表达函数。由此,我们可以看到,闭包也具有提高代码可复用性的作用。

如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。利用闭包,我们实际上创建了泛函。line函数定义一种广泛意义的函数。这个函数的一些方面已经确定(必须是直线),但另一些方面(比如a和b参数待定)。随后,我们根据line_conf传递来的参数,通过闭包的形式,将最终函数确定下来。

 

2.保存上次的运行环境(外层函数的的生命周期结束之后,外层函数的变量不被销毁)

def outer(name):
    count=[0]
    def inner():
        count[0]+=1
        print 'Hello,', name,', ', str(count[0])+' access!'
        print count
    return inner

hello = outer('hy')
hello()
hello()
hello()

########
Hello, hy ,  1 access!
[1]
Hello, hy ,  2 access!
[2]
Hello, hy ,  3 access!
[3]

这里面调用outer的时候就产生了一个闭包——inner,并且该闭包持有自由变量——count,因此这也意味着,当函数outer的生命周期结束之后,count这个变量依然存在,因为它被闭包引用了,所以不会被回收。
另外再说一点,闭包并不是Python中特有的概念,所有把函数做为一等公民的语言均有闭包的概念。不过像Java这样以class为一等公民的语言中也可以使用闭包,只是它得用类或接口来实现。

装饰器

函数装饰器

装饰函数

定义:装饰器是特殊的闭包,特殊在于装饰器的参数除了可以是基本数据类型外,还可以是函数或类

作用:不改动原函数、不改变原函数调用方式的前提下,扩展函数功能,遵循了开放封闭原则

 

需求一:为源码函数扩展功能,且不改变调用方式

 # _*_ encoding:utf-8 _*_
 def login(func):
     print("passer user vertification...")
     func()
 
 
 def tv():
     print("Welcome [%s] to home page")
 
 tv = login(tv)  # tv的值为None
 tv()  # 这步出错:TypeError: 'NoneType' object is not callable
 
 # 输出
passer user vertification...
File "D:/PythonProject/0313/str.py", line 14, in <module> tv()
TypeError: 'NoneType' object is not callable

问题:
1.调用方法改变了
2.调用端还没有调用 tv(),扩展的功能就先执行了
v1
def login(func):
     print("passer user vertification...")
     return func
 
 def tv():
     print("Welcome [%s] to tv page")
 
 tv = login(tv)  #tv的值为tv的内存地址
 tv()
 
 # 输出
 # passer user vertification...
 # Welcome [%s] to tv page
 #
 # 问题:
 # 调用端还没有调用 tv(),扩展的功能就执行执行
v2
def login(func):
    print("passer user vertification...")
    return func

@login  #@login等效于tv = login(tv)
def tv():
    print("Welcome [%s] to tv page")

tv()

# 输出
# passer user vertification...
# Welcome [%s] to tv page
#
# 问题:
# 调用端还没有调用 tv(),扩展的功能就执行执行
v2.2
 def login(func):
     def inner():
         print("passed user vertification...")
         func()
     return inner
 
 def home():
     print("Welcome [%s] to home page" % name)
 # @login # tv=login(tv)
 def tv():
     print("Welcome [%s] to tv page")
 def movie():
     print("Welcome [%s] to home movie" % name)
 
 tv=login(tv)
 tv()
v3.1 加个闭包
 def login(func):
     def inner():
         print("passed user vertification...")
         func()
     return inner

 @login # tv=login(tv)
 def tv():
     print("Welcome [%s] to tv page")
 
 tv()
v3.2 加个闭包

需求二:需求一 + 传递参数 + 返回值

def outer(func): #func=tv
    def inner(args):  #参数其实传到了这里
        print("passed user vertification...")
        func(args)
    return inner

@outer # tv=outer(tv),tv=inner,tv()=inner()
def tv(name):
    print("Welcome [%s] to tv page" % name)

tv('hy')

#######
passed user vertification...
Welcome [hy] to tv page
func无返回值+普通参数
def outer(func):  # func=tv
    def inner(*args, **kwargs):  # 参数其实传到了这里
        print("passed user vertification...")
        func(*args, **kwargs)
    return inner


@outer  # tv=outer(tv),tv=inner,tv()=inner()
def tv(name):
    print("Welcome [%s] to tv page" % name)

tv('hy')
#######
passed user vertification...
Welcome [hy] to tv page
func无返回值+动态参数
def outer(func):  # func=tv
    def inner(args):  # 参数其实传到了这里
        print("passed user vertification...")
        return func(args)
    return inner


@outer  # tv=outer(tv),tv=inner,tv()=inner()
def tv(name):
    print("Welcome [%s] to tv page" % name)
    return 6

print tv('hy')

########
passed user vertification...
Welcome [hy] to tv page
6
func有返回值+普通参数
def outer(func):  # func=tv
    def inner(*args, **kwargs):  # 参数其实传到了这里
        print("passed user vertification...")
        return func(*args, **kwargs)
    return inner


@outer  # tv=outer(tv),tv=inner,tv()=inner()
def tv(name):
    print("Welcome [%s] to tv page" % name)
    return 6

print tv('hy')

########
passed user vertification...
Welcome [hy] to tv page
6
func有返回值+动态参数

需求三:需求二+含参装饰器

def wrapper(*wrapperargs):
    def outer(func):  # func=tv
        def inner(*args, **kwargs):  # 参数其实传到了这里
            print("passed user vertification...")
            print '[%s] looks like very [%s]' % (''.join(args), ''.join(wrapperargs))
            return func(*args, **kwargs)
        return inner
    return outer


@wrapper('shuai')  # tv=outer(tv),tv=inner,tv()=inner()
def tv(name):
    print("Welcome [%s] to tv page" % name)
    return 6

print tv('hy')

########
passed user vertification...
[hy] looks like very [shuai]
Welcome [hy] to tv page
6
func有返回值+func动态参数+装饰器动态参数
def Before():
    print('before')


def After():
    print('after')


def wrapper(before_func, after_func):
    def outer(func):  # func=tv
        def inner(*args, **kwargs):  # 参数其实传到了这里
            print("passed user vertification...")
            before_func()
            after_func()
            return func(*args, **kwargs)

        return inner

    return outer


@wrapper(Before, After)
def tv(name):
    print("Welcome [%s] to tv page" % name)
    return 6


print(tv('hy'))

#######
passed user vertification...
before
after
Welcome [hy] to tv page
6
func有返回值+func动态参数+装饰器参数(函数作为参数)

需求四:多层装饰器

#!/usr/bin/env python  
# _*_ coding=utf-8 _*_  
  
def outer(func):  
    def inner(*args,**kwargs):  
        print('log')  
        r=func(*args,**kwargs)  
        print('after')  
        return r  
    return inner  
  
def outer2(func):  
    def inner(*args,**kwargs):  
        if LOGIN_INFO['is_login']:  
            r=func()  
            return r  
        else:  
            print('please login')  
    return inner  
  
#如果套两层装饰器,就是双层装饰器了,当然也有三层,四层,道理类似  
#这里大家可能有疑惑,python在解释有 “@+函数”这种格式的语法时,会自动从里向外解读,再从外向内执行,  
#也就是最里层的原函数被逐层装饰直到最外层,对应例子里,python先把f2(原函数)发给outer2(里层装饰器),被装饰后的outer2的inner再  
#被outer(外层装饰器)装饰,最终返回的是outer的inner函数体。  
@outer  
@outer2  
def f2(a,v):  
    print('F2')  
#当然有人问主函数的调用为啥这样写呢,这个会在模块对于的blog中介绍  
  
if __name__ == '__main__':  
    f2  
随意组合上面几种类型装饰器

 类装饰器

装饰函数

 再来看看类装饰器,相比函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器还可以依靠类内部的__call__方法,当使用 @ 形式将装饰器附加到函数上时,就会调用此方法。

class Outer(object):
    def __init__(self, func):
        self._func = func

    def __call__(self):
        self._func()


@Outer  # tv=Outer(tv)
def tv():
    print("Welcome  to tv page")

tv()

###
Welcome  to tv page
无参数+无返回值

functools.wraps

作用:并不改变原有函数的属性,如doc name

def trace(func):
    """ 装饰器 """

    # @wraps(func)
    def callf(*args, **kwargs):
        """ A wrapper function """
        print("Calling function:{}".format(func.__name__))  # Calling function:foo
        res = func(*args, **kwargs)
        print("Return value:{}".format(res))  # Return value:9
        return res

    return callf


@trace
def foo(x):
    """ 返回给定数字的平方 """
    return x * x


if __name__ == '__main__':
    print(foo.__doc__)
    print(foo.__name__)

############
A wrapper function 
callf
不加wraps
from functools import wraps


def trace(func):
    """ 装饰器 """

    @wraps(func)
    def callf(*args, **kwargs):
        """ A wrapper function """
        print("Calling function:{}".format(func.__name__))  # Calling function:foo
        res = func(*args, **kwargs)
        print("Return value:{}".format(res))  # Return value:9
        return res

    return callf


@trace
def foo(x):
    """ 返回给定数字的平方 """
    return x * x


if __name__ == '__main__':
    print(foo.__doc__)
    print(foo.__name__)

#####
返回给定数字的平方 
foo
加wraps

魔法函数

定义:以双下划线开头和结尾的属性,如__init__ __len__ __getitem__

作用:python会自动调用这些方法,自定义类就可以增加一些特性

 字符串

 

 

posted @ 2017-01-15 20:14  沐风先生  阅读(631)  评论(1编辑  收藏  举报