函数内容回顾
一、函数:对功能或者动作的封装 (function)
定义:
def 函数名(形参列表):
函数体(return)
调用:
函数名(实参列表)
形参:在函数声明的位置写的变量
1、位置参数
2、默认值参数
3、动态传参
1、*args 位置参数的动态参数,接受的是元组
2、**kwargs 关键字的动态传参,接受的是字典
*和**在形参中是聚合 在实参中是打散
实参:在函数调用的时候给的值
1、位置参数
2、关键字参数
3、混合参数
传参:把实参传递给形参的过程
返回值 :
1、不写return 或者只写return
2、return 值 返回一个值
3、return val1,val2, val3 ....返回多个值,元组类型
名称空间:
1、内置名称空间
---Python解释器的内置的东西
2、全局名称空间
---全局变量,全局函数
3、局部名称空间
---局部变量、在函数内部
作用域:
1、全局作用域 (内置+全局)
2、局部作用域 (局部)
globals() 查看全部作用域中的内容
locals() 查看当前作用域的内容
global 把全局变量引入函数中
nonlocal 在局部中的函数,引入离他最近的局部变量
函数调用 、 函数嵌套
二、闭包
--def outer():
a = 10 ## 常驻内存
def inner():
print(a) ## 在内部使用的外面的变量
return inner ## 返回了内部函数的内存地址
fn = outer()
fn()
## 这种结构叫做闭包
作用:1、可以保护我的变量
2、可以让一个变量常驻内存 (相当于 全局变量)
## 判断是否为闭包
fn.__closure__ ## 有返回的就是东西,返回的是None则不是闭包
## 闭包的作用:保护变量、常驻内存
三、迭代器(iterator)
回顾 : 可迭代对象 (str、list、dict、tuple、set、open()、range()), int 不能迭代,那么什么是可迭代对象?
dir() 可以查看某数据类型中可以执行的方法
s = "alex"
print(dir(s))#在字符串中发现了__iter__.没有__next__
a = 123
print(dir(a))#在int中没有__iter__,没有__next__
总结:
str、list、dict、tuple、set、open()、range()中都有__iter__ , int没有__iter__
## 在数据类型中可以认为有__iter__ 是可迭代的
## 所有包含了__iter__的东西都可以使用for 循环进行迭代
## 迭代器、在for 循环内部, 调用了__iter__(), 访问__iter__()可以得到迭代器
1 lst = [1, 2, 3, 4, 5] 2 it = lst._iter__() ##iterator 迭代器 3 while 1: 4 try: 5 it.__next__() 6 except: 7 print("结束了") 8 9 ##此代码等于 for in 执行
四、概括总结
函数名(第一类对象):
1、函数名可以当做变量使用
2、函数名可以作为集合类的函数
3、函数名可以作为参数传递
4、函数名可以作为返回值返回(闭包)
__name__ 查看函数的名字
__doc__ 查看函数的注释
闭包:
内部函数对外部函数中的变量的调用
用法:
def outer():
a = 10
def inner():
print(a)
return inner
好处:
保护变量、常驻内存
迭代器:
dir() 查看数据可以执行的方法
(iterable) : 在数据内部存在__iter__() 可以被迭代的内容
(iterator) : 迭代器,存在__iter__(),__next__()
还可以引入collections中的Iterable和Iterator
from collections import Iterable
isinstance(对象,类型) 可以判断xxx对象是否xxx类型
特征:
1、节省内存
2、惰性机制(只有执行__next__才会取值)
3、只能向前
for 循环内部使用的是迭代器
五、生成器(本质上是迭代器的一种)
def func():
print("123")
yield "456" // 有yield 就是 生成器
f1 = func()
ret = f1.__next__() // 执行遇到yield就是打印出来 123,465
ret = f1.__next__() // 执行没遇到就会报错,StopIteration....
// send() 用法
def func():
print("123")
a = yield "456" // 有yield 就是 生成器
print("147",a)
f1 = func()
ret = f1.__next__() // 第一个必须用__next__
ret = f1.send("大哈") // 给上一个yield 传递值
// send() 和 __next__()区别
## send() 不可以用开头
## send() 可以给上一个yield 传递值,不能给最后一个yield传值
// 生成器本质是迭代器
def func():
print("123")
a = yield "456" // 有yield 就是 生成器
print("147",a)
f1 = func()
print("__iter__" in dir(f1)) // 判断是否存在iter,返回True则表示是生成器
// 推导式
lst = [] # 创建列表
for i in range(1,17): # 循环1-16
lst.append("python%s"%i) # 装数据
print(lst)
--->>>列表推导式:
lst = ["python%s "%i ifor i in range(1,17)]
语法:
[结果 for _ in range() if 判断]
练习:
## 获取1-100内能被3整除的数
lst = [i for i in range(1,101) if i % 3 == 0]
## 100以内能被3整除的数的平方
lst = [ i**2 for i in range(1,101) if i % 3 == 0]
## 寻找名字中带有两个e的人的名字
names = [['Toal','Billy','Jefferson','Andrew','Wesley','Steven','Joe'],
['Alice','Jill','Ana','Weniy','Jemifer','Shery','Eva']]
lst = [name for first in names for name in first if name.count("e") >= 2]
print(lst)
--->>> 字典推导式:
dic = {"张无忌":"九阳神功","乔峰":"降龙十八掌","楚留香":"香"}
d = {dic[k]:k for k in dic}
print(d)
语法:
{key:vale for 循环 if 判断}
练习:
lst1=['东北','陕西','山西','开封','杭州','广东','济南']
lst2=['大推皮','油泼面','老陈','灌汤包','西制埋鱼','早茶','胶东一锅鲜']
dic = {lst1[i]:lst2[i] for i in range(len(lst1))}
print(dic)
--->>> 集合推导式:
lst = ['周杰伦','周星驰','周润发','周星驰','周笔畅','周星驰','周伯通','周星驰']
s = {el for el in lst}
语法:
{key for if }
--->>> 生成器表达式:
gen = (i for i in range(10)) ## generator
print(gen.__next__())
## 元组没有推导式i
## (结果 for if ) ## 这不是元组推导式,这拿到的是生成器
## 可以直接使用生成器表达式创建生成器
## 生成器表达式和列表推导式区别
## 列表推导式:一次性把所有的数据创建出来,容易产生内存浪费
## 生成器表达式: 记录一次代码,然后每次需要的时候去生成器中执行这个代码
## 特性:
1、 节省内存
2、 惰性机制
3、 只能向前
练习:(难点)
1、def func():
print(111)
yield 222
g = func() ## 生成器
g1 = (i for i in g) ## 生成器
g2 = (i for i in g1) ## 生成器
print(list(g)) ## 才会开始真正的取数据 111, [222]
print(list(g1)) ## []
print(list(g2)) ## []
2、def add(a, b):
return a + b
def test():
for r_i in range(4):
yield r_i
g = test()
for n in [2, 10]:
g = (add(n, i) for i in g)
print(list(g))
// 看最后一个数乘以循环次数加上g ,就是最后的结果
// 生成器记录内存中的代码