1函数的对象与嵌套、名称空间与作用域、闭包函数

1.1函数的对象

函数是第一类对象,指的是函数名指向的值(函数)可以被当作数据去使用

def func():# func=函数的内地址
  print('from func')

print(func)

age=10
#1. 可以被引用
x=age
print(x,age)

f=func
print(f)
f()

#2. 可以当作参数传给另外一个函数
def bar(x):
  print(x)

bar(age)
bar(func)

#3. 可以当作一个函数的返回值
def bar(x):
  return x

res=bar(age)
print(res)

res=bar(func)
print(res)

#4. 可以当作容器类型的元素
l=[age,func,func()]
print(l)


1.2、函数的嵌套

1.2.1.函数嵌套分为两大类

1.2.1.1函数的嵌套调用:在调用一个函数过程中,其内部代码又调用了其他函数
def max2(x,y):
  if x > y:
    return x
  else:
    return y

def max4(a,b,c,d):
  res1=max2(a,b)#2
  res2=max2(res1,c)#3
  res3=max2(res2,d)#4
  return res3

print(max4(1,2,3,4))#4
1.2.1.2函数的嵌套定义:一个函数内部又定义了另外一个函数
案例一
def outter():
    x=1
    print('from outter')
    def inner():
        print('from inner')
    print(x)
    print(inner)

outter()
#from outter
#1
#<function outter.<locals>.inner at 0x000001D175B7CB70>

inner()#无法在外部调用内部函数
案例二
def f1():
    print('from f1')
    def f2():
        print('from f2')
        def f3():
            print('from f3')
        f3()
    f2()
f1()
#from f1
#from f2
#from f3
案例三
from math import pi
print(pi)#3.141592653589793

def circle(radius,action=0):
    """
    圆形相关运算
    :param radius: 半径
    :param action: 0代表求面积,1代表求周长
    :return: 面积或者周长
    """
    def area(radius):
        return pi * (radius ** 2)

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

    if action == 0:
        res=area(radius)
    elif action == 1:
        res=perimiter(radius)

    return res


print(circle(10,0))#314.1592653589793
print(circle(10,1))#62.83185307179586

1.3、名称空间与作用域

1.3.1 什么是名称空间namespace

名称空间就是用来存放名字与值内存地址绑定关系的地方(内存空间)

age=18
但凡查找值一定要通过名字,访问名字必需去查找名称空间

1.3.2 名称空间分为三大类

1.3.2.1内置名称空间

存放的是python解释器自带的名字
例如:
len
max
print

1.3.2.2全局名称空间

存放的是文件级别的名字
例如:以下名字中x\y\z\b\foo都会存放于全局名称空间中

x=1
y=2
if x == 1:
    z=3

while True:
    b=4
    break

def foo():
  m=3

 

1.3.2.3局部名称空间

在函数内定义的名字
例如:
foo内的m这个名字一定是存放于一个局部名称空间中

1.3.2.4生命周期

内置名称空间:在解释器启动时则生效,解释器关闭则失效
全局名称空间:在解释器解释执行python文件时则生效,文件执行完毕后则失效
局部名称空间:只在调用函数时临时产生该函数的局部名称空间,改函数调用完毕则失效

1.3.2.4加载顺序

内置->全局->局部

1.3.2.5查找名字的顺序

基于当前所在位置往上查找
假设当前站在局部,查找顺序:局部->全局->内置
假设当前站在全局,查找顺序:全局->内置

 案列一:
len=111

def foo():
    len=222
    print(len)

foo()
print('站在全局找len: ',len)
案例二
x=111

def f1():
    x=222
    def f2():
        def f3():
            x=444
            print(x)#444
        x=333
        f3()
    f2()
f1()

 

(******)名字的查找顺序,在函数定义阶段就已经固定死了(即在检测语法时就已经确定了名字的查找顺序),与函数的调用位置无关,也就是说无论在任何地方调用函数,都必须回到
当初定义函数的位置去确定名字的查找关系

案列三:
x=111
def outer():
    def inner():
        print('from inner',x) # x访问的时全局名称空间中x
    return inner
f=outer()

x=222
f()#222
案列四:
x=111
def outer():
    def inner():
        print('from inner',x) # x访问的时全局名称空间中x
    return inner

f=outer()

# x=222
def func():
    x=333
    f()

x=444

func()#444
案列五:
x=111
def outer():
    def inner():
        print('from inner',x) # x是来自于当前层的名字,但是此时的x并未定义
        x=2222222222
    return inner

f=outer()

f()

1.3.3.作用域:

域指的是范围,作用域指的就是作用的范围,分为两种
全局作用域:包含的是内置名称空间与全局名称空间中的名字
特点:全局有效,全局存活

局部作用域:包含的是局部名称空间中的名字
特点:局部有效,临时存活

案例一
x=1#全局存活

def foo():
    y=2
    print(x)#1

def bar():
    print(x)#1

foo()
bar()
案例二
x=1
def foo():
    x=2#局部有效
foo()
print(x)#1
案例三
l=[]#这个l是存放在全局空间
def foo():
    l.append(1)#报错,在局部名称空间中没有l
    l=33333
foo()
print(l)

 

global:在局部声明一个名字是来自于全局作用域的,可以用来在局部修改全局的不可变类型

x=1
def foo():
    global x
    x=2
foo()
print(x)#2

 

nonlocal:声明一个名字是来自于当前层外一层作用域的,可以用来在局部修改外层函数的不可变类型

x=0
def f1():
  x=111
  def f2():
    nonlocal x#只能修改当前函数的外面一层而已
    x=222
  f2()
  print(x)#222

f1()
print(x)#0

 

1.4、闭包函数

1.4.1 什么是闭包函数

闭:指的是闭包函数是定义在一个函数内部的函数
包:该内部函数包含对外层函数作用域名字的引用

需要结合函数对象的概念将闭包函数返回到全局作用域去使用,从而打破函数的层级限制

def outter():
  x=111
  def inner():
    print(x)
  return inner

f=outter() #f=outter内的inner

1.4.2 为何要用闭包函数

闭包函数提供了一种为函数体传值的解决方案

1.4.3 如何用闭包函数

1.4.3.1为函数体传值的方式一:参数
def func(x,y):
  print(x+y)
func(1,2)

 

1.4.3.2为函数体传值的方式二:闭包
def outter(x,y):
    def func():
        print(x+y)
    return func

f=outter(1,2)
f()
1.4.3.3案例

需求
def get():
  respnotallow=requests.get(url)
  if response.status_code == 200:
    print(response.text)


解决方案一:参数
pip3 install requests

import requests
def get(url):
  response=requests.get(url)
  if response.status_code == 200:
    print(len(response.text))

get('https://www.baidu.com')
get('https://www.baidu.com')
get('https://www.baidu.com')
get('https://www.tmall.com')
get('https://www.tmall.com')

url1='https://www.baidu.com'
url2='https://www.tmall.com'

get(url1)
get(url1)
get(url1)

get(url2)
get(url2)
get(url2)
 解决方案二:闭包
def outter(url):
    # url='https://www.baidu.com'
    def get():
        response=requests.get(url)
        if response.status_code == 200:
            print(len(response.text))
    return get

baidu=outter('https://www.baidu.com')


tmall=outter('https://www.tmall.com')