函数对象,函数的嵌套,名称空间与作用域,闭包,装饰器,迭代器,内置函数

Posted 龚旭1994

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了函数对象,函数的嵌套,名称空间与作用域,闭包,装饰器,迭代器,内置函数相关的知识,希望对你有一定的参考价值。

一,函数对象

    函数对象:函数是第一类对象,即函数可以当做数据传递

     1,可以被引用

def foo():
    print(\'from foo\')
func=foo
print(func)
print(foo())
func()

     2,可以做参数的传递

def foo():
    print(\'from foo\')
def bar(func):
    print(func)
bar(foo)
foo()

     3,返回值可以是函数

def foo():
    print(\'from foo\')
def bar(func):
    return func
f=bar(foo)
print(f)     #打印foo的内存地址
f()          #可直接调用,是foo的值

     4,可以当作容器类型的元素

func_dic={
    \'func\':func
}

func_dic[\'func\']()

 二,函数嵌套

 1,函数的嵌套调用

def max1(x,y):
    return x if x>y else y
def max2(a,b,c):
    res=max1(a,b)
    res1=max1(res,c)
    return res1
print(max2(10,20,30))

 2,函数的嵌套定义

函数的定义相当于变量的定义

def f1():
    print(\'from f1\')
    def f2():
        print(\'from f2\')
        def f3():
            print(\'from f3\')
        f3()
    f2()
f1()

三,名称空间与作用域 

名称空间:存放名字的地方叫名称空间,存放这些值与名字的绑定关系

查看内置名称的两种方法:
第一种
import builtins
print(dir(builtins))
第二种
import builtins
for i in dir(builtins):
    print(i)

三种名称空间

1,内置名称空间:随着python解释器的启动而产生
2,全局名称空间:文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放入该空间((在执行文件时产生,存放文件级别定义的名字,文件执行时生效,关闭时失效))
3,局部名称空间:调用函数时会产生局部名称空间,只在函数调用时临时绑定,调用结束解除绑定(用来存放该函数内定义的名字)
加载顺序:内置-----》全局--------》局部
作用域:
   1,全局作用域:
         包含内置名称空间和全局名称空间(全局有效,在任何位置都能被访问到,除非del删掉,否则会一直存活到文件)
   2,局部作用域:
         局部名称空间,局部有效,只能在局部范围调用,只在函数调用时才有效,函数结束
名字的查找顺序:局部名称空间-----全局名称空间-----内置名称空间
x=1000
def func(y):
    x=2
    print(locals())    #在局部能看见全局和局部
    print(globals())   #在全局能看见全局,看不见局部
func(1)

查看全局作用域内名字的方法:gloabls()

查看全局作用域内名字的方法 :locals()

global(把局部变成全局名称空间)
nonlocal(只在局部生效)
优先掌握:
作用域关系在函数定义时就已经固定(与调用位置无关)在调用函数时,必须回到函数原来定义的位置去找作用于关系

四,闭包

定义在函数内部的函数 ,内部函数包含对外部作用域而非全局作用域的引用,该内部函数就称为闭包函数
闭包:
def f1():
    x=1
    def f2():
        print(x)
    return f2
f=f1()
f()
闭包函数:惰性计算
def f1():
    x=1
    y=1
    def f2():
        print(x,y)
    return f2
f=f1()
print(f.__closure__)   #显示值的个数
print(f.__closure__[0].cell_contents)  #显示值,[]中选择显示第几个值
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
应用领域:延迟计算(原来我们是传参,现在我们是包起来)

五,装饰器(闭包函数的一种应用场景)

为什么要用装饰器?

      1,开放封闭原则,对修改是封闭的,对扩展是开放的

      2,装饰器就是为了在不修改被装饰对象的源代码以及调用方式的前提下,为其添加新功能

装饰器:在遵循下面两个原则的前提下为被修饰者添加新功能

必须遵循两个原则:

      1,尽量不要修改源代码

      2,不能修改调用方式

装饰器:修饰别人的工具,修饰:添加功能,工具指的是函数

装饰器本身可以是任何可调用对象,被装饰的对象也可以是任意可调用对象 

装饰器语法:
被装饰函数的正上方,单独一行

无参函数的简单语法

import time
def timmer(func):
    def wrapper():
        start_time=time.time()
        func()
        stop_time=time.time()
        print(\'run time is %s\' %(stop_time-start_time))
    return wrapper
@timmer
def index():
    time.sleep(3)
    print(\'welcome to index\')
index()
sleep休眠函数
@装饰器的语法,正下方的函数当做参数传进来,固定只有一个参数
传入有参函数的语法
import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print(\'run time is %s\' %(stop_time-start_time))
        return res
    return wrapper
@timmer
def index():
    time.sleep(3)
    print(\'welcome to index\')
    return 3
@timmer
def foo(name):
    time.sleep(1)
    print(\'from foo\')
res=index()
print(res)
res1=foo(\'gx\')
print(res1)
index()

多个装饰器(有参装饰器的使用)

login={\'user\':None,\'status\':False}
def auth(drive=\'file\'):
    def auth2(func):
        def wrapper(*args,**kwargs):
            print(\'======>>auth.wrapper\')
            if drive==\'file\':
                if login[\'user\'] and login[\'status\']:
                    res=func(*args,**kwargs)
                    return res
                else:
                    name=input(\'用户名>>>>>>:\').strip()
                    pwd=input(\'密码>>>>>>>:\').strip()
                    if name == \'gx\' and pwd == \'123\':
                        login[\'user\']=\'gx\'
                        login[\'status\']=True
                        print(\'login successful\')
                        res=func(*args,**kwargs)
                        return res
                    else:
                        print("login error")
            elif drive==\'ldap\':
                print(\'=====>>ldap的认证\')
            elif drive==\'mysql\':
                print(\'======>>mysql的认证\')
                return func(*args,**kwargs)
            else:
                print(\'未知的认证\')
        return wrapper
    return auth2
@auth(\'file\')
def index():
    print(\'welcome to index page\')
index()

装饰器补充:

Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。写一个decorator的时候,最好在实现之前加上functools的wrap,它能保留原有函数的名称和docstring

functools.wraps 则可以将原函数对象的指定属性复制给包装函数对象, 默认有 __module____name____doc__,或者通过参数选择。

from functools import  wraps
def deco(func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        return func(*args,**kwargs)
    return wrapper
@deco
def index():
    \'\'\'哈哈哈\'\'\'
    print(\'from index\')
print(index.__doc__)

六,迭代器

为什么要有迭代器?

对于没有索引的数据类型,必须提供一种不依赖索引的迭代方式

迭代的概念:重复+上一次迭代的结果为下一次迭代的初始值,重复的过程称为迭代,每次重复即一次迭代,并且每次迭代的结果是下一次迭代的初始值

执行__iter__方法,得到的结果就是迭代器

迭代器的有点和缺点:

优点:1,提供了一种不依赖下标的迭代方式

         2,就迭代器本身来说,更节省内存

缺点: 1,无法获取迭代器对象的长度

          2,不如序列类型取值灵活,是一次性的,只能往后取,不能往前退

迭代协议:

           对象有__next__

          对象有__iter__,对于迭代器来说,,执行__iter__方法,得到的结果仍然是它本身

while True: #只满足重复,因而不是迭代
            #     print(\'====>\')

迭代
l=[1,2,3]
count=0
while count < len(l): #只满足重复,因而不是迭代
     print(\'====>\',l[count])
     count+=1

可迭代对象

[1,2].__iter__()
\'hello\'.__iter__()
(1,2).__iter__()
{\'a\':1,\'b\':2}.__iter__()
{1,2,3}.__iter__()
f=open(\'a.txt\',\'w\')
f.__iter__()
print(isinstance(\'abc\',Iterable))
print(isinstance([],Iterable))
print(isinstance((),Iterable))
print(isinstance({\'a\':1},Iterable))
print(isinstance({1,2},Iterable))
print(isinstance(f,Iterable))


语法:isinstance(object,type)

作用:来判断一个对象是否是一个已知的类型。 

只有文件是迭代器对象__next__是迭代器

__next__一次只能取一个值

抛出异常:StopIteration说明值已取完

取字典value的值和处理异常

dic={\'a\':1,\'b\':2,\'c\':3}
i=dic.__iter__()
while True:
    try:
        key=i.__next__()
        print(dic[key])
    except StopIteration:
        break

生成器函数:只要函数体包括yield关键字,该函数就是yield就是生成器函数

yield的功能:

          1,相当于为函数装好__iter__和__next__

          2,return只能返回一次值,函数就终止了,而yield能返回多次值,每次返回都会将函数暂停,下一次next会从上一次暂停的位置继续执行。

def foo():
    print(\'first\')
    yield 1
    print(\'second\')
    yield 2
    print(\'third\')
    yield 3
    print(\'fourth\')
g=foo()
for i in g:
    print(i)
def foo():
    print(\'first\')
    yield 1
    print(\'second\')
    yield 2
    print(\'third\')
    yield 3
    print(\'fourth\')
g=foo()
print(next(g))
print(next(g))   #触发迭代器g的执行,进而触发函数的执行
print(next(g))
print(next(g))
三元表达式
def max2(x,y):
    return x if x > y else y
print(max2(1,2))

name=\'gongxu\'
print(\'h\' if name == \'haha\' else \'gongxu\')
列表推导式
l=[\'egg%s\' %i for i in range(10)]
print(l)

l=[\'egg%s\' %i for i in range(10) if i >=5]
print(l)

names=[\'gx_xx\',\'liting_xx\',\'xiaohua\']
name_new=[name for name in names if name.endswith(\'xx\')]
print(name_new)
生成器表达式(把[]变成()就是生成器表达式)
with open(\'a.txt\',encoding=\'utf-8\') as f:
    print(max([len(line) for line in f])

with open(\'a.txt\', encoding=\'utf-8\') as f:
    res=max(len(line) for line in f)
    print(res)

以上是关于函数对象,函数的嵌套,名称空间与作用域,闭包,装饰器,迭代器,内置函数的主要内容,如果未能解决你的问题,请参考以下文章

函数对象函数嵌套名称空间与作用域装饰器

python基础:函数对象函数嵌套名称空间与作用域装饰器

python基础之====函数对象函数嵌套名称空间与作用域装饰器

20181128(闭包函数,函数嵌套,名称空间,作用域,装饰器待补充)

装饰器

函数嵌套 ,名称空间与作用域 ,闭包函数 ,装饰器 ,迭代器, 生成器 三元表达式,列表解析,生成器表达式 递归与二分法, 内置函数