Python:万物皆对象,本质是引用(指针)
python中的赋值 =
从变量与数据角度理解python中变量(名)与数据分离存储,对变量名的调用,例如:a=1
然后print(a)
,print(a)
实际是先引用数据存储的位置,然后再打印。因此可以简单理解为a和数字1都是对象,1赋值给a则是将地址赋给a。
从对象角度理解,这里的a
和1
实际上都是对象,执行a=1
本质上是把a
指向1
所在的地址。此时,如果将a
赋值为2
,则a
的地址会重新指向2
所在的地址。例如:
#id()用于获取对象的内存地址
x = 1
print("x id:",id(x),"\n数值id:",id(1),"x:",x)
print("~~~~~~~~~~~~~~~~~~~~~~~")
x = 2
print("x id:",id(x),"\n数值id:",id(1),"x:",x)
x *=1
print("原地操作:",id(x),"\tx:",x)
x +=1
print("非原地操作:",id(x),"\tx:",x)#对象已经改变,不在是数值2
y = x
x_pre = id(x)
print("y:",y,"\tx:",x)
print("y id:",id(y),"\nx id:",id(x))
print("~~~~~~~~~~~~修改x的值~~~~~~~~~~~")
x = 1
x_after = id(x)
print("y:",y,"\tx:",x)
print("y id:",id(y),"\nx id:",id(x))
print("x之前的id:",x_pre)
print("x重新赋值为1的id:",x_after)
print("x由重新指向了最开始的数值对象:1")
x id: 140704650404256
数值id: 140704650404256 x: 1
~~~~~~~~~~~~~~~~~~~~~~~
x id: 140704650404288
数值id: 140704650404256 x: 2
原地操作: 140704650404288 x: 2
非原地操作: 140704650404320 x: 3
y: 3 x: 3
y id: 140704650404320
x id: 140704650404320
~~~~~~~~~~~~修改x的值~~~~~~~~~~~
y: 3 x: 1
y id: 140704650404320
x id: 140704650404256
x之前的id: 140704650404320
x重新赋值为1的id: 140704650404256
x由重新指向了最开始的数值对象:1
print("~~~~~~~~~~~~列表对象~~~~~~~~~~~")
a = [1,2,3]
pre_a = id(a)
print("a id:",pre_a,"\ta:",a)
a *= 2
after_a = id(a)
print("a id:",after_a,"\ta:",a)
b = a
pre_b = id(b)
print("a id:",id(a),"\nb id:",pre_b)
b *=3
after_b = id(b)
print("a id:",id(a),"\nb id:",pre_b)
print("a:",a,"b:",b)
print(a==b)
print("b[1] id:",id(b[1]))
b[1] = 100
print("b id:",id(b),"after_b id:",after_b)
print("b[1] id:",id(b[1]))
b[1] = 3
print("b[1] id",id(b[1]),"\nb[2] id",id(b[2]))
~~~~~~~~~~~~列表对象~~~~~~~~~~~
a id: 2340823783240 a: [1, 2, 3]
a id: 2340823783240 a: [1, 2, 3, 1, 2, 3]
a id: 2340823783240
b id: 2340823783240
a id: 2340823783240
b id: 2340823783240
a: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3] b: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
True
b[1] id: 140704650404288
b id: 2340823783240 after_b id: 2340823783240
b[1] id: 140704650407424
b[1] id 140704650404320
b[2] id 140704650404320
小结:
python中万物皆对象,无论是什么数据类型(数值、字符串、列表等等本质都是对象),只要产生后就会给该对象分配一个内存空间。区别在于这些对象能都修改,例如数值对象1
就不能修改(指直观上通过变量进行+1这样的操作),而列表元素可以修改(对列表元素值进行改变后,列表id不会变换,但是列表元素的id会变),但是列表的每一个元素又是对象。
两句话概括:本质就是无限套娃,直到套到最底层的数据int、char这些为止。变量id是否会随数据的变化而改变,得看数据对象是什么类型。
基本语法:
1.*
与**
:
1.1*
在传递参数的时候使用,表示将列表元素解开,例如:
x = [1,2,3]
def fn(a,b,c):
print(a,b,c)
return a+b+c
fn(*x)
1 2 3
6
1.2*
函数定义时(出现在参数中),表示将传进来的参数转为一个元组,例如:
x = [1,2,3]
def fn(*args):
print(args)
return args
fn(*x)
(1, 2, 3)
(1, 2, 3)
1.3**
在传递参数的时候使用,表示将字典元素解开,例如:
x = {
"a":1,
"b":2,
"c":3
}
def fn(a,b,c):
print(a,b,c)
fn(**x)
1 2 3
1.4**
函数定义时(出现在参数中),表示将传进来的参数转为字典,例如:
def fn(**kwargs):
for key, value in kwargs.items():
print("key:",key,",value:",value)
print(type(key),type(value))
fn(a=1,b=2,c=3,d=4,e=5,f=6)
key: a ,value: 1
<class 'str'> <class 'int'>
key: b ,value: 2
<class 'str'> <class 'int'>
key: c ,value: 3
<class 'str'> <class 'int'>
key: d ,value: 4
<class 'str'> <class 'int'>
key: e ,value: 5
<class 'str'> <class 'int'>
key: f ,value: 6
<class 'str'> <class 'int'>
注意点:
1.定义函数的时候,参数列表中出现有参数给定初始值时,其后边的参数必须给定初始值,否则会报错,例如:
def fn(a,b,c=1,d):#会报错
print(a,b,c,d)
def fn(a,b,c=1,d=2):#不会报错
print(a,b,c,d)