作用域:变量的访问权限,全局变量所在的位置在全局作用域,局部变量所在的位置仅在局部作用域。
函数内部可以直接访问其外部的变量,但函数外部不能直接访问其内部的变量。如果函数外部需要访问函数内部的变量,需函数内部把相应的变量以return返回出来。
"""
全局作用域与局部作用域
"""
a = 10 # 全局变量 -> 全局作用域
print(a)
def func(): # 全局的一个函数
b = 20 # 局部变量 -> 局部作用域
print(a)
func()
print(b) # 此时不能直接访问变量b
def func3():
func() # 访问全局函数
func3()
"""
函数外部需要访问函数内部的变量
"""
def func():
c = 10
return c
c1 = func()
print(c1)
函数的嵌套
函数相当于一个变量,可以作为返回值进行返回,也可以作为参数进行互相传递。
函数名实际上就是一个变量名, 都表示一个内存地址。
"""
函数可以被其它的函数调用
"""
def func1():
pass
def func2():
func1() # 此时是函数的调用,并非函数嵌套
func2()
"""
函数的嵌套
"""
def func1():
b = 20
def func2(): # 函数的嵌套,相当于局部变量
pass
# func2 = def():
print(b)
func2() # 局部变量一般都是在局部作用域中被访问
print(func1())
"""
嵌套函数的运行顺序
"""
def func1():
print(123) # (1)
def func2():
print(456) # (3)
def func3():
print(789) # (5)
print(1) # (4)
func3()
print(2) # (6)
print(3) # (2)
func2()
print(4) # (7)
func1()
""" 运行结果
123
3
456
1
789
2
4
"""
"""
函数可以作为返回值进行返回,也可以作为参数进行互相传递
"""
def func():
def inner():
print(123)
print(inner)
return inner # 返回的是函数名称, 此时是把一个函数当成一个变量进行返回的
b1 = func() # b1是func的内部inner
print(b1)
b1()
def an():
print(123)
an()
bn = an # 作为参数进行传递
bn()
"""
代理模式
"""
def func(an): # 此时an收到的是一个函数
an() # 执行这个函数
def target():
print("我是target")
func(target) # 实参可以是函数
两个关键字:global与nonlocal
a = 10
def func():
print(a)
# 要在函数内部修改全局的变量a
global a # 用关键字“global”把外面的全局变量引入到局部
a = 20 # 此处可修改全局变量a
func()
print(a)
def func():
a = 10
def func2():
nonlocal a # 向外找一层,如果有对应的变量就引入, 没有就继续向外一层, 直到全局(不包括)
a = 20 # 此处可修改外层局部变量a
func2()
print(a)
func()
闭包函数
闭包函数的本质:内层函数对外层函数的局部变量的使用
闭包函数的作用:
1. 可以让一个变量常驻于内存
2. 可以避免一个变量像全局变量那样被轻易修改
3. 多了一种传参的方式
def func():
a = 10
def inner():
nonlocal a
a += 1
return a
return inner # 函数对象可以被赋值、当做参数、当做容器类型的元素,也可以作返回值
ret = func() # ret就是函数名inner
r1 = ret() # 运行inner函数,获取闭包函数的返回值
print(r1)
两种为函数体传参的方式:
# 方式一:直接把函数体需要的参数定义成形参
def f2(x):
print(x)
f2(1)
# 方式二:以闭包函数的方式传参
def f1(x): # x=3
def f2():
print(x)
return f2
x=f1(3) # 传参
print(x) # f2函数的内存地址
x() # 执行f2函数
两种为函数体传参方式的应用:
import requests
# 传参方式一:
def get(url):
response = requests.get(url)
print(len(response.text), url)
get('https://www.baidu.com/')
get('https://www.csdn.net/')
get('https://www.bilibili.com/')
# 传参方式二:
def outter(url):
def get():
response = requests.get(url)
print(len(response.text), url)
return get
baidu = outter('https://www.baidu.com/')
baidu()
csdn = outter('https://www.csdn.net/')
csdn()
bilibili = outter('https://www.bilibili.com/')
bilibili()
装饰器
装饰器就是一个函数,在不改变原函数的代码以及调用方式的前提下,为原函数增加新的功能,其本质是闭包。
标准装饰器
# 定义装饰器 def wrapper(fn): def inner(*args, **kwargs): # '''添加额外的功能:执行被装饰函数之前的操作''' ret = fn(*args, **kwargs) # '''添加额外的功能:执行被装饰函数之后的操作''' return ret return inner # 使用装饰器 @wrapper def func(): pass
多个装饰器的运行顺序——远先近后,先进后出
def wrapper01(fn):
def inner(*args, **kwargs):
print("wrapper01入口")
ret = fn(*args, **kwargs)
print('wrapper01出口')
return ret
return inner
def wrapper02(fn):
def inner(*args, **kwargs):
print('wrapper02入口')
ret = fn(*args, **kwargs)
print('wrapper02出口')
return ret
return inner
@wrapper01
@wrapper02
def main():
print('main函数')
main()
运行结果:
wrapper01入口 wrapper02入口 main函数 wrapper02出口 wrapper01出口
有参装饰器
# 有参装饰器模板
def outter(x,y,z):
def wrapper(fn):
def inner(*args, **kwargs):
res = fn(*args, **kwargs)
return res
return inner
return wrapper
@outter(1,y=2,z=3)
def func():
pass
迭代器
迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而继续的,并非单纯的重复。
可迭代对象与迭代器对象
1、可迭代对象(可以转换成迭代器的对象):内置有方法__iter__()对象
可迭代对象.iter(): 得到迭代器对象
2、迭代器对象:内置有方法__next__()和方法__iter__()的对象
迭代器对象.next():得到迭代器的下一个值
迭代器对象.iter():得到迭代器的本身,调了与没调都是一样的
可迭代对象:字符串、列表、元组、字典、集合、文件对象
迭代器对象:文件对象
lst = ['Java', 'Python', 'C/C++', 'PHP'] # 获取迭代器对象 iterator = iter(lst) # 方式一 iterator = lst.__iter__() # 方式二 # 从迭代器中取值 # 一次取一项值,取值完成后再进行取值则抛出异常StopIteration print(next(iterator)) # 方式一 print(iterator.__next__()) # 方式二
迭代器实现for循环:
lst = ['Java', 'Python', 'C/C++', 'PHP']
# for循环遍历列表
for item in lst:
print(item)
# 迭代器遍历列表
iterator = iter(lst)
while True:
try:
print(next(iterator))
except StopIteration:
break
# 等价于
iter_ = lst.__iter__()
while True:
try:
print(iter_.__next__())
except StopIteration:
break
迭代器优缺点
1、优点:
I、为序列和非序列类型提供了一种统一的迭代取值方式。
II、惰性计算:迭代器对象表示的是一个数据流,可以只在需要时才去调用方法next()来计算出一个值,就迭代器本身来说,同一时刻在内存中只有一个值,因而可以存放无限大的数据流,而对于其他容器类型,如列表,需要把所有的元素都存放于内存中,受内存大小的限制,可以存放的值的个数是有限的。
2、缺点:
I、除非取尽,否则无法获取迭代器的长度
II、只能取下一个值,不能回到开始,更像是‘一次性的’,迭代器产生后的唯一目标就是重复执行方法next()直到值取尽,否则就会停留在某个位置,等待下一次调用方法next();若是要再次迭代同个对象,只能重新调用方法iter()去创建一个新的迭代器对象,如果有两个或者多个循环使用同一个迭代器,必然只会有一个循环能取到值。
在函数内一旦存在yield关键字,调用函数并不会执行函数体代码,而会返回一个生成器对象,生成器即自定义的迭代器。
生成器对象调用方法__next__()时会触发函数体代码的运行,然后遇到yield停下来,并将yield后的值当做本次调用的结果返回。
关键字yield可以用于返回值,但不同于return,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数,用来返回多次值。
def my_range(start,stop,step=1):
# print('start...')
while start < stop:
yield start
start+=step
g=my_range(1,5,2) # 1 3
print(next(g))
print(next(g))
print(next(g))
for n in my_range(1,7,2):
print(n)
推导式
# 列表推导式
lst = [x for x in range(10) if x % 2 == 1]
print(lst) # [1, 3, 5, 7, 9]
# 字典推导式
lst = ['Java', 'Python', 'C/C++', 'PHP']
dic = {i: lst[i] for i in range(len(lst))}
print(dic) # {0: 'Java', 1: 'Python', 2: 'C/C++', 3: 'PHP'}
# 生成器表达式
iter_ = (x for x in range(1, 10, 3))
print(iter_) # 生成器对象
print(iter_.__next__())
print(iter_.__next__())
print(iter_.__next__())
匿名函数
func = lambda x, y: x + y # 等价于 def func(x, y): return x + y print(func(2, 3)) func = lambda x, y: x if x > y else y # 等价于 def func(x, y): if x > y: return x return y print(func(2, 3))



