python开发第四篇--函数

名称空间与作用域

1.变量储存在一个内存空间中
2.当程序运行的时候代码从上到下依次执行,它会将变量与值的关系存储在一个空间中,这个空间叫名称空间,命名空间,全局名称空间
3.当程序遇到函数时,它会将函数名存在内存中,函数体漠不关心
4.当程序执行的时候,内存会临时开辟一个空间,存放函数体里的代码(变量,代码等)
5.函数外面访问不到临时空间的内容,随着函数执行完毕,临时名称空间会被释放掉,向这个临时开辟的空间也叫临时名称空间,也叫局部名称空间

  • python名称空间分为三种:
    1.内置名称空间
    2.全局名称空间
    3.局部名称空间
  • 按照作用域分为两种:

    • 全局作用域

      1.内置名称空间
      2.全局名称空间
    • 局部作用域

      1.局部名称空间
  • 加载顺序
    内置名称空间—全局名称空间(当程序执行时)—局部名称空间(函数调用时)
  • 取值顺序
    局部名称空间(函数调用时)—全局名称空间(当程序执行时)—内置名称空间
    注:取值顺序是单向不可逆的

      1.取值又叫引用,局部名称空间可以临时像全局名称空间引用,但是无法修改
      2.取值是从小到大取值LEGB
          - L=最里层的局部作用域
          - E=父亲级别的局部作用域
          - G=全局作用域中的全局名称空间
          - B=全局作用域中的内置名称空间
  • 内置函数globals和locals的方法:

    • globles

         globales返回一个字典,字典里的内容是全局名称空间的内容
    • locals

         locals返回一个字典,当前位置的所有变量(看locals的位置是否在函数体里还是在全局里)
      
#1.
print(globals())
print(locals())
#打印结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x004DB4B0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/python/day04/1.py', '__cached__': None}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x004DB4B0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/python/day04/1.py', '__cached__': None}
#2.
def func():
    a = 12
    b = 20
    print(locals())
    print(globals())
func()
#打印结果:
{'b': 20, 'a': 12}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0044B4B0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/python/day04/1.py', '__cached__': None, 'func': <function func at 0x0040B660>}
  • 关键字global和nonlocal的方法:

    • global
      1.global可以引用全局变量,并且改变全局变量
      2.在局部作用域声明一个全局变量
    • nonlocal
      1.不能操作全局变量
      2.在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。

注:对于可变的数据类型list,dict,set,不用引用global,nonlocal
注:如果默认参数是一个可变的数据类型,那么他在内存中永远是一个。

#1.第一种情况:
def extendList(val,list=[]):
    list.append(val)
    return list
list1 = extendList(10)
print('list1=%s'%list1)  # [10,]
list2 = extendList(123,[])
print('list2=%s'%list2)  # [123,]
list3 = extendList('a')
print('list3=%s'%list3)  #[10,'a']
打印结果为:
list1=[10]
list2=[123]
list3=[10, 'a']
#2.第二种:
def extendList(val,list=[]):
    list.append(val)
    return list
list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')
print('list1=%s'%list1)
print('list2=%s'%list2)
print('list3=%s'%list3)
打印结果为:
list1=[10, 'a']
list2=[123]
list3=[10, 'a']
因为:如果默认参数是一个可变的数据类型,那么他在内存中永远是一个。

1.global实例:

def func():
    global a
    a = 3
func()
print(a)
#打印结果为:3
count = 1
def search():
    global count
    count = 2
search()
print(count)
#打印结果为2

2.nonloacl实例:

def add_b():
    b = 42
    def do_global():
        b = 10
        print(b)
        def dd_nonlocal():
            nonlocal b
            b = b + 20
            print(b)
        dd_nonlocal()  #30
        print(b) #30
    do_global()   #10
    print(b)
add_b()
#打印结果为:
10
30
30
42

函数

  • 函数的嵌套与调用:
#函数的嵌套
def max2(x,y):
    m  = x if x>y else y
    return m
def max4(a,b,c,d):
    res1 = max2(a,b)
    res2 = max2(res1,c)
    res3 = max2(res2,d)
    return res3
#函数的调用
max4(1,2,3,4)
  • 函数名的本质
    1.打印函数名
def func():
    print('in func')
f = func
print(f)
#打印结果为:<function func at 0x0020B660>
为一块内存地址
2.函数名可以作为容器类数据的元素
def func1():
    print(111)
def func2():
    print(222)
def func3():
    print(333)
l1 = [func1, func2, func3]
for i in l1:
    i()
#打印结果为:
111
222
333
3.函数名可以作为函数的参数
def func1():
    print(111)
def func2(x):
    print(x)
    x()
    print(222)
func2(func1)
#打印结果为:
<function func1 at 0x0021B660>
111
222
4.函数名可以作为函数的返回值
def func1():
    return 111
def func2(x):  # x = func1
    print(222)
    return x
ret = func2(func1)  # func1
print(ret())
print(ret)
#打印结果为:
222
111
<function func1 at 0x002BB660>
  • 总结:
    函数名的应用,第一类对象

      - 函数名打印的出来的是个内存地址,加()号就可以运行
      - 函数名可以作为容器类型内的元素
      - 函数名可以作为传递的参数
      - 函数名可以作为函数的返回值,return把值给函数的执行者
  • 闭包函数

      - 内层函数对外层函数非全局变量的引用,就叫做闭包
      - 判断是否是闭包:__closure__
      - 如果python解释器遇到了闭包,他有个机制,这个闭包不会随着函数的结束而释放
      - 装饰器@语法糖,装饰器放在需要装饰的函数的上边,利用的就是闭包函数

装饰器:

#测试func1函数的执行时间
def timmer(f):
    def inner(*args,**kwargs):
        start_time = time.time()
        ret = f(*args,**kwargs)
        end_time = time.time()
        print('此函数的执行效率%s' % (end_time - start_time))
        return ret
    return inner
@timmer
def func1():
    time.sleep(0.3)
    print('非常复杂......')
func1()
#格式为:
def wrapper(f):
    def inner(*args,**kwargs):
        """被装饰函数执行之前的操作"""
        ret = f(*args,**kwargs)
        """被装饰函数执行之后的操作"""
        return ret
    return inner
# 装饰器 本质就是闭包
# 装饰器根本作用:在不影响原函数执行的基础上,增加一些额外的功能登录认证,打印日志等等。

内裤可以用来遮羞,但是到了冬天它没法为我们防风御寒,聪明的人们发明了长裤,有了长裤后宝宝再也不冷了,装饰器就像我们这里说的长裤,在不影响内裤作用的前提下,给我们的身子提供了保暖的功效。

    原文作者:禁止进入i
    原文地址: https://segmentfault.com/a/1190000015073758
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞