Python函数

函数

函数
(1)函数的含义:
功能 (包裹一部分代码 实现某一个功能 达成某一个目的)
(2)函数特点:
可以反复调用,提高代码的复用性,提高开发效率,便于维护管理
(3)函数基本格式
# 函数的定义
def func():
	code1....
	code2....

# 函数的调用
func()
(4)函数命名
"""
		  函数的命名
字母数字下划线,首字符不能位数字
严格区分大小且,且不能使用关键字
函数命名有意义,且不能使用中文

驼峰命名法:
(1)大驼峰命名法:每个单词的首字符大写 (一般在类中起名用这样的方式, 推荐)
	mycar => MyCar  
(2)小驼峰命名法:除了第一个单词首字符不用大写之外,剩下首字符都大写 				(函数中的命名)
	mycar => myCar 
"""
函数参数 : 函数运算时需要的值
(1)函数参数概念及分类
  函数参数:调用时需要传递的数据.
  函数参数大类分为形参和实参:
      形参意思: 函数定义时的参数
      实参意思: 函数调用时的参数
  形实关系:函数调用时,形参和实参个数需要一一对应
  形参种类: 普通参数(位置参数),默认参数,普通收集参数,命名关键字参数,关键字收集参数
  实参种类: 普通实参,关键字实参
# 1.普通参数
"""
函数的定义处,普通形参
"""
def small_start(hang,lie):
    i = 0
    while i<hang:
        j = 0
        while j<lie:
            # 打印星星
            print("*",end="")
            j+=1
        # 打印换行
        print()
        i+=1
# 函数的调用出为实参
small_start(3,8)

# 2. 默认形参 hang,lie 在函数定义处给与默认值
"""
    如果给与实参,那么就使用实际参数,
    如果没给实参,那么就使用参数的默认值
"""
def small_start(hang=10,lie=10):
    i = 0
    while i<hang:
        j = 0
        while j<lie:
            # 打印星星
            print("*",end="")
            j+=1
        # 打印换行
        print()
        i+=1

# 3. 普通形参 + 默认形参 
"""默认形参必须写在普通形参的后面,语法上有要求"""
# 函数的定义处
def small_start(hang,lie=10):
# def small_start(hang,lie=10):
    i = 0
    while i<hang:
        j = 0
        while j<lie:
            # 打印星星
            print("*",end="")
            j+=1
        # 打印换行
        print()
        i+=1

# (4) 关键字实参
"""
(1)如果使用关键字实参进行函数调用,实参的顺序无所谓
(2)如果定义时是普通形参,调用时是关键字实参,
那么这个参数后面的所有调用方式都需要关键字实参进行调用
"""
def small_start(hang,a,b,c,lie=10):
# def small_start(hang,lie=10):
    i = 0
    while i<hang:
        j = 0
        while j<lie:
            # 打印星星
            print("*",end="")
            j+=1
        # 打印换行
        print()
        i+=1
# 关键字实参 hang  和 lie 
small_start(lie = 12,hang = 12)

        
函数参数
(2)收集参数:
普通收集参数:专门用于收集多余的普通实参,形成一个新的元组
语法:参数前面加* 例:*args(arguments)
# 计算任意长度的累加和
def my_sum(*args):
    total = 0
    for i in args:
        total += i
    print(total)
my_sum(1,2,3,4,5)
    关键字收集参数:专门用于收集多余的关键字实参,形成一个新的字典
语法:参数前面加** 例:**kwargs(keword arguments)
# 拼接任意字符串
def func(**kwargs):
    strvara = ""
    strvarb = ""
    dictvar = {"stra":"1","strb":"2"}
    for k,v in kwargs.items():
        if k in dictvar:
            strvara += dictvar[k] + ":" + v + "\n"
        else:
            strvarb += v + " "
    print(strvara)
    print(strvarb)

func(stra="A",strb="B",strc="C")
(3)命名关键字参数:定义时放在*号后面的参数,调用时强制必须指定关键字实参才能调
语法:(*,x) x是命名关键字参数
# 命名关键字参数
# 方法一
def func(a,b,*,c,d):
    print(a,b)
    print(c,d)
func(1,2,c=3,d=4)
# 方法二
def func(*args,c,**kwargs):
    print(args)
    print(c)
    print(kwargs)
func(1,2,3,4,a=1,b=2,c=3)
# 方法三
def func(a,b,*,c=3):
    print(a,b)
    print(c)
func(1,2,c=33)
# 区别于默认形参
def func(a,b,c=3):
    print(a,b)
    print(c)
func(1,2)
func(1,2,c=33)
func(1,2,33) # 关键字参数只能传关键字 
(4)*和**的魔术用法:打包和解包 
  *和**,在函数的定义处,负责打包(把实参都收集过来,放在元组或字典中)
  *和**,在函数的调用处,负责解包(把容器类型的数据,一个一个拿出来,进行传递)
# *
def func(a,b,c):
    print(a,b,c)
listvar = [1,2,3]
func(*listvar)

# **
def func(a,*,b,c,d):
    print(a)
    print(b,c,d)
dictvar = {"b":2,"c":3,"d":4}
func(1,**dictvar)
"""
在字典的前面加上一个*号,默认只传递健
"""
def func(a,b):
    print(a,b)
dictvar = {"a":1,"b":2}
func(*dictvar)

# *字符串
def func(a,b):
    print(a,b)
strvar = "12"
func(*strvar)
(5)形参声明的位置顺序:
普通参数 -> 默认参数 -> 收集参数 -> 命名关键字参数 -> 关键字收集参数

(6)对于任意函数,都可以通过 def func(*args, **kw) 来获取所有参数

return

return返回值
为这个函数返回一个结果 (return返回值可有可无 按照需求选择)
注意:执行return语句之后,函数执行结束
"""
return 自定义返回值,如果没有写return ,默认返回None
功能:把值返回到函数的调用处;
(1)return 后面可以返回值 是自定义的. 除了6大标准数据类型之外,还有类 对象 函数 
(2)如果执行了return 语句,意味着函数终止,后面的代码不执行
"""
# (1) return 后面可以返回值 是自定义的. 除了6大标准数据类型之外,还有类 对象 函数 
def func():
	# return 1
	# return 3.14
	# return 3+4j
	# return True
	# return [1,2,3]
	# return {"a":1,"b":2}
	pass
res = func() # res ={"a":1,"b":2}
print(res)

# (2) 如果执行了return 语句,意味着函数终止,后面的代码不执行
def func():
    print(1)
    return 
    print(2)
res = func()
print(res)

def func():
    for i in range(5):
        if i == 3:
            return i 
        print(i)
res = func()


# (3) 计算器示例
def calc(sign, num1, num2):
    if sign == "+":
        res = num1 + num2
    elif sign == "-":
        res = num1 - num2
    elif sign == "*":
        res = num1 * num2
    elif sign == "/":
        if num2 == 0:
            return "除数不能为零"
        res = num1 / num2
    return res

res = calc("+", 1, 1)
res = calc("-", -1, 90)
res = calc("*", 52, 10)
res = calc("/", 52, 10)
res = calc("/", 5200, 10)
print(res)

doc

__doc__或者help查看文档
# __doc__
help(print)
res = print.__doc__
print(res)

# 自定义函数文档
def defined_word():
    """
    功能:自定义函数文档
    参数:
    :return: None
    """
    print("自定义函数文档")
# 方法一
res = defined_word.__doc__
print(res)

# 方法二
help(defined_word)

内置函数

abs    绝对值函数
>>> res = abs(-90.7)
>>> res
90.7
>>>
round  四舍五入 (n.5 n为偶数则舍去 n.5 n为奇数,则进一!)
>>> print(round(2.5))
2
>>> print(round(3.5))
4
>>>
sum    计算一个序列得和
>>> tuplevar = (1,2,3,4,5)
>>> print(sum(tuplevar))
15
>>>
max    获取一个序列里边的最大值
min   获取一个序列里边的最小值
>>> listvar = [11,88,66,33,77]
>>> print(max(listvar))
88
>>> print(min(listvar))
11
>>> listvara = sorted(listvar)
>>> listvara
[11, 33, 66, 77, 88]
>>> # 最大值
...
>>> print(listvara[-1])
88
>>> # 最小值
...
>>> print(listvara[0])
11
>>>
>>> # 获取一个序列里面的最小值,key=自定义函数
...
>>> listvar = [("a",88),("b",66),("c",99)]
>>> def func(n):
...   return n[1] % 10
...
>>> res = min(listvar,key=func)
>>> print(res)
('b', 66)
>>>
pow    计算某个数值的x次方
>>> # 第三个参数时可选项,如果存在,前两个平方后和第三个取余
...
>>> print(pow(2,3))
8
>>> print(pow(2,3,3))
2
>>>
range  产生指定范围数据的可迭代对象
>>> for i in range(9,0,-2):
...   print(i)
...
9
7
5
3
1
>>>
bin    将10进制数据转化为二进制
oct   将10进制数据转化为八进制
hex   将10进制数据转化为16进制
>>> print(bin(6))
0b110
>>> print(oct(9))
0o11
>>> print(hex(16))
0x10
>>>
chr    将ASCII编码转换为字符
ord   将字符转换为ASCII编码
>>> print(chr(97))
a
>>> print(ord("A"))
65
>>>
eval   将字符串当作python代码执行
exec   将字符串当作python代码执行(功能更强大)
>>> strvar = "print(123)"
>>> res = eval(strvar)
123
>>> print(res) # 返回值没有意义
None
>>>
>>> strvar = 'course = "python"'
>>> res = eval(strvar) # 声明变量,eval不允许
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    course = "python"
           ^
SyntaxError: invalid syntax
>>>
>>> strvar = 'course = "python"'
>>> res = exec(strvar)
>>> print(course)
python
>>> print(res)
None
>>>
>>> strvar = """
... for i in range(5):
...   print(i)
... """
>>> exec(strvar)
0
1
2
3
4
>>>
repr   不转义字符输出字符串
>>> strvar = "D:\note"
>>> print(strvar)
D:
ote
>>> print(repr(strvar))
'D:\note'
>>>
input  接受输入字符串
>>> res = input("Please input username>>>")
Please input username>>>admin
>>>
hash   生成哈希值
>>> strvara = "password"
>>> strvarb = "password"
>>> print(hash(strvara))
-8671913786014747281
>>> print(hash(strvarb))
-8671913786014747281
>>>

参数练习

def f1(a, b, c=0, *args, **kw):
  print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
  print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

以上两个函数 打印结果
#(一)
f1(1, 2)
f1(1, 2, c=3)
f1(1, 2, 3, 'a', 'b')
f1(1, 2, 3, 'a', 'b', x=99)
f2(1, 2, d=99, ext=None)
#(二)
args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
f1(*args, **kw)

#(三)
myargs = (1, 2, 3)
mykw = {'d': 88, 'x': '#'}
f2(*myargs, **mykw)

#(四)
def f1(a, b, c=0, *args,d,**kw):
  print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
  print(d)

f1(1,2,3, 'a', 'b',d=67, x=99,y=77)
>>> def f1(a,b,c=0,*args,**kw):
...   print('a=',a,'b=',b,'c=',c,'args=',args,'kw=',kw)
...
>>> def f2(a,b,c=0,*,d,**kw):
...   print('a=',a,'b=',b,'c=',c,'d=',d,'kw=',kw)
...
>>> f1(1,2,c=3)
a= 1 b= 2 c= 3 args= () kw= {}
>>> f1(1,2,3,'a','b')
a= 1 b= 2 c= 3 args= ('a', 'b') kw= {}
>>> f1(1,2,3,'a','b',x=99)
a= 1 b= 2 c= 3 args= ('a', 'b') kw= {'x': 99}
>>> f2(1,2,d=99,ext=None)
a= 1 b= 2 c= 0 d= 99 kw= {'ext': None}
>>> args=(1,2,3,4)
>>> kw={'d':99,'x':'#'}
>>> f1(*args,**kw)
a= 1 b= 2 c= 3 args= (4,) kw= {'d': 99, 'x': '#'}
>>> myargs=(1,2,3)
>>> mykw={'d':88,'x':'#'}
>>> f2(*myargs,**mykw)
a= 1 b= 2 c= 3 d= 88 kw= {'x': '#'}
>>> def f1(a,b,c=0,*args,d,**kw):
...   print('a=',a,'b=',b,'c=',c,'args=',args,'kw=',kw)
...   print(d)
...
>>> f1(1,2,3,'a','b',d=67,x=99,y=77)
a= 1 b= 2 c= 3 args= ('a', 'b') kw= {'x': 99, 'y': 77}
67

函数名的使用

python中的函数可以像变量一样,动态创建,销毁,当参数传递,作为值返回,叫第一类对象.其他语言功能有限
1.函数名是个特殊的变量,可以当做变量赋值
2.函数名可以作为容器类型数据的元素
3.函数名可以作为函数的参数
4.函数名可作为函数的返回值
>>> # 1.函数名是个特殊的变量,可以当做变量赋值
... def func():
...     print("函数名可以当成变量赋值")
...
>>> abc = 45
>>> abc = func
>>> print(abc)
<function func at 0x00000209F87256A8>
>>> abc()
函数名可以当成变量赋值
>>>
>>># 2.函数名可以作为容器类型数据的元素
>>> def func1():
...   print(1)
...
>>> def func2():
...   print(2)
...
>>> listvar = [func1,func2]
>>> print(listvar)
[<function func1 at 0x00000209F87257B8>, <function func2 at 0x00000209F8725730>]
>>> for i in listvar:
...   i()
...
1
2
>>>
>>> # 3.函数名可以作为函数的参数
...
>>> def func1(func):
...   func()
...
>>> def func2():
...   print('func2')
...
>>> func1(func2)
func2
>>>
>>> # 4.函数名可以作为函数的返回值
...
>>> def func1(func):
...   return func
...
>>> def func2():
...   print('func2')
...
>>> res = func1(func2)
>>> print(res)
<function func2 at 0x00000209F8725840>
>>> res()
func2
>>>
__doc__或者help查看文档

命名空间

作用域:作用范围
命名空间 : 划分一块区域保存所有数据,以字典的方式存储(变量与值形成映射关系).一共三种.
(1)内建命名空间:解释器启动时创建,直到解释器运行结束,生存周期最长
(2)全局命名空间:文件运行时创建,直到解释器运行结束,生存周期较长
(3)局部命名空间:函数调用时,里面的局部变量才创建,调用结束后即释放,生存周期较短
命名空间的提出是为了划分和控制变量是否可见,以及生存周期的长短.

命名空间 创建顺序:(了解)
python解释器启动->创建内建命名空间->创建全局命名空间->创建局部命名空间
命名空间 销毁顺序:(了解)
函数调用结束后->销毁函数对应的局部命名空间数据->销毁全局命名空间数据->销毁内建命名空间数据

全局变量 与 局部变量 及 其关键字的使用

局部变量:函数内部的变量是局部变量,作用域仅在函数内部可见(局部命名空间)
全局变量:函数外部的变量是全局变量,作用域横跨整个文件(全局命名空间)
# 局部变量的获取 与 修改
def func():
	a = 15
	# 获取局部变量
	print(a)
	# 修改局部变量
	a = 17
	print(a)
func()
# print(a) error  a局部变量值限定在函数内部使用;

# 全局变量的获取 与 修改
b = 100
# 获取全局变量
print(b)
# 修改全局变量
b += 200
print(b)
内置函数:内建命名空间

global   :关键字:声明全局变量获修改全局变量
# 在函数内部可以直接获取全局变量,但是不能直接修改
# 用global关键字,修改全局变量
c = 50
def func():
	global c
	print(c)
	c = 60
	print(c)
func()
print(c)


# 在函数内部可以直接定义一个全局变量
def func():
	global d
	d = 90
func()
print(d)
nonlocal  :关键字:修改局部变量(当前函数上一层的局部变量)
# (1) nonlocal 只能用来修改局部变量
a = 90
def func():
	# nonlocal a  error
	a = 80
	print(a)
func()

# (2) nonlocal 会不停的寻找上一层空间所对应的值,拿来修改
"""通过LEGB原则,可以获取到上一层空间的值,只能单纯的获取,不能直接修改
如果想要修改 通过nonlocal 加以修饰.
"""
def outer():
	a = 20
	def inner():
		nonlocal a
		print(a)
		a += 1
		print(a)
	inner()
outer()

# (3) 如果上一层找不到,继续向上寻找,再也找不到了,直接报错; nonlocal 只能修饰局部变量
a = 100

def outer():
	a = 100
	def inner():
		# a = 110
		def smaller():
			nonlocal a
			a += 10
			# print(a)
		smaller()
		print(a,"<=1=>")
	inner()
	print(a,"<=2=>")
outer()


# (4) 不通过nonlocal 是否可以改变局部变量? 可以! 需要使用列表进行操作;
def outer():
	lst = [100,101,102]
	def inner():
		lst[0] += 1
	inner()
	print(lst)
outer()
locals()  :返回字典,获取当前作用域的所有内容
  如果在函数里:获取locals()调用之前,该作用域出现的内容
  如果在函数外:获取locals()打印返回值之前,该作用域出现的内容
# 当前作用域在全局范围
a = 1
b = 2
res = locals()
c = 3
print(res)
# 当前作用域在局部范围
zz = 90
def func():
	d = 4
	f = 5
	res = locals()
	g = 6
	print(res)

func()
globals() :返回字典,获取全局作用域的所有内容
  如果在函数里: 获取globals()调用之前,全局作用域出现的内容
  如果在函数外: 获取globals()打印返回值之前,全局作用域出现的内容
"""
globals 无论在函数内外,都只获取全局作用域当中的所有内容
如果globals在函数外:所获取的是globals(),打印返回值之前的所有内容
如果globals在函数内:所获取的是globals(),调用之前所有内容
"""
# 当前作用域在全局范围
a = 1
b = 2
res = globals()
c  = 3
print(res)

# 当前作用域在局部范围
aa = 11
bb = 22
def func():
    d =1
    f = 2
    res = globals()
    z = 3
    print(res)
cc = 33
func() #res = globals()
dd = 4

# globals 动态的创建全局变量
"""
globals() 返回的是系统的字典,只需要在字典里面添加键值对,就可以创建全局变量
字典中的键 就是变量名
字典中的值 就是变量所指代的值
"""
dic = globals()
print(dic)
dic["strvar"] = "abc"
print(strvar)

# 创建p1~p5 5个全局变量
def func():
    dic = globals()
    for i in range(1,6):
        # p1 ~ p5 5个键
        dic["p%d" % (i)] = i
func()
print(p1)
print(p2)
print(p3)
print(p4)
print(p5)
globals 

LEGB原则(即就近原则找变量)

找寻变量的调用顺序采用LEGB原则(即就近原则)
B —— Builtin(Python);Python内置模块的命名空间     (内建作用域)
G —— Global(module); 函数外部所在的命名空间       (全局作用域)
E —— Enclosing function locals;外部嵌套函数的作用域(嵌套作用域)
L —— Local(function);当前函数内的作用域           (局部作用域)
依据就近原则,从下往上 从里向外 依次寻找

内部函数

(1)内部函数可以直接在函数外部调用么
(2)调用外部函数后,内部函数可以在函数外部调用吗
(3)内部函数可以在函数内部调用吗
(4)内部函数在函数内部调用时,是否有先后顺序
>>> # 函数的嵌套
...
>>> def outer():
...   def inner():
...     def smaller():
...       print(id)
...       print('small func')
...     smaller()
...   inner()
...
>>> outer()
<built-in function id>
small func
>>>

闭包

获取闭包函数使用的变量  __closure__ , cell_contents

闭包的定义:
内函数使用外函数的局部变量,并且外函数将内函数返回出来的方法叫闭包,
返回的内函数叫 闭包函数.

闭包的特点:
  内函数使用了外函数的局部变量,外函数的局部变量与内函数发生绑定,延长该变量的生命周期
  (实际内存给它存储了这个值,暂时不释放)
"""
内函数使用了外函数的局部变量,外函数的局部变量与内函数发生绑定,延长了该变量的生命周期
"""
def outer(val):
	def inner(num):
		return num +  val
	return inner

func = outer(10)
res = func(5) # func = inner() = num + val = 10 + 5 = 15
print(res)

闭包的意义:
闭包可以优先使用外函数中的变量,并对闭包中的值起到了封装保护的作用.外部无法访问.
"""
闭包可以优先使用外函数中的变量,并对闭包中的值起到了封装保护的作用.外部无法访问.
模拟一个鼠标点击计数功能:
"""
clicknum = 0
def clickfunc():
	global clicknum
	clicknum += 1
	print(clicknum)

# 模拟点击操作,点击一次就调用一次
clickfunc()
clickfunc()
clickfunc()
clickfunc()
clickfunc()
clicknum = 100
clickfunc()

# 用闭包函数来进行改造
def clickfunc():
	x = 0
	def func():
		nonlocal x
		x +=1 
		print(x)
	return func
clickfunc2 = clickfunc()
clickfunc2() # clickfunc2() = func()
clickfunc2() 
clickfunc2() 
clickfunc2() 
clickfunc2() 
x = 100
clickfunc2() 

匿名函数

lambda 表达式:用一句话来表达只有返回值的函数
   好处:简洁,方便,定义函数快速简单
   语法:lambda 参数 : 返回值
>>> # 1.无参数的lambda表达式
...
>>> def func():
...   return 123
...
>>> res = func()
>>> print(res)
123
>>> func = lambda:123
>>> res = func()
>>> print(res)
123
>>>
>>> # 2.有参数的lambda表达式
...
>>> def  func(n):
...   return type(n)
...
>>> res = func('123')
>>> print(res)
<class 'str'>
>>> func = lambda n : type(n)
>>> res = func('123')
>>> print(res)
<class 'str'>
>>>
>>> # 3.带有条件判断的lambda表达式
"""
三元运算:
  真值 if 条件表达式 else 假值
	如果条件表达式成立,执行真值
	如果条件表达式不成立,执行假值
"""
>>> def func(n):
...   if n % 2 == 0:
...     return "偶数"
...   else:
...     return "奇数"
...
>>> func(11)
>>> n = 11
>>> func = "偶数" if n % 2 == 0 else "奇数"
>>> func
'奇数'
>>>
>>> # 计算参数中的最大值
...
>>> def func(m,n):
...   if m > n:
...     return m
...   else:
...     return n
...
>>> print(func(11,33))
33
>>> func = lambda m,n : m if m > n else n
>>> print(func(11,33))
33
>>>

递归函数

递归函数:自己调用自己的函数 (递:去 归:回 一去一回是递归)
  (1)每调用一次函数,就是开辟一个栈帧空间的过程
每结束一次函数,就是释放一个栈帧空间的过程
递归函数就是不停的开辟栈帧空间和释放栈帧空间的过程

(2)回的过程有两种触发时机:
(1)当最后一层函数全部执行完毕,触发回的过程,回到上一层函数调用处
(2)当遇到return 返回值的时候,触发回的过程,回到上一层函数调用处
>>> def recursion(n):
...   print("session01>>>",n)
...   if n > 0:
...     recursion(n-1)
...   print("session02>>>",n)
...
>>> recursion(5)
session01>>> 5
session01>>> 4
session01>>> 3
session01>>> 2
session01>>> 1
session01>>> 0
session02>>> 0
session02>>> 1
session02>>> 2
session02>>> 3
session02>>> 4
session02>>> 5
>>>
>>> # 计算n的阶乘
...
>>> def factorial(n):
...   if n <= 1:
...     return 1
...   return n * factorial(n-1)
...
>>> res = factorial(5)
>>> print(res)
120
>>> 

如果我们计算fact(5),可以根据函数定义看到计算过程如下:

===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120

内存栈区堆区(了解内容)

单独讲栈堆是数据结构
  栈:后进先出的一种数据结构
  堆:排序后的一种树状数据结构
   
栈区堆区是内存空间
  栈区:按照后进先出的数据结构(栈),无论创建或销毁都是自动为数据分配内存,释放内存
(系统自动做的)
  堆区:按照排序后的树状数据结构(堆),可优先取出必要数据,无论创建或销毁都是手动分配内存,释放内存(程序员手动做的)
  --内存中的栈区 : 自动分配 自动释放
  --内存中的堆区 : 手动分配 手动释放

运行程序时在内存中执行,会因为数据类型的不同而在内存的不同区域运行
因不同语言对内存划分的机制不一,但大体来讲,有如下四大区域

--栈区: 分配局部变量空间.
--堆区: 是用于手动分配程序员申请的内存空间.
--静态区(全局栈区): 分配静态变量,全局变量空间.
--代码区(只读区,常量区): 分配常量和程序代码空间的.

栈区 堆区 静态区 代码区 都是内存中的一段空间

迭代器

迭代器:能被next()函数调用并不断返回下一个值的对象称为迭代器(Iterator  迭代器是对象)
特征:迭代器会生成惰性序列,它通过计算把值依次的返回,一边循环一边计算而不是一次性得到所有数据
优点:需要数据的时候,一次取一个,可以大大节省内存空间.而不是一股脑的把所有数据放进内存.

--Iterable可迭代的 Iterator迭代器
惰性序列:没有一次性的把所有数据都放在序列中,而是遍历一个放一个,这样的序列

1.可迭代对象。

  如果一个数据类型其中的成员包含了__iter__方法,这个数据类型就是可迭代对象

  dir 这个函数可以获取该数据类型的成员结构

>>> setvar ={1,2,'a','b'}
>>> setvar
{1, 2, 'b', 'a'}
>>> for i in setvar:
...   print(i)
...
1
2
b
a
>>> res = dir(setvar)
>>> res
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__init_subclass__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']
>>>
2.迭代器
  for循环在迭代数据的时候,内部先转化为迭代器,然后通过next方法来进行调用
  变成迭代器:
    (1)iter (2)__iter__()
>>> setvar ={1,2,'a','b'}
>>> res = iter(setvar)
>>> res
<set_iterator object at 0x00000135A70DB8B8>
>>> ret = setvar.__iter__()
>>> ret
<set_iterator object at 0x00000135A70DB900>
>>>
  遍历迭代器
    (1)next (2)__next__()
>>> setvar ={1,2,'a','b'}
>>> res = iter(setvar)
>>> ret = next(res)
>>> ret
1
>>> ret = next(res)
>>> ret
2
>>> ret = next(res)
>>> ret
'b'
判断可迭代对象
>>> setvar ={1,2,'a','b'}
>>> res = iter(setvar)
>>> print("__iter__" in dir(setvar))
True
>>> 
判断迭代器
    (1)含有__iter__和__next__两个方法,该数据类型就是迭代器
>>> setvar ={1,2,'a','b'}
>>> res = iter(setvar)
>>> print("__iter__" in dir(res) and "__next__" in dir(res))
True
>>>
    (2)from collections import Iterator,Iterable 
>>> from collections import Iterator,Iterable
>>> listvar = [1,2,3,4]
>>> # 是否是一个迭代器
...
>>> res = isinstance(listvar,Iterator)
>>> res
False
>>> # 是否是可迭代对象
...
>>> res = isinstance(listvar,Iterable)
>>> res
True
>>>
  迭代器是可迭代对象
  可迭代对象不一定是迭代器

range 是 可迭代对象
>>> res = isinstance(range(10),Iterator)
>>> res
False
>>> res = isinstance(range(10),Iterable)
>>> res
True
>>>
range 和 迭代器 能够产生惰性序列 
在调用时,超出了原有的数据个数,会直接越界报错
>>> it = iter(range(3))
>>> print(next(it))
0
>>> print(next(it))
1
>>> print(next(it))
2
>>> print(next(it))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

  遍历

  通过for和next配合使用

>>> it = iter(range(5))
>>> for i in range(3):
...   res = next(it)
...   print(res)
...
0
1
2
>>>

  通过for一次性遍历迭代器中所有数据

>>> it = iter(range(5))
>>> for i in it:
...   print(i)
...
0
1
2
3
4
>>>

高阶函数

高阶函数:能够把函数当成参数传递的就是高阶函数

map
map(func,iterable)
功能:
把iterable里面所有数据 一一的放进到func这个函数中进行操作 ,把结果扔进迭代器
参数:
func 内置或自定义函数
iterable 具有可迭代性的数据 ([迭代器],[容器类型的数据],[range对象])
返回值:
返回最后的迭代器
例1:["1","2","3","4"] ==> [1,2,3,4]
常规方法
>>> listvar = ["1","2","3","4"]
>>> listvara = []
>>> for i in listvar:
...   res = int(i)
...   listvara.append(res)
...
>>> listvara
[1, 2, 3, 4]
>>>

  使用map

>>> listvar = ["1","2","3","4"]
>>> from collections import Iterator,Iterable
>>> it = map(int,listvar)
>>> print(isinstance(it,Iterator))
True
>>> print(next(it))
1
>>> print(next(it))
2
>>> print(next(it))
3
>>> print(next(it))
4
>>> # 使用for进行调用
...
>>> it = map(int,listvar)
>>> for i in it:
...   print(i)
...
1
2
3
4
>>> # for配合next进行调用
...
>>> it = map(int,listvar)
>>> for i in range(2):
...   res = next(it)
...   print(res)
...
1
2
>>> # 使用list强转成列表
...
>>> it = map(int,listvar)
>>> lst = list(it)
>>> lst
[1, 2, 3, 4]
>>>

  例2:[1,2,3,4] ==> [3,6,9,12]

>>> listvar = [1,2,3,4]
>>> listvara = []
>>> for i in listvar:
...   res = i * 3
...   listvara.append(res)
...
>>> listvara
[3, 6, 9, 12]
>>>

  map

>>> listvar = [1,2,3,4]
>>> def func(n):
...   return n * 3
...
>>> it = map(func,listvar)
>>> print(list(it))
[3, 6, 9, 12]
>>>

  例3:{97:"a",98:"b",99:"c"} ==> {"a":97,"b":98,"c":99}

>>> dictvar = {97:"a",98:"b",99:"c"}
>>> dictvara = {}
>>> res = dictvar.items()
>>> res
dict_items([(97, 'a'), (98, 'b'), (99, 'c')])
>>> # 反转字典中的键值对
...
>>> for k,v in res:
...   dictvara[v] = k
...
>>> dictvara
{'a': 97, 'b': 98, 'c': 99}
>>>

  map自定义函数,需要一个参数,必须写一个返回值

>>> def func(n):
...   dictvar = {97:"a",98:"b",99:"c"}
...   for k,v in dictvar.items():
...     dictvara[v] = k
...   return dictvara[n]
...
>>> it = map(func,["a","b","c"])
>>> print(list(it))
[97, 98, 99]
>>>
reduce
reduce(func,iterable)
功能:  
  先把iterable里面的前2个数据拿到func函数当中进行运算,得到结果,
  在把计算的结果和iterable中的第三个数据拿到func里面进行运算,
  依次类推 ,直到iterable里面的所有数据都拿完为止,程序结束
参数:
func     内置或自定义函数
iterable 具有可迭代性的数据 ([迭代器],[容器类型的数据],[range对象])
返回值:
计算的最后结果
例1:[5,4,8,8] ==> 5488
>>> listvar = [5,4,8,8]
>>> strvar = ''
>>> for i in listvar:
...   strvar += str(i)
...
>>> print(strvar,type(strvar),int(strvar))
5488 <class 'str'> 5488
>>>

  方法二:

  5 * 10 + 4 = 54

  54 * 10 + 8 = 548

  548 * 10 + 8 = 5488 

>>> listvar = [5,4,8,8]
>>> it = iter(listvar)
>>> res1 = next(it)
>>> res2 = next(it)
>>> res = res1 * 10 + res2
>>> res
54
>>> for i in it:
...   res = res * 10 + i
...
>>> print(res,type(res))
5488 <class 'int'>
>>>

  使用reduce进行改写

>>> from functools import reduce
>>> listvar = [5,4,8,8]
>>> def func(x,y):
...   return x*10 + y
...
>>> res = reduce(func,listvar)
>>> print(res,type(res))
5488 <class 'int'>
>>>

  例2:"789" ==> 789 不适用int强转的前提下完成

>>> strvar = "789"
>>> def func(n):
...   dictvar = {"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9}
...   return dictvar[n]
...
>>> def funca(x,y):
...   return x*10 + y
...
>>> it = map(func,strvar)
>>> res = reduce(funca,it)
>>> print(res,type(res))
789 <class 'int'>
>>>
sorted 
sorted(iterable,reverse=False,key=函数)
功能:  
对数据进行排序
参数:
  iterable : 具有可迭代性的数据(迭代器,容器类型数据,可迭代对象)
  reverse   : 是否反转 默认为False 代表正序, 改成True 为倒序
  key       : 指定函数 内置或自定义函数
返回值:
返回排序后的数据
>>> # 默认从小到大排序
...
>>> listvar = [88,31,-90,0]
>>> res = sorted(listvar)
>>> res
[-90, 0, 31, 88]
>>> # 从大到小排序
...
>>> listvar = [88,31,-90,0]
>>> res = sorted(listvar,reverse=True)
>>> res
[88, 31, 0, -90]
>>>

  列1:按照绝对值排序,使用内置函数

>>> listvar = [-99,-2,45,1]
>>> res = sorted(listvar,key=abs)
>>> res
[1, -2, 45, -99]
>>>

  例2:按照余数排序,使用自定义函数

>>> def func(n):
...   return n % 10
...
>>> listvar = (19,24,91,36)
>>> res = sorted(listvar,key=func)
>>> res
[91, 24, 36, 19]
>>> listvar
(19, 24, 91, 36)
>>>
filter
filter(func,iterable)
功能:
  用来过滤的,如果func函数中返回True , 会将这个值保留到迭代器中
  如果func函数中返回False , 会将此值舍弃不保留
参数:
  func : 自定义函数
  iterable : 具有可迭代性的数据(迭代器,容器类型数据,可迭代对象)
返回值:
返回处理后的迭代器
例1:保留偶数
基本写法
>>> listvar = [1,2,3,4,5,6,7,8,9]
>>> for i in listvar:
...   if i % 2 ==0:
...     print(i)
...   else:
...     pass
...
2
4
6
8
>>>

  filter写法

>>> def func(n):
...   if n % 2 == 0:
...     return True
...   else:
...     return False
...
>>> it = filter(func,listvar)
>>> print(list(it))
[2, 4, 6, 8]
>>>

  简洁写法

>>> func = lambda n:True if n % 2 == 0 else False
>>> it = filter(lambda n : True if n % 2 == 0 else False,listvar)
>>> print(list(it))
[2, 4, 6, 8]
>>>

推导式(comprehensions)

通过一行循环判断,遍历出一系列数据的方式是推导式
语法: val for val in Iterable (把想要的值写在 for的左侧)
里面是一行循环判断!根据套在推导式外层的符号判断具体是什么类型的推导式

推导式种类三种:
  [val for val in Iterable] 列表推导式
  {val for val in Iterable} 集合推导式
  {a:b for a,b in iterable} 字典推导式
例1:生成一个列表 listvar=[1,2,3,4,5,6,7,8,9,10]
>>> listvar = []
>>> for i in range(1,11):
...   listvar.append(i)
...
>>> listvar
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>>

  普通列表推导式

>>> listvar = [i for i in range(1,11)]
>>> listvar
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> listvar = [i*2 for i in range(1,11)]
>>> listvar
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
>>>

  带有判断条件的列表推导式

  基本写法

>>> listvar = [1,2,3,4,5,6,7,8,9]
>>> listvara = []
>>> for i in listvar:
...   if i % 2 == 1:
...     listvara.append(i)
...
>>> listvara
[1, 3, 5, 7, 9]
>>>

  推导式写法

>>> listvar = [1,2,3,4,5,6,7,8,9]
>>> listvara = [i for i in listvar if i % 2 == 1]
>>> listvara
[1, 3, 5, 7, 9]
>>>

  双循环列表推导式

>>> listvara = ["1","2","3"]
>>> listvarb = ["a","b","c"]
>>> listvar = []
>>> for i in listvara:
...   for j in listvarb:
...     strvar = i + ":" + j
...     listvar.append(strvar)
...
>>> listvar
['1:a', '1:b', '1:c', '2:a', '2:b', '2:c', '3:a', '3:b', '3:c']
>>>
>>> listvar = [i + ":" + j for i in listvara for j in listvarb]
>>> listvar
['1:a', '1:b', '1:c', '2:a', '2:b', '2:c', '3:a', '3:b', '3:c']
>>>

  带有条件判断的双循环列表推导式

>>> listvara = ["1","2","3"]
>>> listvarb = ["a","b","c"]
>>> listvar = []
>>> for i in listvara:
...   for j in listvarb:
...     if listvara.index(i) == listvarb.index(j):
...       strvar = i + ":" + j
...       listvar.append(strvar)
...
>>> listvar
['1:a', '2:b', '3:c']
>>>
>>>
>>> listvar = [i + ":" + j for i in listvara for j in listvarb if listvara.index(i) == listvarb.index(j)]
>>> listvar
['1:a', '2:b', '3:c']
>>>

列表推导式,集合推导式,字典推导式的相关写法

(1)普通推导式
(2)带有判断条件的推到式
(3)多循环推到式
(4)带有判断条件的多循环推到式
集合推导式(去重)
>>> setvar = {15 if i % 2 == 1 else 16 for i in range(3)}
>>> setvar
{16, 15}
 (1)enumerate
enumerate(iterable,[start=0])
功能:枚举 ; 将索引号和iterable中的值,一个一个拿出来配对组成元组放入迭代器中
参数:
  iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
  start: 可以选择开始的索引号(默认从0开始索引)
返回值:迭代器
>>> from collections import Iterator,Iterable
>>> listvar = [1,2,3,4]
>>> it = enumerate(listvar)
>>> print(it)
<enumerate object at 0x000001D7FC53BAB0>
>>> print(isinstance(it,Iterator))
True
>>> print(list(it))
[(0, 1), (1, 2), (2, 3), (3, 4)]
>>>

  强制迭代器变成字典

>>> listvar = ["a","b","c"]
>>> it = enumerate(listvar)
>>> res = dict(it)
>>> print(res)
{0: 'a', 1: 'b', 2: 'c'}
>>>

  字典推导式变成字典

>>> listvar = ["a","b","c"]
>>> it = enumerate(listvar)
>>> dictvar = {k:v for k,v in it}
>>> print(dictvar)
{0: 'a', 1: 'b', 2: 'c'}
>>>
>>> it = enumerate(listvar,start=10)
>>> dictvar = {k:v for k,v in it}
>>> print(dictvar)
{10: 'a', 11: 'b', 12: 'c'}
>>>
 (2)zip
zip(iterable, ... ...)
  功能: 将多个iterable中的值,一个一个拿出来配对组成元组放入迭代器中
  iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range)
返回: 迭代器
>>> listvara = ["1","2","3"]
>>> listvarb = ["a","b","c"]
>>> listvarc = ["e","f","g"]
>>> it = zip(listvara,listvarb,listvarc)
>>> print(list(it))
[('1', 'a', 'e'), ('2', 'b', 'f'), ('3', 'c', 'g')]
>>>

  dict强转迭代器变成字典

>>> listvara = ["1","2","3"]
>>> listvarb = ["a","b","c"]
>>> res = dict(zip(listvara,listvarb))
>>> print(res)
{'1': 'a', '2': 'b', '3': 'c'}
>>>

  字典推导式

>>> dictvar = {k:v for k,v in zip(listvara,listvarb)}
>>> print(dictvar)
{'1': 'a', '2': 'b', '3': 'c'}
>>>

元组推导式是生成器(generator)

元组推导式的返回值是一个生成器对象,简称生成器,生成器本质就是迭代器.

迭代器和生成器区别:
迭代器本身是系统内置的.重写不了.而生成器是用户自定义的,可以重写迭代逻辑

生成器可以用两种方式创建:
  (1)生成器表达式 (里面是推导式,外面用圆括号)
  (2)生成器函数   (用def定义,里面含有yield)
 yield 类似于 return
共同点在于:执行到这句话都会把值返回出去
不同点在于:yield每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走
  而return直接终止函数,每次重头调用.
yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用

基本定义,返回生成器对象,简称生成器
>>> from collections import Iterator
>>> generator_obj = (i for i in range(10))
>>> print(generator_obj)
<generator object <genexpr> at 0x000001D7FC506570>
>>> print(isinstance(generator_obj,Iterator))
True
>>>

  使用next方法调用

>>> res = next(generator_obj)
>>> res
0
>>>

  for配合next调用

>>> for i in range(5):
...   res = next(generator_obj)
...   print(res)
...
1
2
3
4
5

  for循环遍历生成器

>>> for i in generator_obj:
...   print(i)
...
6
7
8
9
>>>

生成器函数

1.基本语法

>>> def mygen():
...   print(1)
...   yield 1
...   print(2)
...   yield 2
...   print(3)
...   yield 3
...
>>>

  初始化生成器函数,返回生成器对象,调用完后会报错

>>> gen = mygen()
>>> res = next(gen)
1
>>> res = next(gen)
2
>>> res = next(gen)
3
>>> res = next(gen)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

  例1:

def mygen():
	for i  in  range(100):
		yield "num:{:d}".format(i)

# 初始化生成器函数 ,返回生成器对象,简称生成器
gen = mygen()
for i in range(50):
	res = next(gen)
	print(res)

for i in range(30):
	print(next(gen))

  数据量大使用for进行遍历,会死循环

生成器send 与 yield from

 send
next和send区别:
next 只能取值
send 不但能取值,还能发送值
send注意点:
第一个 send 不能给 yield 传值 默认只能写None
最后一个yield 接受不到send的发送值
>>> def mygen():
...   print(1)
...   res1 = yield 1
...   print(res1,"接受返回1")
...   res2 = yield 2
...   print(res2,"接受返回2")
...
>>> # 初始化生成器函数
...
>>> gen = mygen()
>>> # 第一次无法给上一个yield发送数据,强制发送None
...
>>> res = gen.send(None)
1
>>> res = gen.send(111)
111 接受返回1
>>> res = gen.send(222)
222 接受返回2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>
 yield from : 将一个可迭代对象变成一个迭代器返回
>>> def mygen():
...   yield from [1,2,3]
...
>>> gen = mygen()
>>> res = next(gen)
>>> res
1
>>> res = next(gen)
>>> res
2
>>> res = next(gen)
>>> res
3
>>>

  斐波那契数列(用前两数相加得到第三个)

>>> def mygen(n):
...   a,b = 0,1
...   i = 0
...   while i < n:
...     yield b
...     a,b = b,a+b
...     i += 1
...
>>> gen = mygen(5)
>>> for i in gen:
...   print(i)
...
1
1
2
3
5
>>>

练习题:

(1).{'x': 'A', 'y': 'B', 'z': 'C' } 把字典写成x=A,y=B,z=C的列表推导式
(2).把列表中所有字符变成小写 ["ADDD","dddDD","DDaa","sss"]
(3).x是0-5之间的偶数,y是0-5之间的奇数 把x,y组成一起变成元组,放到列表当中
(4).使用列表推导式 制作所有99乘法表中的运算
(5)#求M,N中矩阵和元素的乘积
M = [ [1,2,3], 
     [4,5,6], 
     [7,8,9] ] 

N = [ [2,2,2], 
     [3,3,3], 
     [4,4,4] ] 
=>实现效果1   [2, 4, 6, 12, 15, 18, 28, 32, 36]
=>实现效果2   [[2, 4, 6], [12, 15, 18], [28, 32, 36]]




 

 
posted @ 2019-07-14 10:28  wangzihong  阅读(337)  评论(0编辑  收藏  举报