可变长参数、函数的嵌套、名称空间和作用域学习笔记

写在博客的开头

nick说:人生疾苦唯有自救,这是你相信IT的最后一次机会。这个时候必须得逼自己一把,只有对自己够狠才能慢慢强大。昨天看一哥们在博客上说每天大喊一遍python第一java第二,python大法无所不能,给自己以一个乐观积极的态度好好学习天天向上。加油,希望我们每一个人都不负光阴。

可变长参数

*形参名

def f1(*args):#调用时有多少个位置实参就接收多少个
    print(args)#\*args(约定俗成的),用元组接收多余的位置实参

**形参

def f1(**kwargs):
    print(kwargs)#用字典接收多余的关键字实参

以上内容很important,以下内容仅作了解(Nick说以后很少用到)

*实参

def f1(a,b,c,d,e,f,g):
    print(a,b,c,d,e,f,g)
    
    lt = [1,2,3,4,5,6,7]
    f1[*lt]#\*lt把列表中的元素打散成位置实参一次传给位置形参(这个过程其实就是解压缩)

**实参

def f1(z,b):
    print(z,b)
dic = {'z':,'b':2}
f1(**dic)#**dic把字典打散成关键字实参然后传给函数f1

函数对象

Python中一切皆对象,函数是第一类对象,即函数可以被当作数据处理。

def func():
    print('from func')
    
prnit(func)

<function func at 0x10af72f28>

一、函数对象的四大功能

  1. 引用

    x = 'hello nick'
    y = x
    
    f = func#这么做的的原因是:这样f()和func()就是同一个函数了
    print(f)
    

    <function func at 0x10af72f28>

  2. 当做参数传给一个函数

    len(x)
    
    def foo(m):
        m()
    foo(func)#func是一个函数名,将func作为实参传给foo这个函数,形参m用于接收func,执行到foo函数体里面就得到了func()实现了对func函数的调用。 
    

    from func

  3. 可以当做函数的返回值

    def foo(x):
        return x
    
    res = foo(func)
    print(res)
    res()#func被return回来赋给res从而实现了对func函数的调用
    

    <function func at 0x10af72f28>
    from func

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

    l = [x]
    
    function_list = [func]
    function_list[0]()#这个就很叼了,在调用登录注册等多个函数时把函数名作为字典的value,然后通过这种方法去调用函数贼方便。
    

    from func

练习

def register():
    print('register')
def login():
    pass
def withdraw():
    pass
def shoppong():
    print('shopping')
func_dict = {
    '1':register,
    '2':login,
    '3':withdraw,
    '4':shopping,
}
print('''
1 注册
2 登录
3 提现
4 购物
''')
while Ture:
    choice = input('请选择你需要的功能(输入q退出):')
    if choice == 'q':
        break
     func_dict[choice]()#函数当做容器类型的元素
    

函数的嵌套

所谓嵌套就是在函数内部再定义函数,不过函数内部定义的函数,无法在函数外部使用。

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

f2()  
# NameError: name 'f2' is not defined

这个就可以使用:

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

f1()

from f2

函数嵌套的调用

如下面一个比较四个数大小得出最大值的函数

def compare_1(x,y):
    if x>y:
        return x
    else:
        return y
def compare_2(a,b,c,d):
    res1 = compare_1(a,b)
    res2 = compare_1(res1,c)
    res3 = compare_1(res2,d)#牛掰哦这种比较方法
        return res3
#compare_2(1,2,3,4)
print(compare_2(1,2,3,4))

4

名称空间和作用域

一、名称空间

名称空间(name spaces):在内存管理那一章节时,我们曾说到变量的创建其实就是在内存中开辟了一个新的空间。但是我们一直在回避变量名的存储,其实在内存中有一块内存存储变量名与变量间的绑定关系的空间,而这个空间称为名称空间。

1.1 内置名称空间

内置名称空间:存放Pyhton解释器自带的名字,如int、float、len

生命周期:在解释器启动时生效,在解释器关闭时失效。

1.2 全局名称空间

全局名称空间:除了内置和局部的名字之外,其余都存放在全局名称空间。

生命周期:在文件执行时生效,在文件执行结束后失效。

1.3 局部名称空间

局部名称空间:用于存放函数调用期间函数体产生的名字,如下面代码的f2

生命周期:在文件执行时函数调用期间时生效,在函数执行结束后失效。

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

1.4 加载顺序

由于.py文件是由Python解释器打开的,因此一定是在Python解释器中的内置名称空间加载结束后,文件才开始打开,这个时候才会产生全局名称空间,当文件内某一个函数被调用时,才会产生局部名称空间,因此名称空间的加载顺序为:内置》全局》局部》。

1.5 查找顺序

由于名称空间是用来存放变量名与变量值之间的绑定关系的,所以但凡要查找名字,一定要从三者之一找到,查找顺序为:

从当前所在的位置开始查找,如果当前所在的位置为局部名称空间,则查找顺序为:局部》全局》内置。

x = 1
y = 2
len = 100

def func():
    y = 3
    len = 1000
    print(f"y:{y}")
    print(f"len:{len}")
   
func()    

y: 3
len: 1000

def func():
    
    printx
x = 10
func()

10

二、作用域

域指的是区域,作用域就是作用的区域。

2.1 全局作用域

全局作用域:全局有效,全局存活,包含内置名称空间和全局名称空间。

#全局作用域
x = 1
def bar():
    print(x)
bar()

1

2.2 局部作用域

局部作用域只包含局部名称空间。

def f1():
    def f2():
        def f3():
            print(x)
        x = 2
        f3()
    f2()
f1()

2

2.3 注意点

作用域关系在函数作用阶段就固定死了,与函数的调用无关。

# 作用域注意点
x = 1


def f1():  # 定义阶段x=1
    print(x)


def f2():
    x = 2
    f1()

f2()

1

很绕的一个例子,画个图看一下:

程序运行的时候内存空间的开辟如图所示,所以当f1()运行的时候,程序会先在f1()的局部作用域内找x的值,找不到就去全局找而不是去f2()的作用域内找。再看下面一个例子:

x = 1
def f2():
    x = 2

    def f1():  # 定义阶段x=1
        print(x)
    f1()
f2()

2

这个f1执行完就回去f2找x的值,因为f1的作用域在f2里面。

2.4 函数对象+作用域应用

# 作用域应用
def f1():
    def inner():
        print('from inner')
    return inner

f = f1()  # 把局部定义的函数放在全局之中

def bar():
    f()

bar()#相当于f1()(),相当于inner()

from inner

三、补充知识点

3.1 global关键字(尽量少用,Nick说容易懵逼)

修改全局作用域中的变量。

x = 1


def f1():
    x = 2

    def f2():
        #         global x  # 修改全局
        x = 3
    f2()


f1()
print(x)

1

x = 1


def f1():
    x = 2

    def f2():
        global x  # 修改全局
        x = 3
    f2()


f1()
print(x)

3

3.2 nonlocal关键字(最好不要使用,容易把自己弄懵逼)

修改作用域中的变量。

x = 1


def f1():
    x = 2

    def f2():
        #         nonlocal x
        x = 3

    f2()
    print(x)


f1()

2

x = 1


def f1():
    x = 2

    def f2():
        nonlocal x
        x = 3

    f2()
    print(x)


f1()

3

3.3 注意点(very important)

  1. 可变数据类型可以打破上述一切规则。
lt = [10]


def f1():
    lt.append(12)
    lt[0] = 11


f1()

print(lt)

[11, 12]

  1. 在局部如果想修改全局的不可变类型,需要借助global声明,声明为全局变量,即可直接修改。
posted @ 2019-09-20 21:41  ylpb  阅读(250)  评论(0编辑  收藏  举报