"""author = 陳俊龍"""
==============運(yùn)算符的重載==============
1. 運(yùn)算符
python中所以的數(shù)據(jù)類型本質(zhì)都是類扇谣,所以所有的數(shù)據(jù)本質(zhì)都是對(duì)象
使用運(yùn)算符對(duì)數(shù)據(jù)進(jìn)行操作的時(shí)候笨觅,實(shí)際是調(diào)用運(yùn)算符對(duì)應(yīng)的魔法方法
運(yùn)算符前面的數(shù)據(jù)類型決定了函數(shù)調(diào)用哪個(gè)類中對(duì)應(yīng)的魔法方法
10+20 # class int
'abc'+'123' # class str
[1, 2, 3]+[1] # class list
每個(gè)運(yùn)算符都有自己固定的魔法方法,看某種類型的數(shù)據(jù)是否支持某種運(yùn)算符就看這個(gè)類型中有沒有實(shí)現(xiàn)對(duì)應(yīng)的魔法方法
例如:
‘+’ -- _ add _
‘>’ -- _ gt _
class Student:
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
# +號(hào)對(duì)應(yīng)的魔法方法,實(shí)現(xiàn)兩個(gè)對(duì)象求和
def __add__(self, other):
return self.age+other.age
# 定制乘法運(yùn)算,實(shí)現(xiàn)對(duì)象乘數(shù)字
def __mul__(self, other):
return self.age * other
def __repr__(self):
return '<%s>' % str(self.__dict__)[1:-1]
# 定制比較運(yùn)算拘悦,實(shí)現(xiàn)對(duì)象成績(jī)的比較(比較多的情況)
def __lt__(self, other):
return self.score < other.score
def __gt__(self, other):
return self.score > other.score
stu1 = Student('小明', 18, 90)
stu2 = Student('小李', 18, 92)
print(stu1 == stu2) # False 支持相等比較锋爪,其他的比較都不支持婆翔,如果需要,只有自己去寫__add__這個(gè)魔法方法
# 自己實(shí)現(xiàn)加法運(yùn)算的魔法方法后的效果:
print(stu1+stu2)
# 自己實(shí)現(xiàn)乘法運(yùn)算的魔法方法后的效果:
print(stu1*2)
all_student = [
Student('stu1', 17, 90),
Student('stu2', 17, 91),
Student('stu3', 17, 92),
Student('stu4', 17, 93)
]
#all_student.sort()TypeError: '<' not supported between instances of 'Student' and 'Student'
# 解決方法1:
all_student.sort(key=lambda item: item.score)
print(all_student)
# 解決方法2:運(yùn)算符重載
print(stu1 < stu2)
# 還可以找出最大值:
print(max(all_student)) # <'name': 'stu4', 'age': 17, 'score': 93>
=================內(nèi)存管理==============
from sys import getrefcount
手動(dòng)內(nèi)存管理:
c語言:內(nèi)存分為棧區(qū)間和堆區(qū)間善涨,棧區(qū)間的內(nèi)存是自動(dòng)開辟自動(dòng)釋放蒂萎,堆區(qū)間的內(nèi)存需要程序員寫代碼申請(qǐng)和釋放
1.內(nèi)存的開辟:
python所有的數(shù)據(jù)都是對(duì)象让禀,對(duì)象都是保存在堆區(qū)間套么,變量是保存在棧區(qū)間最蕾,變量中實(shí)際存儲(chǔ)的是堆中對(duì)應(yīng)的數(shù)據(jù)的地址(變量的本質(zhì)就是指針)
注意:
如果數(shù)據(jù)是數(shù)字和字符串就屬于特殊情況:除了數(shù)字和字符串對(duì)象,其他的對(duì)象都是每次需要數(shù)據(jù)的時(shí)候直接在堆中開辟空間
數(shù)字和字符串會(huì)先檢查這個(gè)數(shù)據(jù)之前是否保存過源内,如果保存過就直接用之前的數(shù)據(jù)葡粒,否則才會(huì)開辟新的空間
num1 = 100
num2 = 100
print(id(num1), id(num2)) # 1385658480 1385658480 地址相同
2.內(nèi)存的釋放:
python中內(nèi)存的釋放采用的是'垃圾回收機(jī)制'自動(dòng)釋放
a.垃圾回收機(jī)制:
1)看一個(gè)數(shù)據(jù)是否需要銷毀,就看這個(gè)對(duì)象的引用計(jì)數(shù)是否為0(引用:就是看沒有其他變量或者數(shù)據(jù)在用它)
2)如果這個(gè)對(duì)象引用計(jì)數(shù)不為零膜钓,就臨時(shí)刪除一下他嗽交,然后看會(huì)不會(huì)有其他的對(duì)象因?yàn)樗南ФВ绻心蔷桶阉麄冋嬲膭h除
b.循環(huán)引用:
在堆區(qū)間兩個(gè)數(shù)據(jù)互相的引用颂斜,而沒有棧區(qū)間的變量引用他們夫壁,兩個(gè)數(shù)據(jù)互相引用,這種情況就屬于循環(huán)引用
釋放棧區(qū)間的變量只有用del來刪除釋放
面試題:== 和 is 的區(qū)別:
沃疮!補(bǔ)充:is 的使用 -- 判斷兩個(gè)數(shù)據(jù)的地址是否相等盒让,注意和 == 區(qū)分梅肤!
list1 = [1,2,3]
list2 = [1,2,3]
print(list1 == list2) True
print(list1 is list2) False
list1 = [1, 2, 3]
list2 = [1, 2, 3]
# 打印它的引用計(jì)數(shù)
print(getrefcount(list1)) # 2 問題:不是說除數(shù)字和字符串以外都會(huì)從新開辟數(shù)據(jù)空間嗎?list1 = [1,2,3] list2 = [1,2,3]
print(id(list1), id(list2))
list3 = list1
=============深拷貝和淺拷貝============
import copy
使用變量的三種情況:
1.直接賦值 - 附的是地址邑茄,賦完值后兩個(gè)變量一模一樣
變量1 = 變量2
如果對(duì)變量1數(shù)據(jù)進(jìn)行修改姨蝴,變量的數(shù)據(jù)也是會(huì)修改
list1 = [1, 2, 3]
list2 = list1
list1.remove(1) # 修改list1
print(list2) # [2, 3] 打印list2,數(shù)據(jù)也有變化
2.淺拷貝
copy.copy(原變量)
列表[:],列表.copy()都屬于淺拷貝
將數(shù)據(jù)復(fù)制一遍到一個(gè)新的內(nèi)存空間肺缕,有一個(gè)新的地址左医,將這個(gè)新地址賦給這個(gè)新的變量,但是如果這個(gè)數(shù)據(jù)還引用了子對(duì)象搓谆,那么這個(gè)復(fù)制出來的新對(duì)象還是引用的原來的那個(gè)子對(duì)象炒辉,豪墅!不會(huì)把子對(duì)象也復(fù)制一遍泉手!,所以有子對(duì)象的情況下改變子對(duì)象還是會(huì)影響原來的變量
class Student:
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
def __repr__(self):
return '<%s>' % str(self.__dict__)[1:-1]
stu1 = Student('tom', 18, 90)
stu2 = copy.copy(stu1)
stu2.name = 'bob'
print(stu1, stu2)
3.深拷貝
copy.deepcopy(原變量)
將數(shù)據(jù)復(fù)制一遍到一個(gè)新的內(nèi)存空間偶器,有一個(gè)新的地址斩萌,
將這個(gè)新地址賦給這個(gè)新的變量,但是如果這個(gè)數(shù)據(jù)還引用了子對(duì)象屏轰,會(huì)把子對(duì)象也復(fù)制一遍颊郎,所以完全不會(huì)影響原來的其他變量
stu3 = copy.deepcopy(stu1)