day_04、函数

python代码运行原理

  从python开始执行以后,就在内存里开辟一个空间,每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来。当遇到函数定义的时候,解释器只是象征性的将函数名读到内存,表示知道这个函数存在了。至于函数内部的变量和逻辑,解释器不关心。

  等执行到函数调用的时候,python解释器会再开辟一块内存来存储这个函数里面的内容,这个时候,才关注函数里面有哪些变量。而函数中的变量会储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕。这块内存中的所有内容也会被清空

我们给这个‘存放名字与值得关系’得空间起了一个名字------命名空间。

代码在运行伊始,创建得存储‘变量名与值的关系’的空间叫做全局命名空间

在函数的运行中开辟的临时的空间叫做局部命名空间

命名空间和作用域

命名空间一共分为三种:

全局命名空间

局部命名空间

内置命名空间

内置命名空间中存放了python解释器为我们提供的名字:input,print,list...

三种命名空间之间的加载与取值顺序:

加载顺序:内置命名空间(程序运行前加载)-->全局命名空间(程序运行中:从上到下加载)-->局部命名空间(程序运行中:调用时才加载。)

取值顺序

  在局部调用:局部命名空间-->全局命名空间-->内置命名空间

  在全局调用:全局命名空间-->内置命名空间

作用域

  作用域就是作用范围,按照生效分为可以分为全局作用域和局部作用域。

  全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效

  局部作用域:布局名称空间,只能在局部范围内生效。

globals()和locals()

1 print(globals())
2 print(locals())
在全局调用globals和locals
1 def func():
2     a = 12
3     b = 20
4     print(locals())
5     print(globals())
6 
7 func()
在局部调用locals和globals

global关键字,nonlocal关键字。

global:

  1、声明一个全局变量。

  2、在局部作用域(函数内部)想要对全局变量进行修改时,需要用到global(限于字符串,数字。即全局作用域的列表和字典、集合可以在函数内部直接修改。)

def func():
    global a
    a = 3
func()
print(a)


count = 1
def search():
    global count
    count = 2
search()
print(count)

 ps:对可变数据类型(list,dict,set)可以直接引用不用通过global。

li = [1,2,3]
dic = {'a':'b'}

def change():
    li.append('a')
    dic['q'] = 'g'
    print(dic)
    print(li)
change()
print(li)
print(dic)

nonlocal:

   1、不能修改全局变量

   2、在局部作用域,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从哪层及以下此变量全部发生改变。

def add_b():
    b = 42
    def do_global():
        b = 10
        print(b)
        def dd_nonlocal():
            nonlocal b
            b = b + 20
            print(b)
        dd_nonlocal()
        print(b)
    do_global()
    print(b)
add_b()

函数的嵌套和作用域链

函数的嵌套调用

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(23,-7,31,11)

  函数的嵌套定义

 1 def f1():
 2     print("in f1")
 3     def f2():
 4         print("in f2")
 5 
 6     f2()
 7 f1()
 8 ###########
 9 def f1():
10     def f2():
11         def f3():
12             print("in f3")
13         print("in f2")
14         f3()
15     print("in f1")
16     f2()
17     
18 f1()
函数的嵌套定义

函数的作用域链:小范围作用域可以使用大范围的变量,但是反之不行,他是单向的。

 1 def f1():
 2     a = 1
 3     def f2():
 4         def f3():
 5             print(a)
 6         f3()
 7     f2()
 8 
 9 f1()
10 ################
11 def f1():
12     a = 1
13     def f2():
14         a = 2
15     f2()
16     print('a in f1 : ',a)
17 
18 f1()
函数的作用域链:小范围作用域可以使用大范围的变量,但是反之不行,他是单向的。

函数名的本质

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

1、可以被引用

def fun():
    print('in fun')

print(fun)

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']()

3、可以当作函数的参数和返回值

def f1():
    print('f1')

def func1(argv):
    argv()
    return argv

f = func1(f1)
f()

第一类对象:

1、可以在运行时创建

2、可用作函数参数或返回值

3、可存入变量的实体。

闭包

def fun():
    name = 'root'
    def inner():
        print(name)
    return inner()
fun()

 

def fun():
    name = 'root'
    def inner():
        print(name)
fun()

闭包函数:

内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数

# 函数内部定义的函数称为内部函数

由于有了作用域的关系,我们就不能拿到函数内部的变量和函数了。如果我们想拿就要返回。

我们都知道函数内的变量我们想在函数外部用,可以直接返回这个变量。

那么我们想在函数的外部直接调用函数内部的函数。直接返回这个函数的名字。(即fun,不带‘()’)

 

def fun():
    name = 'root'
    def inner():
        print(name)
    return inner

fun()()

 

判断闭包函数的方法

def fun():
    name = 'root'
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

fun()()

 #(<cell at 0x02DF6F10: str object at 0x0506C8E0>,)

name = 'ubuntu'
def fun():
    # name = 'root'
    def inner():
        print(name)
    print(inner.__closure__)
    return inner

fun()()

  闭包嵌套

 1 def wrapper():
 2     money = 100
 3     def fun():
 4         name = 'root'
 5         def inner():
 6             print(name, money)
 7         return inner
 8     return fun
 9 
10 wrapper()()()

装饰器

装饰器本质上就是一个python函数,它可以在其他函数不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。装饰器的应用场景:插入日志,性能测试,事物处理,缓存等。

开放封闭原则

1、对扩展是开放的

  任何一个程序,不可能在设计之处就已经想好了所有的功能,并且不做任何更新和修改。所以我们必须允许代码扩展、添加新功能。

2、对修改是封闭的

  已经上线的函数,对其进行修改,很可能会影响其他已经在使用该函数的用户。

装饰器模板

def timer(func):
    def inner(*args,**kwargs):
        '''执行函数之前要做的'''
        re = func(*args,**kwargs)
        '''执行函数之后要做的'''
        return re
    return inner

带参数的装饰器    #待填

def outer(flag):
    def time(fun):
        def fun(*args, **kwargs):
            if flag:
                pass
            ret = fun(*args, **kwargs)
            if flag:
                pass
            return ret
        return fun
    return time

@outer(False)
def func():
    pass  

多个装饰器装饰一个函数---俄罗斯套娃

def wrapper1(func):
    def inner():
        print('wrapper1 ,before func')
        func()
        print('wrapper1 ,after func')
    return inner

def wrapper2(func):
    def inner():
        print('wrapper2 ,before func')
        func()
        print('wrapper2 ,after func')
    return inner

@wrapper2
@wrapper1
def f():
    print('in f')

f()

 参数的用法

def fun(start, stop=None, step=1):
    if stop is None:
        start, stop = 0, start
    result = []
    i = start
    while i < stop:
        result.append(i)
        i += step
    return result

print(fun(10))

 函数的有用信息

from functools import wraps

def logger(f):
    @wraps(f)
    def inner(*args, **kwargs):
        """
        :param args: 函数名,密码
        :param kwargs: 备用
        :return:  True
        """
        ret = f(*args, **kwargs)
        return ret
    return inner

@logger
def login(username,password):
    """
    此函数是完成登录功能的函数,需要用户名,和密码两个参数,返回True 登陆成功
    :return:  True
    """
    print(666)
    return True
# login(1,2)  #inner()
# # login('alex', 123)
print(login.__doc__)
print(login.__name__)

  

 

 

 

 

 

posted on 2018-05-28 21:10  空舟  阅读(108)  评论(0编辑  收藏  举报

导航