函数进阶

三元运算
变量 = 条件返回true的结果  if  条件 else 条件返回false的结果

#如:返回a,b中较大的值
a = 1
b = 5
c = a if a>b else b
print(c)

使用函数的目的:可用性强,复用性强
默认参数的陷进
如果默认参数的值是一个可变数据类型,那么每一次调用函数时,如果不传参数就公用这个数据类型的资源。

①def qqxing(L = []):
    L.append(2)
    print(L)
qqxing()        #结果:[2]
qqxing()        #结果:[2,2]

②def qqxing(L={}):
    L['k'] = 'v'
    print(L)
qqxing()     #结果:{'k':'v'}
qqxing()      #结果:{'k':'v'}
           #两个结果一样,因为字典的键值不可重复

③def qqxing(k,L ={}):
    L[k] = 'v'
    print(L)
qqxing(1)    #结果:{1: 'v'}
qqxing(2)    #结果:{1: 'v', 2: 'v'}

命名空间和作用域:
函数的命名空间有三种
内置命名空间———python解释器
  ①python解释器可以使用的名字存储再内置命名空间中
  ②内置的名字再启动解释器时被加载到内存里
全局命名空间------我们写的代码但不是函数中的代码
  ①是在程序从上到下被执行的过程中依次加载进内存的
  ②放置了我们设置的所有变量名和函数名
局部命名空间————函数
  ①就是函数内部定义的名字
  ②当调用函数时才会产生这个命名空间,随着函数调用的结束,这个命名空间就又消失了。
在局部:可以使用全局也可以使用内置命名空间中的名字:
在全局:可以使用内置命名空间中的名字但不能用局部
在内置:不能使用全局和局部的名字
注:
①当我们在全局定义了和内置命名空间中同名的名字时,会使用全局的名字
②在正常情况下直接使用内置的名字
③当自己有的时候就不找上级要了
④如果自己没有,就找上一级要,上一级没有再找上一级,若内置的名字空间都没有就会报错
⑤多个函数应该拥有多个独立的局部名字空间,不能相互共享

作用域(两种)
全局作用域-----作用在全局
     ①内置和全局名字空间中的名字都属于全局作用域
布局作用域-----作用在局部
     ①函数(局部名字空间中的名字属于局部作用域)
globals
①对于不可变数据类型,在局部可以查看全局作用域中的变量但是不能修改,
  如果想要修改,需要在程序的一开始添加global声明
②如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效
两个方法查看变量和值
①局部名称空间中的变量和值用locals()查看
②全局名称空间中的变量和值用globals()查看
③globals()永远打印全局的名字;locals()输出什么是根据locals所在的位置,如果在全局则打印全局名字,如果在局部则打印局部名字)
函数的嵌套调用

def max(a,b):
    return a if a>b else b
def the_max(x,y,z):
    c = max(x,y)
    return max(c,z)
print(the_max(1,2,3))

函数的嵌套定义

def outer():
    def inner():
        print('inner')
    inner()
outer()

内部函数可以使用外部函数的变量

def outer():
    a = 1
    def inner():
        print(a)
        print(inner)
    inner()
outer()

nonlocal
①声明了nonlocal的内部函数的变量修改会影响到离当前函数最近一层的局部变量
②只能用于局部变量,找上层中里当前函数最近一层的局部变量
③对全局无效,对局部也只是对最近一层有影响

a = 0
def outer():
    a = 1
    def inner():
        a = 2
        def inner2():
            nonlocal a
            print(a+2)
        inner2()
    inner()
outer()

函数名的本质:

函数名加括号等价于函数的内存地址加括号;函数名加括号代表一个函数的执行;
去掉括号表示函数的内存地址;即根据函数名能找到内存地址

①函数名就是内存地址
②函数名可以赋值  func2 = func
③函数名可以作为容器类型的元素 L = [func,func2]
④函数名可以作为函数的参数
⑤函数名可以作为函数的返回值

def func():
    print(123)
def func2(W):
    W()          #W()相当于func()
func2(func)      #func作为参数传给W,W得到的时func的地址
                 #结果:123

函数名是第一类对象:
第一类对象是指:①可在运行期间创建
                          ②可以作为函数的参数和返回值
                             ③可存入变量的实体
闭包:必须是嵌套函数,且内部函数必须调用外部函数的变量

def outer():
    a = 1
    def inner():
        print(a)
    print(inner.__closure__)   #_closure_查看inner是否是闭包
outer()

闭包最常用的形式

def outer():
    a = 1
    def inner():
        print(a)
    return inner
inn = outer()
inn()            #在函数得外部使用它得内部函数

闭包的应用

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