一、函数的本质【重点掌握】
函数就是一个变量,可以重新赋值,可以作为函数的参数,也可以作为函数的返回值
# 1.函数就是一个变量
print(abs(-66)) # 函数的调用,66
print(abs) # 函数本身,<built-in function abs>
print(type(abs)) # <class 'builtin_function_or_method'>
r1 = abs(-66)
print(r1)
r2 = abs
print(r2)
# 注意1:函数本身是一个变量,函数名可以给其他变量直接赋值,赋值之后,可以使用该变量调用函数
print(r2(-88)) # 88
f = int
print(f('234'))
def test():
print("test~~~~")
f = test
f()
# 2.函数名可以重新赋值
# 注意2:自定义变量名的时候,尽量避免和系统的关键字或函数名重名,如:list(),int(),str(),dict()
# abs = 'abc'
# print(type(abs)) # <class 'str'>
# print(abs(-99))
# 3.函数可以作为另一个函数的参数使用
numlist = ['fafa','agahaha','23']
numlist.sort(key=len) # len(xx)
print(numlist)
def func1(a,b,f):
total = f(a) + f(b)
return total
r = func1(34,-6,abs)
print(r)
# 4.函数也可以作为另一个函数的返回值使用
def func1(a,b,f):
total = f(a) + f(b)
return f
f1 = func1(345,67,abs)
print(f1) # <built-in function abs>
print(f1(-19))
# 总结:函数就是一个变量,函数名就是一个变量名,只要变量能进行的操作,函数都可以
二、闭包【重点掌握】
函数只是一段可执行代码,编译后就“固化”了,每个函数在内存中只有一份实例,得到函数的入口点便可以执行函数了。函数还可以嵌套定义,即在一个函数内部可以定义另一个函数,有了嵌套函数这种结构,便会产生闭包问题
# 1.需求:在func2函数中访问func1中的num1变量
# 方式一:设置返回值,通过调用函数获取返回值
# def func1():
# num1 = 10
# return num1
# def func2():
# print(func1())
# func2()
# 方式二:进行函数的嵌套定义,就可以直接访问
def func1():
num1 = 10
def func2():
print(num1)
print("*" * 50)
# 2.嵌套定义的函数如何调用
# 方式一:在外部函数中直接调用
def outer1():
print("外部函数~~~~1111")
num1 = 10
def inner1():
print("内部函数~~~~1111")
print(num1)
inner1()
outer1()
print("*" * 50)
# 方式二:给外部函数设置返回值。返回值为内部函数
def outer1():
print("外部函数~~~~1111")
num1 = 10
def inner1():
print("内部函数~~~~1111")
print(num1)
return inner1
f1 = outer1()
print(f1) # <function outer1.<locals>.inner1 at 0x1084e16a8>
f1()
print("*" * 50)
# 3.闭包
"""
概念:如果两个函数嵌套定义,如果内部函数访问了外部函数中的变量,则会形成一个闭包
"""
# a.
def outer1():
print("外部函数~~~~1111")
num1 = 10
def inner1():
print("内部函数~~~~1111")
print(num1)
return inner1
f1 = outer1()
print(f1)
f1()
print("*" * 50)
# b.
def outer1(a):
print("外部函数~~~~1111")
num1 = 10
def inner1():
print("内部函数~~~~1111")
print(num1,a)
return inner1
f1 = outer1(8)
print(f1)
f1()
print("*" * 50)
# c.
def outer1(a):
print("外部函数~~~~1111")
num1 = 10
def inner1(b):
print("内部函数~~~~1111")
print(num1,a,b)
return inner1
f1 = outer1(8)
print(f1)
f1(78)
print("*" * 50)
# d.
def outer1(a):
print("外部函数~~~~1111")
num1 = 10
def inner1(b):
print("内部函数~~~~1111")
print(num1,a,b)
return a + b
return inner1
f1 = outer1(8)
print(f1)
r = f1(78)
print(r)
"""
总结:
a.闭包是一个函数的嵌套定义
b.判断是否是闭包的特征:内部函数是否访问了外部函数中的变量
c.闭包本质上还是一个函数,所以普通函数中使用的默认参数,关键字参数,不定长参数和返回值都可以使用
"""
三、变量的作用域【重点掌握】
1.作用域的分类
变量的作用域指的是变量可以使用的范围
程序的变量并不是在任意位置都可以访问,访问权限取决于这个变量是在哪里定义的
变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。
【面试题】Python的作用域一共有4种,分别是
L:Local,局部作用域,特指内部函数
E:Enclosing,函数作用域【内部函数外的函数中】
G:Global,全局作用域
B:Built-in,内建作用域【内置作用域】 num = int("244")
查找方式:以L—>E—>G—>B,在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找
# 访问权限的大小:global > enclosing > local
# 1.不重名
num1 = 10 # 全局作用域:global,可以在当前文件的任意位置访问
def outer1():
num2 = 20 # 函数作用域:enclosing,只能在外部函数中访问
def inner1():
num3 = 30 # 局部作用域:local,只能在内部函数中访问
print(num1,num2,num3)
print(num1,num2)
return inner1
f1 = outer1()
f1()
print(num1)
print("*" * 50)
# 2.重名
# 注意:不同作用域内的变量重名的情况下,访问的时候遵循的是就近原则
num = 10
def outer1():
num = 20
def inner1():
num = 30
print("inner:",num) # 30
print("outer:",num) # 20
return inner1
f1 = outer1()
f1()
print('global:',num) # 10
# 3.
"""
注意:
Python中只有模块(module)、类(class)以及函数(def、lambda)才会引入新的作用域,
其他的代码块,例如if/elif/else、try/except、for/while等是不会引入新的作用域的,
也就是说这些语句内定义的变量,在外部也可以使用
"""
def func():
n = 10
# print(n)
if 1:
m = 19
print(m)
for _ in range(10):
a = 24
print(a)
2.局部变量和全局变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中
# 注意:全局变量和局部变量是一个相对的定义
# 全局变量:可以在当前文件的任意位置被访问
# 局部变量:只能在指定的范围内被访问
# 1.
num1 = 34 # 全局变量
def test1():
num2 = 10 # 局部变量
# 2.
num1 = 23 # 全局变量
def test2():
num2 = 6 # 局部变量【函数作用域】
def inner():
num3 = 10 # 局部变量【局部作用域】
# 3.【面试题】
# a.下面的定义中,两个a表示不同的变量
# 不同作用域内的变量重名的情况下,访问【获取】的时候遵循的是就近原则
a = 15
def check():
a = 88
print(a) # 88
check()
print(a) # 15
print("*" * 50)
# b.
# a = 15
# def check():
# a += 88 # UnboundLocalError: local variable 'a' referenced before assignment
# print(a)
# check()
# print(a)