python成长之路七-函数的进阶

时间:2023-03-08 17:53:10
python成长之路七-函数的进阶

1,python中,名称空间分三种:

  1. 全局命名空间

  2. 局部命名空间(临时命名空间)

  3. 内置名称空间

2,作用域(两种):

   1,全局作用域  包含:全局名称空间   内置名称空间

   2,局部作用域  包含:局部命名空间

  2.1,取值顺序:

    就近原则:局部名称空间 --> 全局名称空间 --> 内置名称空间   单向从小到大范围

  2.2, 加载顺序:

    内置名称空间 --> 全局名称空间(当程序执行时) -- > 局部名称空间(当函数调用的时候)

3,函数的嵌套:

  

def func1():
print(111)
def func2():
print(222)
func1()
print(333)
print(666)
func2()
print(555)

例子1

def func1():
print(222)
def func2():
print(333)
print(111)
func2()
print(666)
func1() # 执行结果:
222 111 333 666

例子2

4,global   nonlocal

  局部名称空间对全局名称空间的变量可以引用,但是不能改变。

count = 1
def func1():
count = 2
print(count)
func1()
count = 1
def func1():
# count = 3
count = count + 1 # local variable 'count' referenced before assignment
print(count)
func1()

报错

报错原因: 如果你在局部名称空间 对一个变量进行修改,那么解释器会认为你的这个变量在局部中已经定义了,但是对于上面的例题,局部中没有定义,所以他会报错,

  global

    1,在局部名称空间声明一个全局变量。

声明

    2,在局部名称空间声明可以对全局变量进行修改。

count = 1
def func1():
global count
count = count + 1
print(count)
func1()
print(count)

修改

  nonlocal

    1,子函数对父函数的变量进行修改。

    2,此变量不能是全局变量

    3,在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从那层及以下此变量全部发生改变。

def func1():
count = 666
def inner():
print(count)
def func2():
nonlocal count
count += 1
print("func2",count)
func2()
print("inner",count)
inner()
print("funcl",count)
func1() # 运行结果:
666
func2 667
inner 667
funcl 667

global

5,函数的应用

  1,函数名就是函数的内存地址。

def func():
pass
print(func) # <function func at 0x05958660>

  2,函数名可以作为变量。

def func1():
print(666)
f1 = func1
f2 = f1
f2()

  3,函数名可以作为函数的参数。

def func():
print(666)
def func1():
func()
def func2(x):
x()
func2(func1)

  4,函数名可以当作函数的返回值。

def wraaper():
def inner():
print("inner")
return inner
ret = wraaper()
ret()

  5,函数名可以当作为容器类类型的元素。

def func1():
print("in func1")
def func2():
print("in func2")
def func3():
print("in func3")
def func4():
print("in func4")
l1 = [func1,func2,func3,func4]
for i in l1:
i()

     向上面的函数名这种,第一个类对象。

6,globals()   locals()

  1,globals()  返回全局变量的一个字典。

  2,locals()   返回当前位置的局部变量的字典。

def funcl():
a = 2
b = 3
# print(globals())
# print(locals())
def inner():
c = 5
d = 6
print(globals())
print(locals())
inner()
print(globals())
print(locals())
funcl()

7,闭包

    --内层函数对外层函数的变量(非全局变量)的引用,并返回。这样就形成了闭包。

  1,迭代器的条件:

      1,必须要有函数嵌套。

      2,内层函数必须要引用外层函数中的变量(不能是全局变量)。

      3,外层函数必须返回内部中的函数名(引用)。
    
def wraaper():
n = 1
def inner():
nonlocal n
n += 1
return n
# inner()
return inner
f = wraaper()
print(f())
print(f())

闭包

  2,闭包的作用:

      当程序执行时,遇到了函数执行,他会在内存开辟一个空间,局部名称空间,

      如果这个函数内部形成了闭包,

      那么他就不会随着函数的结束而消失。

# 1,写装饰器的时候用。
# 2,写爬虫的时候用。 from urllib.request import urlopen def index():
url = "http://www.xiaohua100.cn/index.html"
def get():
return urlopen(url).read()
return get xiaohua = index() # get
content = xiaohua() # get()
content = xiaohua() # get()
print(content.decode('utf-8'))

作用

8,迭代器

  1,可迭代对象

    对象内部含有__iter__方法的就是可迭代对象。

    可迭代对象满足可迭代协议。

  2,判断是否是可迭代对象。

    

dic = {"name":"alex"}
print('__iter__' in dir(dic))

方法一

from collections import Iterable
from collections import Iterator
print(isinstance("alex",Iterable))
print(isinstance('alex',Iterator))
print(isinstance("alex",str))

方法二

  3,可迭代对象 vs 迭代器

    可迭代对象不能取值,迭代器是可以取值的。

    可迭代对象 可以转化成迭代器。

lis = [1,2,3]  # 可迭代对象
itet = lis.__iter__() #迭代器
itet = iter(lis) # 迭代器
print(itet)

    可迭代器如何取值?

      next一次,取值一次

      1,可迭代对象不能取值,迭代器是可以取值的。

      2,迭代器非常节省内存。

      3,迭代器每次只会取一个值。

      4,迭代器是单向的从上至下地取值,一条路走到头。

    1,迭代器原理

      1,将可迭代对象转化成迭代器。

      2,调用__next__方法取值。

      3,利用异常处理停止报错。

s1 = "asdfg"
iter1 = s1.__iter__()
while 1:
try:
print(iter1.__next__())
except StopIteration:
break
s1 = "asdfg"

# l1 = [i for i in range(100)]
# print(11) ret = (i for i in range(10000))
print(ret.__next__())
print(ret.__next__())
print(ret.__next__())

9, 生成器

    --就是自己python用代码写的迭代器,生成器的本质就是迭代器。

  1,构建一个生成器的两种方式:

      1,通过生成器函数。

      2,生成器表达式。

   生成器函数:

def func1(x):
x += 1
return x
func1(5) # 函数的执行命令,并且接受函数的返回值
print(func1(5))

函数

def func1(x):
x += 1
print(111)
print(111)
print(111)
yield x
x += 2
print(222)
yield "alex"
x += 3
g_obj = func1(5) # 生成器函数对象
# print(g_obj)
# print(g_obj.__next__())
print(g_obj.__next__())

生成器函数

    一个 naxt 对应一个 yield

    yield 将值返回给生成器对象 .__next__()

    yield 和 return区别

    return 结束函数,给函数的执行者返回值

    yield  不会结束函数,一个next 对应一个yield,给生成器对.__next__()返回值。

    

    生成器函数 和 迭代器 区别

      1,自定制的区别

# li = [1,2,3,4,5]
# li.__iter__() def func1(x):
x += 1
yield x
x += 3
yield x
x += 5
yield x
g1 = func1(5)
print(g1.__next__())
print(g1.__next__())
print(g1.__next__())

区别1

      2,内存级别的区别

      迭代器是需要可迭代对象进行转化。可迭代对象非常占内存。

      生成器直接创建,不需要转化,从本质就节省内存。

def func1():
for i in range(10000):
yield i g1 = func1()
for i in range(50):
print(g1.__next__()) # ————————————————————————
def func1():
print(1)
count = yield 6
print(count)
print(2)
count1 = yield 7
print(count1)
print(3)
yield 8 g = func1()
next(g)
g.send("alex")
# g.send("太白")
print(g.__next__())

区别二

    

     send   与   naxt   区别

      send与next一样,也是对生成器取值(执行一个yield)的方法。

      send可以给上一个yield传值。

      第一次取值永远都是next。

      最后一个yield永远也得不到send传的值。

# 函数
def cloth1(n):
for i in range(n+1):
print("衣服%s号" % i)
cloth1(1000)
# --------------------------------
# 生成器函数
def cloth1(n):
for i in range(1,n+1):
yield ("衣服%s号" % i)
g = cloth1(1000)
for i in range(50):
print(g.__next__())
# for i in range(50):
# print(g.__next__())

函数 vs 生成器

   列表推导式:

      -- 一行代码几乎搞定你需要的任何的列表。

      优点:一行解决,方便

      缺点:容易着迷,不易排错,不能超过三次循环。

     列表推导式不能解决所有列表问题,所以不要太刻意用。

    循环模式   [变量(加工后的变量)for 变量 initerable]

l = [i for i in range(1,101)]
print(l) l2 = print(["python%s期" % i for i in range(1,11)]) print([i*i for i in range(1,11)])

循环模式

    筛选模式  [变量(加工后的变量)in iterable if 条件]

l3 = [i for i in range(1,31) if i % 2 == 0]
print(l3) print([i for i in range(1,31) if i % 3 == 0]) print([i**2 for i in range(1,31) if i % 3 == 0]) names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
# 请选出名字中带两个e的 print([j for i in names for j in i if j.count("e") == 2])

筛选模式

   生成器表达式: 将列表推导式的 [ ] 换成 ( ) 即可。

g = (i for i in range(100000))
print(g)
print(g.__next__())
print(g.__next__())
for i in range(20): # 循环取取值
print(g.__next__())

生成器表达式

mcase = {"a":10,"b":34}
mcase_frequency = {mcase[k]: k for k in mcase} # 将键值对反转
print(mcase_frequency)

元组表达式

squared = {x**2 for x in [1,-1,2]} # 将集合去重
print(squared)

集合表达式