Python学习(二)
一、深拷贝和浅拷贝
对于数字和字符串而言,赋值、浅拷贝和深拷贝没有意义,永远指向同一个内存地址,其中一个变量的值改变,这个变量会指向其他内存地址,其他的变量指向的内存地址不变,即值不变
1 import copy 2 n1 = 123 3 print(id(n1)) 4 n2 = n1 5 print(id(n2)) 6 n3 = copy.copy(n1) 7 print(id(n3)) 8 n4 = copy.deepcopy(n1) 9 print(id(n4)) 10 n1 = 456 11 print(n1) 12 print(id(n1)) 13 print(n2) 14 print(id(n2))
1421199632
1421199632
1421199632
1421199632
456
1683152
123
1421199632
字符串、数字的赋值、浅拷贝和深拷贝的示意图

对于字典、元组、列表而言,对他们进行赋值、浅拷贝和深拷贝时,内存地址的变化是不同的,对于赋值两个变量的内存地址是相同的,对于浅拷贝而言,只拷贝第一层(比如字典只拷贝键,键的内存地址不是原来的,例如某一个键对应的值是一个列表,则两个变量的列表都是相同的内存地址,还是原来的内存地址,若改变其中一个列表中的值则两个变量都会改变),深拷贝则可以拷贝多层(比如字典中某一个键对应的值为一个列表,则列表的内存地址也拷贝了一份,即使是多层嵌套也同样,两个变量的列表内存地址指向不同的内存地址,若改变其中一个变量中列表的值,其他变量中列表的值不变)
1 import copy 2 n1 = {"k1":"wu","k2":123,"k3":["alex",456]} 3 print(id(n1)) 4 n2 = n1 5 print(id(n2)) 6 print('\n') 7 n3 = copy.copy(n1) 8 print(id(n3)) 9 print('\n') 10 print(id(n1["k3"])) 11 print(id(n3["k3"])) 12 print('\n') 13 n4 = copy.deepcopy(n1) 14 print(id(n4)) 15 print('\n') 16 print(id(n1["k3"])) 17 print(id(n4["k3"])) 18 print('\n') 19 print(id(n1["k3"][0])) 20 print(id(n4["k3"][0]))
31157416
31157416
31157488
36842760
36842760
31986456
36842760
36842568
36642464
36642464
字典、元组、列表的赋值示意图

字典、元组、列表的浅拷贝示意图

字典、元组、列表的深拷贝示意图

1 import copy 2 dict_computer = {"cup":[80],"mem":[50],"disk":[60]} 3 new_dict_computer1 = copy.copy(dict_computer) 4 new_dict_computer1["mem"][0] = 80 5 print(dict_computer) 6 print(new_dict_computer1) 7 print('\n') 8 new_dict_computer2 = copy.deepcopy(dict_computer) 9 new_dict_computer2["mem"][0] = 60 10 print(dict_computer) 11 print(new_dict_computer2)
{'cup': [80], 'mem': [80], 'disk': [60]}
{'cup': [80], 'mem': [80], 'disk': [60]}
{'cup': [80], 'mem': [80], 'disk': [60]}
{'cup': [80], 'mem': [60], 'disk': [60]}
二、函数
把一些功能重复使用的代码封装起来,可以被调用,形成一个函数,函数的基本结构为:定义函数名,写入参数(可以不写,也可以是默认参数、动态参数),冒号下边是函数实现的功能,可以return函数结果值
1 def func(*args,**kwargs): 2 pass
函数内部的变量称为局部变量,局部变量只在函数体内有效(所以函数内部和函数外部可以有相同的变量名,互不影响),该函数体外部不能调用,函数体外部的变量称为全局变量,函数内部要访问全局变量需要在函数内部声明它是全局变量,即 global 变量名
函数体括号内写入函数变量名,称为普通参数,函数返回值可以有多个,接收时也要有多个参数,要一一对应
1 def func(a,b,c): 2 print(a+b) 3 return c,b+c 4 5 d,e = func(1,2,5) 6 print(d) 7 print(e)
3
5
7
可以为函数设置默认参数,调用函数时,若没有传入对应的参数则函数执行默认参数,若传入对应参数则函数默认参数被替代,也可以对函数中的形参指定参数
1 def func(a,b,c=9): 2 print(a+b) 3 return c,b+c 4 5 d,e = func(1,2,5) 6 print(d) 7 print(e) 8 print('\n') 9 d,e = func(1,2) 10 print(d) 11 print(e) 12 print('\n') 13 d,e = func(c=1,a=2,b=7) 14 print(d) 15 print(e)
3
5
7
3
9
11
9
1
8
当不确定给函数传入多少参数时,可以对函数体的形参设置成动态参数,*arg接收的参数变为一个列表,可在函数体中读出参数列表或者循环读出一个个参数,**karg接收的参数变为一个字典,可对参数进行字典的操作
1 def sum(*nums): 2 print(nums) 3 sum_num = 0 4 for num in nums: 5 sum_num += num 6 return sum_num 7 8 def dict_fun(**kwargs): 9 print(kwargs) 10 print(kwargs.keys()) 11 print(kwargs.values()) 12 for i in kwargs.keys(): 13 print(kwargs[i]) 14 15 sum_num = sum(1,2,3,4,7,8,5,4,6) 16 print(sum_num) 17 18 list1 = [1,2,3,4,7,8,5,4,6] 19 sum_num1 = sum(*list1) 20 print(sum_num1) 21 22 dict_fun(k1=3,k2=5,k3=7)
(1, 2, 3, 4, 7, 8, 5, 4, 6)
40
(1, 2, 3, 4, 7, 8, 5, 4, 6)
40
{'k1': 3, 'k3': 7, 'k2': 5}
dict_keys(['k1', 'k3', 'k2'])
dict_values([3, 7, 5])
3
7
5
二、lambda表达式
lambda表达式,即简单函数的简单表示,lambda表达式的格式为:
函数名 = lambda 形参: 功能
函数功能只能有一行代码,形参可以为多个,调用时格式为:函数名(实参)
1 fun = lambda a,b: a+b 2 print(fun(2,3))
5
三、内置函数
内置函数指不需要导入模块,就可以直接使用的函数,一般都是因为使用频率比较频繁或是是元操作,所以通过内置函数的形式提供出来,基本的数据操作基本都是一些数学运算(当然除了加减乘除)、逻辑操作、集合操作、基本IO操作,然后就是对于语言自身的反射操作,还有就是字符串操作。
数学运算类
1 print(complex(2,3)) # 创建一个复数 2 print(abs(-9)) # 求绝对值,参数可以为实数,也可以为复数,复数返回模 3 print(divmod(9,4)) # 求商和余数,返回第一个值为商,第二个值为余数 4 print(pow(3,2)) # 计算a的b次幂 5 for i in range(2,8): 6 print(i) # 生成从a到b-1的一个序列数 7 print(round(2.7)) # 四舍五入 8 a = set([1,5,7]) 9 print(sum(a)) 10 print(sum([1,2,3])) # 对集合中的值求和 11 print(oct(10)) # 将一个数转化为8进制数 12 print(hex(10)) # 将一个数转化为16进制数 13 print(ord('a')) # 将字符变为ASCII码 14 print(chr(97)) # 将ASCII码变为字符 15 print(bin(20)) # 将数字转化为二进制 16 print(bool(-1)) # 转化为布尔类型,除0外都为真
enumerate()是python的内置函数,在字典上是枚举、列举的意思,对于一个可迭代的(iterable)/可遍历的对象(如列表、字符串),enumerate将其组成一个索引序列,利用它可以同时获得索引和值,enumerate多用于在for循环中得到计数
1 ret = list(['苹果','香蕉','西瓜']) 2 for i,item in enumerate(ret,1): # 第一个参数为一个序列,第二个参数为起始编号,不写默认从0开始 3 print(i, item) 4 5 # 如果要统计文件的行数,可以这样写 6 count = 0 7 for index, line in enumerate(open('123.txt','r'),1): 8 count += 1 9 print(index,line) 10 print(count)
1 苹果
2 香蕉
3 西瓜
1 this is first linethis is second line
2 this is third line
2
eval() 参数为一个计算式的字符串,可将字符串中的计算结果给出:result = eval('9*8') print(result) --> 72;
map(function, list) 一个序列根据条件映射为另一个新的序列,可得到映射后的序列,第一个参数为条件函数,第二个参数为原始的列表
1 def add100(x): 2 return x + 100 3 hh = [11,22,33] 4 for value1 in map(add100,hh): # 将列表中的每一个数映射到函数中,得到新的列表 5 print(value1) 6 7 def abc(a, b, c): 8 return a*10000 + b*100 + c 9 list1 = [11,22,33] 10 list2 = [44,55,66] 11 list3 = [77,88,99] 12 for value2 in map(abc,list1,list2,list3): # 如果给出了多个可迭代参数,则对每个可迭代参数中的元素‘并行’应用到function 13 print(value2)
111
122
133
114477
225588
336699
filter(function, list) 一个序列根据条件过滤,符合条件的生成一个新的序列,可接收这个序列,第一个参数为条件函数,第二个参数为原始序列;和map()类似,filter()也接收一个函数和一个序列,和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素
1 def is_odd(n): 2 return n % 2 == 1 3 list1 = [] 4 for value1 in filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]): 5 list1.append(value1) 6 print(list1) 7 8 def not_empty(s): 9 return s and s.strip() 10 list2 = [] 11 for value2 in filter(not_empty, ['A', '', 'B', None, 'C', ' ']): 12 list2.append(value2) 13 print(list2)
[1, 5, 9, 15]
['A', 'B', 'C']
float() 把一个数字或者数字的字符串转换为浮点型;frozenset() 使集合不能进行增减等改变操作;
max() 序列的最大值;mix() 序列的最小值;id() 查看变量的内存地址;
reversed() 参数为字符串,序列,使之反转,若参数为字符串则得到反转后单个字符组成的列表;
sorted() 对序列排序,序列中要同类型数据
zip() 参数为序列,将序列中对应序号的元素各自组成一个元组,生成新的序列,zip函数接受任意多个(包括0个和1个)序列作为参数,返回一个tuple列表
1 x = [1, 2, 3] 2 y = [4, 5, 6] 3 z = [7, 8, 9] 4 for value1 in zip(x, y, z): 5 print(value1) 6 7 x = [1, 2, 3] 8 y = [4, 5, 6, 7] 9 for value2 in zip(x, y): 10 print(value2) 11 12 x = [1, 2, 3] 13 for value3 in zip(x): 14 print(value3) 15 16 x = [1, 2, 3] 17 for value4 in zip(*[x] * 3): 18 print(value4)
(1, 4, 7)
(2, 5, 8)
(3, 6, 9)
(1, 4)
(2, 5)
(3, 6)
(1,)
(2,)
(3,)
(1, 1, 1)
(2, 2, 2)
(3, 3, 3)
四、迭代器和生成器
迭代器是访问集合中元素的一种方式,从第一个元素开始直到元素结束,迭代器只能向前访问,不能向后,生成迭代器的方式是将一个序列传入迭代器函数
1 f = open('456.txt','r',encoding='utf-8') 2 file = f.readlines() 3 file_iter = iter(file) # 将一个序列传入iter()函数,形成一个迭代器 4 print(file_iter.__next__()) # 读取迭代器的内容,用obj.__next__()方法,一次读取一个迭代器元素 5 print(file_iter.__next__())
古剑奇谭OL
剑侠情缘网络版3
一个函数被调用时返回一个迭代器,那这个被调用的函数叫做生成器,即函数中包含yield语法,那这个函数就是一个生成器
1 def cash_money(amount): 2 while amount>0: 3 print('取钱!') 4 amount -= 100 5 yield 100 # 每执行一次obj.__next__(),函数会从上到下执行,等执行到yield这行代码 6 # 会返回yield后面的值,同时停止运行设为断点,当执行下一次obj.__next__()时, 7 # 函数从yield后面的代码执行,当执行完整个代码之后会继续从头开始执行,到yield 8 # 代码行返回值并设为断点,再执行下一次obj.__next__()时重复之前的行为 9 print('取了100,又来!') 10 11 atm_cash = cash_money(500) 12 print(type(atm_cash)) 13 print(atm_cash) 14 print(atm_cash.__next__()) 15 print('第一次执行obj.__next__()结束后!') 16 print(atm_cash.__next__()) 17 print('第二次执行obj.__next__()结束后!')
<class 'generator'>
<generator object cash_money at 0x000000B48EA7D1A8>
取钱!
100
第一次执行obj.__next__()结束后!
取了100,又来!
取钱!
100
第二次执行obj.__next__()结束后!
举一个生产者和消费者的例子,生产者做包子,消费者吃包子
1 import time 2 3 def customer(name): 4 print("%s准备吃包子了。。。" %name) 5 while True: 6 baozi = yield # 当执行obj.__next__()时,函数运行到这行代码,等待给yield传入值,同时设置断点, 7 # 每当给yield传入参数,函数都会把yield赋值给变量,并执行yield下面的程序,当执行完 8 # 之后,不是再从头开始执行函数,而是到断点处等待下一次给yield传入参数,当再给yield 9 # 传入参数,则重复上一次的行为 10 print("%s吃了%s个包子。。。" %(name, baozi)) 11 12 def conductor(name1): 13 print("%s开始做包子了。。。" %name1) 14 a = customer('A') #用生成器函数得到一个迭代器 15 b = customer('B') 16 a.__next__() #执行迭代器函数中代码,预备读取yield中的内容 17 b.__next__() 18 for i in range(5): 19 time.sleep(1) 20 print("第%s次做了2个包子。。。" %(i+1)) 21 a.send(1) #向迭代器中的yield传入值 22 b.send(1) 23 print("第%s执行结果!" %(i+1)) 24 25 conductor("zhu")
zhu开始做包子了。。。
A准备吃包子了。。。
B准备吃包子了。。。
第1次做了2个包子。。。
A吃了1个包子。。。
B吃了1个包子。。。
第1执行结果!
第2次做了2个包子。。。
A吃了1个包子。。。
B吃了1个包子。。。
第2执行结果!
第3次做了2个包子。。。
A吃了1个包子。。。
B吃了1个包子。。。
第3执行结果!
第4次做了2个包子。。。
A吃了1个包子。。。
B吃了1个包子。。。
第4执行结果!
第5次做了2个包子。。。
A吃了1个包子。。。
B吃了1个包子。。。
第5执行结果!
五、装饰器
装饰器是对功能进行扩展,在不改变原来的函数代码基础上,增加函数的功能,装饰器的框架如下:
def login(func): def inner(*args,**kwargs): # 功能1 # 功能2 # 功能3 return func(*args,**kwargs) # 在原来的业务函数中,有返回值的需要return才能被接收 return inner # 装饰函数,扩展函数功能 @login #执行login函数,把被装饰的函数的函数名当作参数传入login,login(w1),其返回值inner(函数地址)赋予w1,得到的新的w1就执行inner中的内容和原来w1中的内容 def w1(*args,**kwargs): # 函数功能1 # 函数功能2 return value #调用函数 value = w1(name,passwd)
当一个函数需要扩展多个功能时,需要对装饰器传入以扩展功能函数的函数名为参数的形参,这样就需要在外部再加入一层函数,装饰器框架如下:
def derector(name1,name2): #装饰器框架,传入扩展功能函数函数名 def need_func(func): #装饰函数,传入业务函数函数名 def inner(*args,**kwargs): result_name1 = name1(*args,**kwargs) #执行扩展功能函数 result_name2 = name2(*args,**kwargs) result_fun = func(*args, **kwargs) # 执行业务函数 return result_fun return inner return need_func def num1(*args,**kwargs): #扩展功能函数 print(789) def num2(*args,**kwargs): print(159) @derector(num1,num2) # 当执行derector函数,把扩展功能函数的函数名传入derector,返回need_func时把被装饰的函数名w1传入need_func,返回inner时就执行inner内部的功能 def w1(a,b): print(a) print(b) return 5 result = w1('123','456') print(result)
789
159
123
456
5
浙公网安备 33010602011771号