python传参和赋值
python的赋值
Assignment statements are used to (re)bind names to values and to modify attributes or items of mutable objects ------官方文档
赋值语句用于(重新)将名称绑定到值,并修改可变对象的属性或项
python中一切皆对象,数字是对象,列表是对象,函数是对象
简单理解,python的变量可以看作一个简简单单的“标签”,除了变量名没有任何意义,直到它被一个有意义的实体(对象)所赋值,赋值的过程其实就是一个变量绑定对象的过程,可以看作是给对象贴了个标签(这个比喻相对严谨)
赋值过程
无论是可变类型(如list)的对象或是不可变类型(如int)的对象, 给变量赋值的过程都意味着绑定或重新绑定
绑定过程不是只有一次,绑定过对象的变量仍可以重新绑定其它对象(包括其它类型的对象),没有被变量绑定的对象将可能被垃圾回收
赋值int
绑定整数对象池中的一个整形对象
a = 1
b = a
c = 1
d = 2
print("a",id(a))
print("b",id(b))
print("c",id(c))
print("d",id(d))
1是一个对象,在整数对象池中是固定的(即一个特定的内存位置存储着1),如上一三两行实现了ac均绑定了整数对象1,第二行意为将a绑定的对象也绑到b上,如此,abc均绑定了对象1,所以显示相同的地址
小整数对象池和大整数对象池
整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间。
Python 对小整数的定义是 [-5, 256] 这些整数对象是提前建立好的,不会被垃圾回收。在一个 Python 的程序中,无论这个整数处于LEGB中的哪个位置,所有位于这个范围内的整数使用的都是同一个对象。同理,单个字母也是这样的。
大整数对象池。说明:终端是每次执行一次,所以每次的大整数都重新创建,而在pycharm中,每次运行是所有代码都加载都内存中,属于一个整体,所以这个时候会有一个大整数对象池,即处于一个代码块的大整数是同一个对象。
------引自:python中小整数对象池和大整数对象池
is是判断是否是同一个对象的操作符,返回值是布尔型;类似于:两个人是一个人等价于两个人的身份证号码相同(如果都有身份证),两个变量绑定了相同的对象 <==> id(变量1) == id(变量2)
赋值list
绑定一个list对象给变量
# 1
a = []
b = []
print("a is b?",a is b)
#2
goo = [1,2,3]
gll = [1,2,3]
gtt = [1,2,3,4]
print(id(goo),id(gll),id(gtt))
#3
c = b
print("c is b?",c is b)
#4
c.append(1)
print("c:",c)
print("b:",b)
1 和 2展示了:对于构造一个可变类型的对象并绑定给变量,无论当前是否有和其暂态相同的对象,都会创建新的对象,而不使用旧的对象。因为它是可变类型,有无限的可能(增删改),暂态相同并不代表永远相同,所以是否相同是不确定的事情,而python或是说程序永远不会去做不确定的事儿。这是与不可变对象的区别。
3 是将b绑定的对象给c绑定上,即bc绑定了同一个对象,那么对c的操作必定会影响对b的操作
4 是对c进行了操作,进而影响了b, 因为对c的append()追加元素操作,实际上是bc共同绑定的对象的追加变更,很多人称python可变对象的这个特点跟C++的引用一样,其实是不准确和错误的。学python的确可以借鉴C++,但不应照单全收,因为两者的机制有非常大的区别。
高级赋值操作
批量赋值
a,b,c = 1,2,3
print(a)
print(b)
print(c)
拆包与装包
# 装包:按位置将变量赋值后多余的装列表里
a,b,*c,d = 1,2,3,4,5,6
print(a,b,c,d)
# 拆包:打开列表取出值
print(*c)
python传参
python的传参过程与赋值过程类似(更像是实参给形参批量赋值),实质也是对象的绑定
C++有传值,传引用,python的参数传递是?就叫他 传对象 吧!
传不可变对象
def give_me_a_num(a):
a = a+1
print("give_me_a_num's a:",a)
def main():
a = 1
print("main's origin a:",a)
give_me_a_num(a)
print("main's a:",a)
main()
a在main里是绑定的整数1,传过去给give_a_num的a, 说你也绑定这个对象吧,于是give_me_a_num里的a的值是1,
接着give_me_a_num里发生了状况,里面的a不喜欢1这个对象了,舍弃,重新绑定了对象a+1,也就是2,
而main里的a一直对1不离不弃,所以这个a一直是1
这样一气呵成,并没什么不妥;但很多人看了这个以后断定:python的参数传递和C++的值传递一样
传可变对象
def give_me_a_girl(girl):
girl["lover"] = "Mike"
print("give_me_a_girl's girl:\n\t",girl)
def main():
girl = {"name":"Mark","age":20,"lover":"Tim"}
print("main's origin girl:\n\t",girl)
give_me_a_girl(girl)
print("main's girl:\n\t",girl)
print("\nTim:\"Mark,you changed!You don't love me anymore.\"")
main()
这里girl是一个字典,是一个可变对象,main里面的变量girl绑定了这个对象,传给了give_me_a_girl里的girl,它也绑定了这个对象,并且对所绑定的对象做了相应的修改,因为main和give_me_a_gril里的girl绑定的是同一个对象,所以main's girl也是改变了的,本质是其绑定的对象发生了改变。
这是python传可变对象的实质,如果give_me_a_girl里面的girl重新绑定了新的对象,再做变化,就不会再影响到main's girl了;但是很多人看了这种实例,就断言:python传参方式和C++里的引用传递一样
默认值参数
def make_cake(cream,butter = 0,fruit = 3):
print("做了蛋糕")
print("奶油{}斤,黄油{}两,水果{}块".format(cream,butter,fruit))
make_cake(1,3)
make_cake(1,2,4)
make_cake(4)
make_cake(2,fruit = 8) #python比较高级的地方
make_cake()的使用比较方便,有两个默认参数,传参时第一个实参不可省,确认是给cream的,剩下两个可以按顺序给或不给(默认),使用key=value的方式可以打破顺序
拆包装包实现可变参数的函数
def get(git_id,*args,**kwargs): #git_id要写前面,否则贪婪匹配,不会给它剩
print("装包后:")
print("git_id:",git_id)
print("args:",args)
print("kwargs:",kwargs)
print("对传过来的参数拆包:".format())
print("*args:",*args)
print("kwargs拆包后传给fun:",end="")
fun(**kwargs) #相当于fun(a=1,b=2)
def fun(b,a): #注意键名和参数名对应
print(a,b)
get(1,2,3,4,5,6,a=1,b=2) #调用时前面第一个之后装包给元组,剩下给字典
args作为形参时是用来接收多余的未命名参数,而*kwargs是用来接收key=value这种类型的命名参数,args是元组,kwargs是字典。
拆装包实现对象的拷贝
# 方便的使用方法
def rich(*money):
print("今天赚了{}元钱".format(sum(money)))
rich(2,3,4,5)
def rich(*money):
print(id(money))
print("今天赚了{}元钱".format(sum(money)))
def main():
today_come = [1,2,3,4,5,6]
print(id(today_come))
rich(*today_come)
main()
可以看到rich()‘s money和 main()’s today_come 的id不一样,也就是两者没有绑定一样的对象了,因为拆包后会装到一个新的包里,这样互相就不影响了
想到这里,,,
def give_me_a_girl(**girl):
girl["lover"] = "Mike"
print("give_me_a_girl's socalled girl:\n\t",girl)
def main():
girl = {"name":"Mark","age":20,"lover":"Tim"}
print("Tim's origin girl:\n\t",girl)
give_me_a_girl(**girl)
print("Tim's normal girl:\n\t",girl)
print("\nTim: \"I love you,Mark!\"")
main()