Python 函数进阶

python代码运行的时候遇到函数是怎么做的。

从python解释器开始执行之后,就在内存中开辟了一个空间

每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来。

但是当遇到函数定义的时候解释器只是象征性的将函数名读入内存,表示知道这个函数的存在了,至于函数内部的变量和逻辑解释器根本不关心。

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

这个“存放名字与值的关系”的空间叫做命名空间。

代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间,在函数的运行中开辟的临时的空间叫做局部命名空间。

1、命名空间

命名空间一共分为三种:

  全局命名空间

  局部命名空间

  内置命名空间

三种命名空间的加载和取值关系:

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

取值: 

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

x = 1
def f(x):
    print(x)

print(10)
在局部使用变量情况取值

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

x = 1
def f(x):
    print(x)

f(10)
print(x)
在全局引用变量x
print(max)
在全局引用变量max

1.1内置命名空间:

  就是Python解释器一启动就可以使用的名字存储在内置命名空间中,内置的名字再启动解释器的时候被加载进内存里。如:print、input、list、tuple

1.2 全局命名空间:

  是在程序从上到下被执行的过程中一次加载进内存的,放置了我们设置的所有变量名和函数名。

1.3 局部命名空间

  就是函数内部定义的名字,当调用函数的时候,才会产生这个名称空间,随着函数执行的结束,这个命名空间就又消失了。

 注意:

函数名指向的是一个内存地址,“函数名+()”就可以调用函数了。

def func(x):
    print(x)

print(func)        #<function func at 0x00546C48>

多个函数应该拥有多个独立的局部名字空间,不能共享。下例中第2个a不能被调用:

func  --> 函数的内存地址
函数名() 函数的调用
函数的内存地址() 函数的调用
def func():
    a=1
def func1():
    print(a)    #a不能使用

2、作用域

2.1全局作用域

包含内置名称空间、全局名称空间,作用在全局,在整个文件的任意位置都能被引用、内置和全局名字空间中的名字都属于全局作用域。

a=1
def func1():
    print(a)    #a能使用
全局作用域

2.2局部作用域

局部名称空间,作用在局部,函数(局部名字空间中的名字属于局部作用)

a = 12
b = 20
def func():
    x = 'aaa'
    y = 'bbb'
    print(locals())     #{'x': 'aaa', 'y': 'bbb'}
    print(globals())

func()
在局部调用locals和globals
print(globals())
print(locals())
在全局调用globals和locals

Locals在局部就打印局部的内容,在全局就打印全局的(输出什么,根据locals所在的位置)

但globals 永远打印全局的名字.

a = 10
def func():
    global a
    a = 20

print(a)        #a=10
func()
print(a)        #a=20
global关键字

3、函数的嵌套调用

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
def max()
函数的嵌套调用

函数的嵌套定义:

def outer():
    def inner():
        print('inner')
    inner()
outer()
函数的调用

函数内部使用外部函数的变量,函数先定义再调用

def outer():
    a=1
    def inner():
        print(a)    #a=1
        print('inner')
    inner()
outer()
函数调用

 

4、nonlocal的是使用:

不可变类型变量,不能被修改会报错。

 

a = 1
def outer():
    a=1
    def inner():
        b = 2
        print(a)
        print('inner')
        def inner2():
            a +=1   #不可变类型的修改
            print('inner2')
        inner2()
    inner()
outer()
不可变数据类型的修改

 

a = 1
print('a',a)    #1
def outer():
    a=2
    def inner():
        a = 3
        def inner2():
            global a
            # nonlocal a
            a +=1
            print('*a*', a)   #2
        inner2()
        print('**a**', a)   #3
    inner()
    print('***a***',a)  #2
outer()
print('a', a)#1--->2 因global,在inner2中被修改
global关键字
a = 1
print('a',a)    #a,1
def outer():
    a=2
    def inner():
        a = 3
        def inner2():
            nonlocal a
            # nonlocal a
            a +=1
            print('*a*', a)   #a=3+1  *a* 4
        inner2()
        print('**a**', a)   #a=4 被修改    **a** 4
    inner()
    print('***a***',a)  #***a*** 2
outer()
print('全局a', a)#全局a,1
nonlocal关键字
global:
对于不可变数据类型 在局部可是查看全局作用域中的变量
但是不能直接修改
如果想要修改,需要在程序的一开始添加global声明
如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效
nonlocal
只能用于局部变量 找上层中离当前函数最近一层的局部变量

声明了nonlocal的内部函数的变量修改会影响到 离当前函数最近一层的局部变量
对全局无效
对局部 也只是对 最近的 一层 有影响
5、作用域链
在内部函数使用变量的时候,是从小局部到大局部,到内置名字的过程,一级一级往上找,找到最近的一个就使用。
a = 1
def outer():
    def inner():
        def inner2():
            print('*a*', a)   #a=1  
        inner2()
    inner()
outer()
作用域链

6、函数的本质

就是一个变量,保存了函数所在的内存地址。

func()函数名就是内存地址
func2 = func 函数名可以赋值
l = [func,func2] #函数名可以作为容器类型的元素
print(l)
for i in l:
    i()
函数名可以作为容器类型的元素

def func():
    print(123)

def wahaha(f):
    f()
    return f           #函数名可以作为函数的返回值
函数名可以作为函数的返回值
def func():
    print(123)

def wahaha(f):
    f()
    return f         

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

7、闭包

定义:必须是嵌套函数,内部函数调用外部函数的变量。

def outer():
    a = 1
    def inner():
        print(a)
    return inner
inn = outer()
inn()
闭包
def outer():
    a = 1
    def inner():
        print(a)
    print(inner.__closure__)       #(<cell at 0x0057EBF0: int object at 0x50A756F0>,)
outer()
判断是否闭包函数

8、urlopen模块

闭包函数获取网络的应用

import urllib  #模块
from urllib.request import urlopen
ret = urlopen('http://www.xiaohua100.cn/index.html').read()
print(ret)
def get_url():
    url = 'http://www.xiaohua100.cn/index.html'
    ret = urlopen(url).read()
    print(ret)

get_url()
import urllib #模块

 

# 1.编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码
# flag=True
# def wrapper(login):
#     def inner(*args,**kwargs):
#         with open('E:\S9 Python code\practice\zzm',encoding='utf-8') as f:
#             s = f.readlines()   #获取文件中的用户名与密码
#             name = s[0].strip() #获取用户名--->name
#             word = s[1].strip() #获取密码--->word
#         global flag     #在全局调用flag
#         while flag:
#             username = input('username:')   #输入用户名
#             password = input('password:')   #输入密码
#             if username == name and password == word:
#                 print('认证成功')
#                 flag = False    #修改全局变量flag的值,停止循环
#             else:
#                 print('用户名或密码错误,请重新输入:')
#         ret = login(*args,**kwargs)         #调用函数
#         return
#     return inner
#
# @wrapper
# def add():
#     print('successful add')
# add()
#
# @wrapper
# def update():
#     print('successful update')
# update()


# 2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
# def wrapper(log):
#     def inner(*args,**kwargs):
#         ret=log(*args,**kwargs)
#         with open('E:\S9 Python code\homework\zab',mode='a+',encoding='utf-8')as f: #打开文件,操作方式为追加
#             f.write(log.__name__+'\n')      #将运行后的函数名写入文件f 函数名.__name__ 可获取函数名
#         return ret
#     return inner
#
# @wrapper
# def update():
#     print('successful update')
# update()
#
# @wrapper
# def add():
#     print('successful add')
# add()


# 进阶作业(选做):
# 1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
# from urllib.request import urlopen
# def get(url):
#     code = urlopen(url).read
#     return code
#
# ret = get('http://www.baidu.com')
# print(ret)

# 2.为题目1编写装饰器,实现缓存网页内容的功能:

# import os
# from urllib.request import urlopen
# def wrapper(f):
#     def inner(*args,**kwargs):
#         if os.path.getsize('zab'):  #判断文件是否为空,空则不执行with
#             with open('zab','rb')as f1: #以读打开zab这个文件,并进行读取
#                 return f1.read()        #获得返回值
#         ret = f(*args,**kwargs)
#         with open('zab','wb')as f1:     #以读打开zab这个文件,并进行读取
#             f1.write(b'********'+ret)   #返回b'********'+ret
#         return ret                      #返回获取的网页内容
#     return inner
#
# @wrapper
# def get(url):
#     code = urlopen(url).read()          #获取网页内容
#     return code
#
# ret = get('http://www.baidu.com')
# print(ret)
# ret = get('http://www.baidu.com')
# print(ret)
# ret = get('http://www.baidu.com')
# print(get(ret))
作业

 

 

 

 

 

 

posted @ 2017-12-27 19:54  amyleell  阅读(92)  评论(0)    收藏  举报