我的Python成长之路---Day11-函数的使用及名称空间和作用域

版权声明:此博客实属作者原创,转载请注明出处! https://blog.csdn.net/Onion_cy/article/details/82853786

1.昨天函数的参数内容的补充

命名关键字参数: 在定义函数时,*与**之间参数称之为命名关键字参数
特点:
在调用函数时,命名关键字参数必须按照key=value的形式传值

def func(x,*,y=1,z):       在这里*后边的y和z都是命名关键字参数,y像默认参数一样被事先赋值好了,再实 
                           参进行传值的时候可以不对y进行传值
    print(x)
    print(y)
    print(z)

func(1,z=2)                传值的时候必须要使用key=value的形式才可以传值成功.

def func(a,b=2,*args,c,**kwargs):     设置形参时各种形参的位置顺序
    print(a)
    print(b)
    print(args)
    print(c)
    print(kwargs)

------------------------------------------------------------------------------------分割线----------------------------------------------------------------------------

一、函数对象

函数是第一类对象: 指的是函数的内存地址可以像一个变量值一样去使用

def foo():                        #foo  不加括号代表函数的内存地址
    print('from foo')

1. 变量值可以被引用
x=1                                #foo=函数的内存地址
y=x

f=foo
print(f)                          输出:<function foo at 0x0000024CF6E63E18>
f()                                 输出:from foo

2. 变量值可以当作参数传给另外一个函数
def bar(x):        这时的x=foo
    print(x)          将函数foo的内存地址打印出来
    x()                 相当于调用函数foo(),会实现foo的功能


bar(foo)             函数bar中的参数为函数foo(foo的内存地址)

3. 变量值可以当作函数的返回值
def func(x):
    return x          将foo当做返回值返回

f=func(foo)         将foo当做参数传给函数func,接受参数为foo时func的返回值
print(f)                其实这里打印的还是foo的内存地址

4. 变量值可以当作容器类型中(容器类型指的是:元组、列表、字典)的元素
l=[foo,]               将foo当做列表中的元素
print(l)                输出:[<function foo at 0x0000016828A43E18>]
l[0]()                   使用列表的特点调用函数foo

dic={'1':foo}        将foo当做字典中的元素
print(dic)
dic['1']()              使用字典特点调用函数foo

-----------------------------------------------------------------------使用函数对象的第四个特点对简易购物车进行优化--------------------------------

def register():               前面定义函数实现相应的功能
    print('注册....')

def login():
    print('登录....')

def pay():
    print('支付....')

def transfer():
    print('转账....')

func_dic={                    利用函数对象的第四个特点,将函数(内存地址)存放在字典中
    '1':register,
    '2':login,
    '3':pay,
    '4':transfer
}

#func_dic['1']()             可以使用这样的形式直接调用相应功能的函数 

'''
整体代码就不用写特别长了,并且可拓展性相对于之前来说好了很多,想要添加什么功能,直接定义函数实现功能的添加,然后在字典中添加新功能对应的键值对,再在打印阶段打印出新功能的提示信息就可以了,主代码并不需要改动即可实现新功能的添加
'''
while True: 
    print("""
    0 退出
    1 注册
    2 登录
    3 支付
    4 转账
    """)
    choice=input('请输入你的操作: ').strip()
    if choice == '0':break        这里输入0对应的操作代码不能喝下面的判断代码互换位置,换了位 
                                  置之后就不能实现退出的功能,会被判定为为错误的指令输入,因为字 
                                  典中的key没有0

    if choice not in func_dic:
        print('输错的指令不存在')   判断输入的指令编号是否存在与字典中
        continue

    func_dic[choice]()            执行相应key对应的函数

二、函数嵌套

函数的嵌套调用:在一个函数内部又调用其他函数

def max2(x,y):
    if x > y:
        return x
    else:
        return y

def max4(a,b,c,d):
    res1=max2(a,b)             在一个函数中又调用其他的函数
    res2=max2(res1,c)
    res3=max2(res2,d)
    return res3

print(max4(1,2,3,4))

函数的嵌套定义: 在函数内又定义了其他函数

def func():
    def foo():                  在func中嵌套定义函数foo
        print('from foo')
    # print(foo)                如果在这里打印foo打印出来的是foo的内存地址
    foo()                       在func中也可以直接调用定义好的foo
    x=1
    print(x)                    这里x的值为1

func()
-------------------------------------------函数嵌套的使用---------------------------------
使用函数嵌套可以将同系列的函数功能统一到一个函数里边,简化了函数的调用
下边是一个函数嵌套的例子

from math import pi

def circle(radius,action):       可以直接通过参数来选择来进行的操作,是要结算周长还是计算面积
    def cal_perimeter():
        return 2 * pi * radius

    def cal_area():
        return pi * (radius ** 2)

    if action == 1:
        res=cal_perimeter()
    elif action == 2:
        res=cal_area()
    return res

res=circle(10,1)
print(res)

 

三、函数的名称空间和作用域

一 、名称空间相关
1. 名称空间Namespaces:指的就是存放名字与值内存地址绑定关系的地方(内存空间)
x=1,需要在内存中申请一个空间来存放1这个值,同时还要寻找一个内存空间来存储x和1的内存地址绑定关系的空间,存放名字与值对应绑定关系的地方就成为名称空间,

2. 名称空间分为三大类
内置名称空间: 存放的是python解释器自带的名字(例如len()、print()、等等)
    产生:python解释器的启动则产生
    销毁:python解释器关闭则销毁

全局名称空间: 在顶级代码中定义的名字

    产生:执行python程序时产生
    销毁:python程序执行完毕后则销毁

x=1
if True:
    y=2
while True:
    while True:
        while True:
            z=3                    z=3在这里也算做顶级代码中定义的名字,因为while循环是一直往下走的一直走到了z=3,相当于写了一行代码,只不                                        过z=3写在最后边而已,也是存在于全局名称空间中的.

局部名称空间: 在函数内定义的名字
    产生: 在函数调用时临时产生
    销毁: 在函数调用完毕后则销毁

def foo():
    m=100                        比如这里的m就属于局部名称空间中的,局部名称都是函数调用时临时产生临时销毁的

foo()

三种名称空间的产生的先后顺序: 内置->全局->局部
查找名字的顺序:从当前位置往外一层一层查找             查找名字指的是在执行当前代码时,所需要用到的变量名的名字,并这行代                                                                                          码所在位置就是当前位置
    如果当前在局部名称空间: 局部->全局->内置
    如果当前在全局名称空间: 全局->内置

# len=111
# def foo():
#     # len=222
#     print(len)           在这里打印len的时候,首先从局部名称空间找,找到len=222,
# len=111                  如果局部空间len=222不存在,就从全部名称空间找,可以找到len=111,
                           如果全部名称空间的len=111不存在,就从内置名称空间中找,这时候打印出来 
                           的len就是python解释器中求长度的函数len()的内存地址
# foo()

# x=0
def f1():
    # x=1
    def f2():
        # x=2
        def f3():
            # x=3
            print(x)
        f3()            
    f2()                
f1()    在f1()的最终结果中x=0,x=1,x=2,x=3都存在话,f1()的最终结果为x=3,如果从x=3.x=2,x=1,x=0一 
        次被注释掉的时候,f1()的最终结果依次为3,2,1,0 这就是函数嵌套时寻找变量名的顺序               

def foo1():
    def foo2():
        def foo3():
            print(x)

'''

二 、作用域:指的是作用范围
全局作用域:包含内置名称空间与全局名称空间的名字
    特点:全局存活(该范围内的名字会伴随程序整个的生命周期,即从读取出来到运行完毕关闭的时候),

            全局有效(在任何位置都能访问的到)

局部作用域:包含的是局部名称空间的名字
    特点:临时存活(只有在调用函数时生效,调用结束时失效)

            局部有效(只能在函数内使用)

作用域关系是在函数定义阶段就已经固定死了,与调用位置无关


示范一:

def f1():
    print(xxx)
xxx=111

def f2():
    xxx=222
    f1()        在这里调用f1()时打印出来的值并不是222因为f1中xxx的值在定义阶段已经被定义了xxx=111 
                无论在哪个地方调用f1,打印出来的值都是111

示范二:

xxx=111

def f1():
    print(xxx)           这里程序会进行报错,原因是在定义阶段已经就近找到了xxx的值为222但是在函数 
                         调用阶段又出现了xxx=111的情况,和定义的时候出现了冲突,去掉函数头顶的 
                         xxx=111即可正常使用函数,这时xxx的值为222
    xxx=222
    yyy=222
    print(yyy)            这里的yyy是可以正常输出的,在定义阶段yyy=222,调用函数的时候没有与定义阶 
                          段冲突,但是如果在函数头顶加上yyy=333时,调用时就会出现和xxx一样的错误 
             
f1()

(全局/局部)名称空间:是存放值与变量名绑定关系的内存空间,是存(全局/局部)变量的地方

(全局/局部)作用域:指的是(全局/局部)变量起作用的范围

(全局/局部)变量:存放在(全局/局部)名称空间中,在代码中体现为全局变量是在顶级代码的位置的,局部变量是在函数体内部的

四、闭包函数

闭包函数:
闭:封闭,指的是该函数是定义一个函数内部的函数
:该内部函数包含对外层函数名字(这里的外层函数名字指的是外层函数包含的局部变量)的引用

def outter():                   inner在这里就是一个典型的闭包函数,它定义在outter()内部,在inner 
                                中使用的x属于outter的局部变量,也就是相对于inner来说的外部函数名 
                                字的引用.
    x=1
    def inner():
        print('from inner',x)
    return inner

f=outter()

def foo():
    # print(f)
    x=111111111111111111111111111111111111
    f()           在这调用f()时,x的值不会受到x=11111111111111111111111的影响,因为在f()定义阶段 
                                                                                       x=1
foo()                 

为函数体传值的两种方式:
def foo():
    print('hello %s' %name)

方式一:直接以参数的形式传入
def foo(name):
    print('hello %s' %name)

foo('egon')
foo('egon')
foo('egon')              这种在调用的时候每次都要输入要传给参数的内容,调用的时候如果遇到要经常传较长内容内参数的时候就会比较麻烦

方式二:闭包函数(使用闭包函数传值给函数体)
def outter(name):
    # name='egon'(省略了这一步)
    def foo():
        print('hello %s' %name)
    return foo

f=outter('egon')     之后就可以直接调用f()就可以打印出来hello egon
# print(f)
f()
f()
f()

f1=outter('alex')
f1()
f1()
f1()

pip3 install requests   安装python中爬虫必要的组件,直接在cmd中输入改命令就可以

闭包函数的简单应用
import requests

问题     要给url传值(也就是需要爬的网站名字)
def get():     
    response=requests.get(url)
    if response.status_code == 200:
        print(response.text)

解决方案一:(设置参数,给参数赋值)
def get(url):
    response=requests.get(url)
    if response.status_code == 200:
        print(response.text)

get('https://www.baidu.com')         缺点:每次爬取都需要给参数url传内容,调用比较麻烦
get('https://www.baidu.com')
get('https://www.baidu.com')

解决方案二:(使用闭包函数给url传值)

def outter(url):
    # url='https://www.baidu.com'
    def get():
        response=requests.get(url)
        if response.status_code == 200:
            print(response.text)
    return get

baidu=outter('https://www.baidu.com')           一次传值后赋值给变量名,以后可以重复使用
cnblogs=outter('https://www.cnblogs.com')

baidu()
baidu()
baidu()
baidu()
baidu()
baidu()

cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()
cnblogs()

 

 

猜你喜欢

转载自blog.csdn.net/Onion_cy/article/details/82853786
今日推荐