一、運算符重載
1. 運算符
python中所有的類型都是類,所以所有的數(shù)據(jù)都是對象
python中使用任意的運算符都是在調(diào)用對應類中的對應方法
每一個運算符對應的方法是固定的
某種數(shù)據(jù)是否支持某個運算符操作,由這個數(shù)據(jù)類型中是否實現(xiàn)了對應的方法決定
2. 運算符重載
在不同的類中實現(xiàn)同樣的運算符對應的函數(shù)
注意
:類的對象默認情況下只支持:==, !=
class Student:
def __init__(self, name, age, score=0):
self.name = name
self.age = age
self.score = score
# self -> 當前類的對象,也是運算符前的數(shù)據(jù)
# other -> 運算符后面的數(shù)據(jù),類型根據(jù)運算規(guī)則的設計可以是任何類型的數(shù)據(jù)
# a + b -> a.__add__(b)
def __add__(self, other):
# return self.age + other.age
# return self.score + other.score
# return self.score + other
return Student(self.name + other.name, self.age + other.age, self.score + other.score)
# a * b -> a.__mul__(b)
def __mul__(self, other: int):
list1 = []
for _ in range(other):
list1.append(copy.copy(self))
return list1
# a < b -> a.__lt__(b)
# 小于和大于符號只需要重載一個,另一個自動支持
def __lt__(self, other):
return self.score < other.score
# return [self for _ in range(other)]
# return Student(self.name * other, self.age * other, self.score * other)
def __repr__(self):
return ''.join(['<', str(self.__dict__)[1:-1], '>'])
stu1 = Student('小明', 19, 90)
stu2 = Student('小花', 20, 78)
print(stu1 + stu2)
print(stu1 * 3)
students = [stu1, stu2, Student('小紅', 12, 100)]
students.sort()
# students.sort(key=lambda x: x.score)
print(students)
print(stu1 < stu2, stu1 > stu2)
二、淺拷貝和深拷貝
class Dog:
def __init__(self, name, color):
self.name = name
self.color = color
def __repr__(self):
return '<{}>, id = {}'.format(str(self.__dict__)[1:-1], hex(id(self)))
class Person:
def __init__(self, name, age, dog=None):
self.name = name
self.age = age
self.dog = dog
def __repr__(self):
return '<{}>, id = {}'.format(str(self.__dict__)[1:-1], hex(id(self)))
1. 直接賦值
將變量中的地址直接賦值給新的變量,賦值后兩個變量的地址相同
p1 = Person('小明', 18, Dog('大黃', '黃色'))
p2 = p1
print(p1)
print(p2)
# <'name': '小明', 'age': 18, 'dog': <'name': '大黃', 'color': '黃色'>, id = 0x101d9f8d0>, id = 0x101d9f908
# <'name': '小明', 'age': 18, 'dog': <'name': '大黃', 'color': '黃色'>, id = 0x101d9f8d0>, id = 0x101d9f908
p1.name = '小花'
print(p1.name, p2.name) # 小花 小花
p2.dog.color = '綠色'
print(p1.dog.color) # 綠色
2. 拷貝
無論是淺拷貝還是深拷貝都會對原數(shù)據(jù)進行復制,產(chǎn)生新的地址
list1 = [1, 2, 3]
list2 = copy(list1)
list3 = deepcopy(list1)
print(id(list1), id(list2), id(list3)) # 4533504520 4533323464 4533504456
list1.append(100)
print(list2, list3) # [1, 2, 3] [1, 2, 3]
3. 淺拷貝
字符串、列表和元組的切片,對象.copy(),以及copy模塊中的copy()都是淺拷貝
淺拷貝只拷貝當前對象,不會對子對象進行拷貝
p3 = copy(p1)
print(id(p1), id(p3)) # 4564163104 4564163384
print(id(p1.dog), id(p3.dog)) # 4564163048 4564163048
p1.name = 'Tom'
print(p1.name, p3.name) # Tom 小花
p1.dog.color = '紅色'
print(p1.dog.color, p3.dog.color) # 紅色 紅色
4. 深拷貝
copy模塊中的deepcopy方法是深拷貝
p4 = deepcopy(p1)
print(id(p1), id(p4)) # 4364675728 4364730776
print(id(p1.dog), id(p4.dog)) # 4364675672 4364730496
p1.name = 'Jack'
print(p1.name, p4.name) # Jack Tom
p1.dog.color = '黑色'
print(p1.dog.color, p4.dog.color) # 黑色 紅色
三、枚舉
枚舉值的特點
1. 可以通過有意義的屬性名直接顯示數(shù)據(jù)
2. 每個數(shù)據(jù)的值不能修改
3. 可以做到不同數(shù)據(jù)的值唯一
from enum import Enum
from enum import unique
@unique
class PokerNum(Enum):
J = 11
Q = 12
K = 13
A = 1
print(PokerNum.J.name) # J
print(PokerNum.K.value, PokerNum.J.value > PokerNum.Q.value) # 13 False
四、內(nèi)存管理
1. 內(nèi)存的開辟
內(nèi)存區(qū)間分為棧區(qū)間和堆區(qū)間
棧區(qū)間的內(nèi)存自動開辟和釋放,堆區(qū)間的內(nèi)存需要程序員手動開辟和釋放,但在python中已經(jīng)將堆區(qū)間內(nèi)存的開辟和釋放過程自動化
當給變量賦值時,系統(tǒng)會先在堆區(qū)間中開辟空間將數(shù)據(jù)保存,然后再將數(shù)據(jù)在堆區(qū)的地址存到棧區(qū)間的變量中
數(shù)字和字符串數(shù)據(jù)在開辟空間時,會先檢查內(nèi)存中之前是否已經(jīng)有當前數(shù)據(jù),如果有則直接使用之前的數(shù)據(jù),沒有會開辟新的空間保存當前數(shù)據(jù)
2. 內(nèi)存的釋放
棧區(qū)間:全局棧區(qū)間在程序結(jié)束后銷毀,函數(shù)棧區(qū)間在函數(shù)調(diào)用結(jié)束后銷毀
堆區(qū)間:對象是否銷毀是由這個對象的引用計數(shù)決定的,如果一個對象的引用計數(shù)為零,這個對象就會銷毀(垃圾回收機制)
注意
:python中針對對象的循環(huán)引用已經(jīng)做了處理,程序員不需要針對循環(huán)引用問題寫額外的代碼