3.2、函数进阶

函数对象

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

#1 可以被引用
#2 可以当作参数传递
#3 返回值可以是函数
#4 可以当作容器类型的元素
def foo():
    print('foo')

def bar():
    print('bar')

dic={
    'foo':foo,
    'bar':bar,
}
while True:
    choice=input('>>: ').strip()
    if choice in dic:
        dic[choice]()
利用函数取代多分支的if

 

全局变量与局部变量

1.定义:在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。

##如果函数的内容无global关键字,优先读取局部变量,能读取区部变量,无法对全局变量重新赋值,但对于可变类型,可以对内部元素进行操作。如果函数中有global关键字,变量本质就是全局的那个变量,可读取可复制

 

gloabal、nonlocal

 首先我们写这样一个代码, 首先在全局声明一个变量, 然后再局部调用这个变量, 并改变这 个变量的值 

a = 100
def func():   
    global a    # 加了个global表示不再局部创建这个变量了. 而是直接使用全局的a   
    a = 28   
print(a)
func()
print(a)
View Code

global表示. 不再使用局部作用域中的内容了. 而改用全局作用域中的变量

lst = ["麻花藤", "刘嘉玲", "詹姆斯"]
def func():   
    lst.append("⻢云")   
    # 对于可变数据类型可以直接进⾏访问. 但是不能改地址. 说⽩了. 不能赋值 在函数中赋值就是在局部空间创建了一个变量   
   print(lst)
func()
print(lst)
View Code

nonlocal 表示在局部作用域中, 调用父级命名空间中的变量.

如果父级命名空间中没有这个变量名,就继续向上查找.最多找到最外成的函数就结束了

a = 10
def func1():   
    a = 20   
    def func2():
        nonlocal a       
        a = 30       
        print(a)  
    func2()   
    print(a)
func1()
 
结果:
加了nonlocal
30
 
不加nonlocal
20
View Code

如果嵌套了很多层, 会是一种什么效果:?

a = 1
def fun_1():   
    a = 2   
    def fun_2():       
        nonlocal a       
        a = 3       
        def fun_3():           
            a = 4           
            print(a)       
        print(a)       
        fun_3()       
        print(a)   
    print(a)   
    fun_2()   
    print(a)
print(a)
fun_1()
print(a)
View Code

 

函数的嵌套

 1定义:在一个函数中定义了另外一个函数即一个函数里用def语句来创建其它的函数的情况

def outer():


  def inner():


    print('inner')


  print('outer')


  inner()


outer()


inner()    # 此句会出错
View Code

 

内部函数不能被外部直接使用,会抛NameError异常,2个体会列子:

 

 

 

函数的作用域,命名空间(名称空间)

 

名称空间:存放名字和值的关系的空间起一个名字叫: 命名空间即名称空间. 我们的变量在存储的时候就 是存储在这片空间中的.  

####在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了,  至于函数内部的变量和逻辑, 解释器是不关心的. 也就是说一开始的时候函数只是加载进来, 仅此而已, 只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间. 随着函数执行完毕, 这些函数内部变量占用的空间也会随着函数执行完毕而被清空.

def fun():   
    a = 10   
    print(a)
fun()
print(a)    # a不存在了已经

 

 

命名空间分类:         

 

    1. 内置命名空间--> 存放python解释器为我们提供的名字, list, tuple, str, int这些都是内置命名空间 (即builtins 内置模块的名称空间)

 

            2. 全局命名空间--> 我们直接在py文件中, 函数外声明的变量都属于全局命名空间   (即globals  全局变量)    

 

            3. 局部命名空间--> 在函数中声明的变量会放在局部命名空间 (即locals 包含局部变量和形参)

 

加载顺序:

  1. 内置命名空间

  2. 全局命名空间

       3. 局部命名空间(函数被执行的时候)

取值顺序:

       1. 局部命名空间

       2. 全局命名空间

       3. 内置命名空间

a = 10
def func():   
    a = 20   
    print(a)
 
func()  # 20

 

作用域:就是作用范围(在python中一个函数就是作用域,所有的局部变量放置在其作用域中,代码定义完成后,作用域已经生成,作用域链向上查找)

按照生效范围来看分为  全局作用域  和   局部作用域   

   全局作用域: 包含内置命名空间和全局命名空间. 在整个文件的任何位置都可以使用(遵循 从上到下逐⾏执行).

   局部作用域: 在函数内部可以使用.             

作⽤域命名空间:         

  1. 全局作⽤用域:    全局命名空间 + 内置命名空间       

  2. 局部作⽤用域:    局部命名空间,只能在局部范围内生效

  3.站在全局看:
    使用名字的时候:如果全局有,用全局的
    如果全局没有,用内置的

4.为什么要有作用域?为了函数内的变量不会影响到全局

5.globals方法:查看全局作用域的名字【print(globals())】

 locals方法:查看局部作用域的名字【print(locals())】

a = 10
def func():   
    a = 40   
    b = 20   
    def abc():       
        print("哈哈")   
        print(a, b)     # 这⾥里里使⽤用的是局部作⽤用域   
        print(globals())    # 打印全局作用域中的内容   
        print(locals())     # 打印局部作用域中的内容
func()
View Code

6.nonlocal让内部函数中的变量在上一层函数中生效,外部必须有

# x=1
# def f1():
#     x=2
#     def f2():
#         # x=3
#         def f3():
#             # global x#修改全局的
#             nonlocal x#修改局部的(当用nonlocal时,修改x=3为x=100000000,当x=3不存在时,修改x=2为100000000 )
#                    # 必须在函数内部
#             x=10000000000
#         f3()
#         print('f2内的打印',x)
#     f2()
#     print('f1内的打印', x)
# f1()
# # print(x)
View Code

7.函数名可以用作参数

def func():
    print('func')

def func2(f):
    f()
    print('func2')
func2(func)
View Code

8.函数名可以作为函数的返回值 

def func():
    def func2():
        print('func2')
    return func2
f2=func()
f2()
#func2=func()
#func2()


2.

def f1(x):
    print(x)
    return '123'

def f2():
    ret = f1('s')  #f2调用f1函数
    print(ret)
f2()


3.
def func():
    def func2():
        return 'a'
    return func2   #函数名作为返回值

func2=func()
print(func2())
View Code

 

 

函数名的本质

函数名本质上就是函数的内存地址

1.可以被引用

def func():
    print('in func')

f = func
print(f)
View Code

2.可以被当作容器类型的元素

def f1():
    print('f1')


def f2():
    print('f2')


def f3():
    print('f3')

l = [f1,f2,f3]
d = {'f1':f1,'f2':f2,'f3':f3}
#调用
l[0]()
d['f2']()
View Code

3.可以当作函数的参数和返回值(即就当普通变量用)

第一类对象(first-class object)指
1.可在运行期创建
2.可用作函数参数或返回值
3.可存入变量的实体。

 

 

闭包

 

def func1():
    name = "alex"
    def func2():
        print(name)
        # 闭包
    func2()
func1()
# 结果: alex
View Code

使用__closure__来检测函数是否是闭包. 使用函数名.__closure__返回cell就是
闭包. 返回None就不是闭包

def func1():
    name = "alex"
    def func2():
        print(name)
        # 闭包
    func2()
    print(func2.__closure__)
func1()
 
结果:
alex
(<cell at 0x0000020077EFC378: str object at 0x00000200674DC340>,)
返回的结果不是None就是闭包
View Code
def wrapper():
    money = 1000
    def func():
        name = 'eva'
        def inner():
            print(name,money)
        return inner
    return func

f = wrapper()
i = f()
i()
闭包嵌套
from urllib.request import urlopen

def index():
    url = "http://www.xiaohua100.cn/index.html"
    def get():
        return urlopen(url).read()
    return get

xiaohua = index()
content = xiaohua()
print(content)
闭包函数获取网络应用

 

 

高阶函数

变量可以指向函数,函数的参数能接受变量,那么一个函数就可以接受另外一个函数作为参数,这种函数就称为高阶函数。只需要满足以下任意一个条件,即是高阶函数:

接受一个或多个函数作为输入

return返回另外一个函数。 例如:

def func1():
        age=83
        def func2():
        return func2
val=func1()
print(val)

 

def func():
    n=10
    def func2():
        print("func2",n)
    return func2
f=func()
print (f)
f()

 

 小结:

 

posted @ 2019-06-24 14:39  二哈的博客  阅读(61)  评论(0编辑  收藏  举报