共享内存
a = 1
b = a
print(a == b) #True
print(a is b) #True
print(id(a)) #8791381152576
print(id(b)) #8791381152576
直接赋值、浅拷贝和深度拷贝解析
直接赋值:其实就是对象的引用(别名)。
浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。
深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。
import copy
a = [1, 2, 3, 4, ['a', 'b']] # 原始对象
b = a # 赋值,传对象的引用
c = copy.copy(a) # 对象拷贝,浅拷贝
d = copy.deepcopy(a) # 对象拷贝,深拷贝
a.append(5) # 修改对象a
a[4].append('c') # 修改对象a中的['a', 'b']数组对象
print('a = ', a) #a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
print('b = ', b) #b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
print('c = ', c) #c = [1, 2, 3, 4, ['a', 'b', 'c']]
print('d = ', d) #d = [1, 2, 3, 4, ['a', 'b']]
浅拷贝
拷贝之后元素一样,内存地址不同
a = [1,2,3]
b = a.copy()
print(a == b) #True
print(id(a)) #30433864
print(id(b)) #30433928
可更改(mutable)与不可更改(immutable)对象
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict,set则是可以修改的对象。
不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
传不可变对象实例
def jisuan(a,b):
a = 10
c = a + b
return c
x = 5
y = 6
z = jisuan(x,y)
print(z) #16
传可变对象实例
x = [1,2,3]
y = [4,5,6]
def modify(a,b):
b = [5,6,7]
b.append(4)
modify(x,y)
print(x) #[1, 2, 3]
print(y) #[4, 5, 6]
可变类型作为默认参数时,会造成歧义
def hanshu(a = []): #不建议使用可变类型作为默认参数,因为会造成歧义
a.append("h")
print(a)
hanshu() #['h'] # 默认调用a的地址
hanshu() #['h', 'h'] # 默认调用a的地址
全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。
a = [1,2,3] #全局变量
def hanshu():
x = 1 #局部变量
print(a) #[1, 2, 3]
hanshu()
print(x) # x是局部变量,只能在函数内部访问
locals(),查看局部变量
globals(),查看全局变量
def hanshu(a,b):
i = 1
j = 2
print(locals()) #{'a': 3, 'b': 4, 'i': 1, 'j': 2}
x = 3
y = 4
hanshu(x,y)
print(globals()) #{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000001D66320>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/Python编程_从入门到实践/04.28.py', '__cached__': None, 'hanshu': <function hanshu at 0x0000000001CFC1E0>, 'x': 3, 'y': 4}
注意变量的赋值顺序,和作用域
a = 1
b = 2
def hanshu():
print(a) #1
print(b) #2
print(c) #NameError: name 'c' is not defined
hanshu()
c = 3
全局变量可以和局部变量重名:
a = 3
def hanshu():
a += 5 #a = a + 5 # a没有被赋值
print(a)
hanshu() #UnboundLocalError: local variable 'a' referenced before assignment
print(a) #3
如果全局变量是不可变数据类型,函数无法修改全局变量的值:
a = 1
def hanshu():
a = 2 #局部变量,只作用于函数里面,无法改变函数外部的不可变数据
print(a)
hanshu() #2
print(a) #1
如果全局变量是可变数据类型,函数可以修改全局变量的值:
a = [1,2,3,4]
def hanshu():
a.append(5) #a地址不变,添加元素5,修改了列表a
hanshu()
print(a) #[1, 2, 3, 4, 5]
如果全局变量是可变数据类型,函数可以修改全局变量的值:
a = [1,2,3,4]
def hanshu():
a = [5,6,7] #局部变量,重新赋值,地址更改,但与全局变量无关
hanshu()
print(a) #[1, 2, 3, 4, 5]
函数嵌套
def hanshu1():
def hanshu2(x,y):
z = x + y
return z
a = 2
b = 3
return hanshu2(a, b)
print(hanshu1()) #5
global 关键字把局部变量变成全局变量:
def hanshu1():
global a
a = 1
hanshu1() #调用hanshu1()函数
print(a) #1
b = 3
def hanshu2():
global b
b += 4 # b = 3 + 4
print(b) #3
hanshu2() #调用hanshu2()
print(b) #7
nonlocal 关键字可以修改函数的外层局部变量
b = 3
def outer():
a = 1
b = 4
def inner():
nonlocal a
nonlocal b
a = 2
b = 5
print(a) #1
print(b) #4
inner() #调用inner()函数
print(a) #2
print(b) #5
outer()
print(b) #3
变量作用域
Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。
变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python的作用域一共有4种,分别是:
L (Local) 局部作用域
E (Enclosing) 闭包函数外的函数中
G (Global) 全局作用域
B (Built-in) 内置作用域(内置函数所在模块的范围)
以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
用一个函数说明变量作用域的访问顺序:
a = 1
b = 4
c = 6
def outer():
a = 2
b = 5
def inner():
a = 3
print("a =",a) #a = 3 局部作用域
print("b =",b) #b = 5 嵌套作用域
print("c =",c) #c = 6 全局作用域
print(max,__name__) #<built-in function max> __main__ #內建作用域
inner()
outer()
匿名函数
python 使用 lambda 来创建匿名函数。
所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。
lambda 只是一个表达式,函数体比 def 简单很多。
lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
a = lambda x,y:2 * x + y #这是一个匿名函数
b = a(1,2)
print(b) #4
a = lambda x,y,z:x*y*z
b = a(1,2,3)
print(b) #6
內建函数:
abs()返回绝对值:
print(abs(18)) #18
print(abs(-18)) #18
max()方法返回给定参数的最大值
max()方法的语法
max( x, y, z, … )
a = [1,3,5,-6,-2,-9]
print(max(a)) #5
min() 方法返回给定参数的最小值
a = [1,3,5,-6,-2,-9]
print(min(a)) #-9
求绝对值最大的数
a = [-7,-2,-3,4,5,6]
b = max(a,key=abs)
print(b) #-7
求相反数最大的数:
方法一:
def hanshu(a):
return - 1 * a
a = [10,20,30,-50,60]
b = max(a,key = hanshu)
print(b) #-50
方法二
a = [10,20,30,-50,60]
b = max(a,key= lambda a:-1*a)
print(b) #-50
按绝对值大小排序
a = [2,-3,1,-5,4]
a.sort(key=abs)
print(a)
map(function, iterable, …)
根据提供的函数对指定序列做映射。
第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
把元组x = (1,2,3),每个元素都乘以它本身,并返回一个列表
方法一
def hanshu(a):
return a*a
x = (1,2,3)
y = map(hanshu,x)
print(y) #<map object at 0x0000000001EF9630>
for i in y:
print(i,end = " ") #1 4 9
方法二
def hanshu(a):
return a*a
x = (1,2,3)
y = map(lambda e:e*e,x)
print(y) #<map object at 0x0000000002959630>
for i in y:
print(i,end = " ") #1 4 9
filter(function, iterable)
用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。
接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
把列表a = [1,2,3,4,5,6,7,8,9]中,所有能被3整数的数提出来
方法一
def shaixuan(a):
if a % 3 == 0:
return a
a = [1,2,3,4,5,6,7,8,9]
b = list(filter(shaixuan,a))
print(b) #[3, 6, 9]
方法二
def shaixuan(a):
if a % 3 == 0:
return a
a = [1,2,3,4,5,6,7,8,9]
b = list(filter(lambda x:x % 3 == 0,a)) #x % 3 == 0为True时,返回x
print(b) #[3, 6, 9]
zip([iterable, …])
用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。
我们可以使用 list() 转换来输出列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
a = [1,2,3]
b = ["a","b","c","d"]
c = zip(a,b) # 返回一个对象
print(c) #<zip object at 0x00000000039E4208>
print(list(zip(a,b))) # list() 转换为列表,[(1, 'a'), (2, 'b'), (3, 'c')]
e,f = zip(*c) # 与 zip 相反,zip(*) 可理解为解压,返回二维矩阵式
print(e) #(1, 2, 3)
print(f) #('a', 'b', 'c')
转换成指定格式:
方法一:
a = ("a","b")
b = ("c","d")
c = zip(a,b)
def dict(x):
return {x[0]:x[1]}
list = []
for i in c:
list.append(dict(i))
print(list)
方法二:
a = ("a","b")
b = ("c","d")
x = list(map(lambda x:{x[0]:x[1]},zip(a,b)))
print(x)
b = lambda x,y:x if x>y else y
print(b(2,3)) #3
用max()查找字典中的最大值
方法一:
a = {"a":1,"b":2,"c":3}
def zuidazhi(x):
return a[x]
b = max(a,key=zuidazhi)
print(b) #c
方法二:
a = {"a":1,"b":2,"c":3}
b = max(a,key = lambda k:a[k])
print(b) #c
查找年龄最大的,给列表按年龄大小排序
a=[{"name":"张三",'age':18},
{"name":"李四",'age':28},
{"name":"王五",'age':48},
{"name":"小明",'age': 8},
]
def hanshu(a):
return a["age"]
b = max(a,key=lambda a:a["age"]) #查找
print(b) #{'name': '王五', 'age': 48}
a.sort(key=lambda a:a["age"]) #排序
print(a) #[{'name': '小明', 'age': 8}, {'name': '张三', 'age': 18}, {'name': '李四', 'age': 28}, {'name': '王五', 'age': 48}]
注意变量的查找顺序:
def outer():
x = 3
def inner(n):
return x ** n
return inner
a = outer()
print(a(3)) #27
def hs(x,y):
return x + y
b = hs
print(b(1,2)) #3
闭包函数
def inter():
x = 3
z = lambda n:n*x
return z
x = 9
b = inter()
print(b(2)) #6
def hanshu():
list = []
for i in range(4):
list.append(lambda a:a * i)
return list
a = hanshu()
print(a[0](2)) #6
print(a[1](2)) #6
print(a[2](2)) #6
print(a[3](2)) #6
i = 5
a = lambda x:x*i
i = 6
b = lambda x:x*i
print(a(2)) #12
print(b(2)) #12