Day 01——Task01:變量、運算符與數據類型
Day 02——Task02:條件與循環
Day 03——Task03:列表與元組(上)
Day 04——Task03:列表與元組(下)
Day 05——Task04:字符串與序列
Day 06——Task05:函數與Lambda表達式(上)
Day 07——Task05:函數與Lambda表達式(下)
Day 08——Task06:字典與集合
Day 09——Task07:文件與文件系統(上)
Day 10——Task07:文件與文件系統(下)
Day 11——Task08:異常處理
Day 12——Task09:else 與 with 語句
Day 13——Task10:類與對象(上)
Day 14——Task10:類與對象(下)
Day 15——Task11:魔法方法(上)
Day 16——Task11:魔法方法(下)
Day 17——Task12:模塊
文章目錄
1. 基礎語法
魔法方法總是被雙下劃線包圍,例如__init__
。
魔法方法是面向對象的 Python 的一切,如果你不知道魔法方法,說明你還沒能意識到面向對象的 Python 的強大。
魔法方法的“魔力”體現在它們總能夠在適當的時候被自動調用。
魔法方法的第一個參數應爲cls
(類方法) 或者self
(實例方法)。
-
cls
:代表一個類的名稱 -
self
:代表一個實例對象的名稱
2.魔法方法
2.1. 基本的魔法方法
2.1.1 __init__(self[, ...])
- 構造器,當一個實例被創建的時候調用的初始化方法
class Rectangle:
def __init__(self, x, y):
self.x = x
self.y = y
def getPeri(self):
return (self.x + self.y) * 2
def getArea(self):
return self.x * self.y
rect = Rectangle(4, 5)
print(rect.getPeri()) # 18
print(rect.getArea()) # 20
2.1.2 __new__(cls[, ...])
__new__
是在一個對象實例化的時候所調用的第一個方法,在調用__init__
初始化前,先調用__new__
。__new__
至少要有一個參數cls,代表要實例化的類,此參數在實例化時由 Python 解釋器自動提供,後面的參數直接傳遞給__init__
。__new__
對當前類進行了實例化,並將實例返回,傳給__init__
的self
。但是,執行了__new__
,並不一定會進入__init__
,只有__new__
返回了,當前類cls的實例,當前類的__init__
纔會進入。
class A(object):
def __init__(self, value):
print("into A __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into A __new__")
print(cls)
return object.__new__(cls)
class B(A):
def __init__(self, value):
print("into B __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into B __new__")
print(cls)
return super().__new__(cls, *args, **kwargs)
b = B(10)
# 結果:
# into B __new__
# <class '__main__.B'>
# into A __new__
# <class '__main__.B'>
# into B __init__
class A(object):
def __init__(self, value):
print("into A __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into A __new__")
print(cls)
return object.__new__(cls)
class B(A):
def __init__(self, value):
print("into B __init__")
self.value = value
def __new__(cls, *args, **kwargs):
print("into B __new__")
print(cls)
return super().__new__(A, *args, **kwargs) # 改動了cls變爲A
b = B(10)
# 結果:
# into B __new__
# <class '__main__.B'>
# into A __new__
# <class '__main__.A'>
- 若
__new__
沒有正確返回當前類cls的實例,那__init__
是不會被調用的,即使是父類的實例也不行,將沒有__init__
被調用。 - 可利用
__new__
實現單例模式。
class Earth:
pass
a = Earth()
print(id(a)) # 260728291456
b = Earth()
print(id(b)) # 260728291624
class Earth:
__instance = None # 定義一個類屬性做判斷
def __new__(cls):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance
else:
return cls.__instance
a = Earth()
print(id(a)) # 512320401648
b = Earth()
print(id(b)) # 512320401648
__new__
方法主要是當你繼承一些不可變的class
時(比如int
,str
,tuple
), 提供給你一個自定義這些類的實例化過程的途徑。
class CapStr(str):
def __new__(cls, string):
string = string.upper()
return str.__new__(cls, string)
a = CapStr("i love lsgogroup")
print(a) # I LOVE LSGOGROUP
2.1.3 __del__(self)
- 析構器,當一個對象將要被系統回收之時調用的方法。
Python 採用自動引用計數(ARC)方式來回收對象所佔用的空間,當程序中有一個變量引用該 Python 對象時,Python 會自動保證該對象引用計數爲 1;當程序中有兩個變量引用該 Python 對象時,Python 會自動保證該對象引用計數爲 2,依此類推,如果一個對象的引用計數變成了 0,則說明程序中不再有變量引用該對象,表明程序不再需要該對象,因此 Python 就會回收該對象。
大部分時候,Python 的 ARC 都能準確、高效地回收系統中的每個對象。但如果系統中出現循環引用的情況,比如對象 a 持有一個實例變量引用對象 b,而對象 b 又持有一個實例變量引用對象 a,此時兩個對象的引用計數都是 1,而實際上程序已經不再有變量引用它們,系統應該回收它們,此時 Python 的垃圾回收器就可能沒那麼快,要等專門的循環垃圾回收器(Cyclic Garbage Collector)來檢測並回收這種引用循環。
class C(object):
def __init__(self):
print('into C __init__')
def __del__(self):
print('into C __del__')
c1 = C()
# into C __init__
c2 = c1
c3 = c2
del c3
del c2
del c1
# into C __del__
2.1.4 __str__ 和 __repr__
__str__(self)
:
- 當你打印一個對象的時候,觸發
__str__
- 當你使用%s格式化的時候,觸發
__str__
- str強轉數據類型的時候,觸發
__str__
__repr__(self)
:
- repr是str的備胎
- 有
__str__
的時候執行__str__
,沒有實現__str__
的時候,執行__repr__
- repr(obj)內置函數對應的結果是
__repr__
的返回值 - 當你使用%r格式化的時候 觸發
__repr__
class Cat:
"""定義一個貓類"""
def __init__(self, new_name, new_age):
"""在創建完對象之後 會自動調用, 它完成對象的初始化的功能"""
self.name = new_name
self.age = new_age
def __str__(self):
"""返回一個對象的描述信息"""
return "名字是:%s , 年齡是:%d" % (self.name, self.age)
def __repr__(self):
"""返回一個對象的描述信息"""
return "Cat:(%s,%d)" % (self.name, self.age)
def eat(self):
print("%s在喫魚...." % self.name)
def drink(self):
print("%s在喝可樂..." % self.name)
def introduce(self):
print("名字是:%s, 年齡是:%d" % (self.name, self.age))
# 創建了一個對象
tom = Cat("湯姆", 30)
print(tom) # 名字是:湯姆 , 年齡是:30
print(str(tom)) # 名字是:湯姆 , 年齡是:30
print(repr(tom)) # Cat:(湯姆,30)
tom.eat() # 湯姆在喫魚....
tom.introduce() # 名字是:湯姆, 年齡是:30
__str__(self)
的返回結果可讀性強。也就是說,__str__
的意義是得到便於人們閱讀的信息,就像下面的 ‘2019-10-11’ 一樣。
__repr__(self)
的返回結果應更準確。怎麼說,__repr__
存在的目的在於調試,便於開發者使用。
import datetime
today = datetime.date.today()
print(str(today)) # 2019-10-11
print(repr(today)) # datetime.date(2019, 10, 11)
print('%s' %today) # 2019-10-11
print('%r' %today) # datetime.date(2019, 10, 11)
2.2. 算術運算符
類型工廠函數
,指的是不通過類而是通過函數來創建對象。
class C:
pass
print(type(len)) # <class 'builtin_function_or_method'>
print(type(dir)) # <class 'builtin_function_or_method'>
print(type(int)) # <class 'type'>
print(type(list)) # <class 'type'>
print(type(tuple)) # <class 'type'>
print(type(C)) # <class 'type'>
print(int('123')) # 123
# 這個例子中list工廠函數把一個元祖對象加工成了一個列表對象。
print(list((1, 2, 3))) # [1, 2, 3]
2.2.1.__add__
和__sub__
__add__(self, other)
定義加法的行爲:+
__sub__(self, other)
定義減法的行爲:-
class MyClass:
def __init__(self, height, weight):
self.height = height
self.weight = weight
# 兩個對象的長相加,寬不變.返回一個新的類
def __add__(self, others):
return MyClass(self.height + others.height, self.weight + others.weight)
# 兩個對象的寬相減,長不變.返回一個新的類
def __sub__(self, others):
return MyClass(self.height - others.height, self.weight - others.weight)
# 說一下自己的參數
def intro(self):
print("高爲", self.height, " 重爲", self.weight)
def main():
a = MyClass(height=10, weight=5)
a.intro()
b = MyClass(height=20, weight=10)
b.intro()
c = b - a
c.intro()
d = a + b
d.intro()
if __name__ == '__main__':
main()
# 高爲 10 重爲 5
# 高爲 20 重爲 10
# 高爲 10 重爲 5
# 高爲 30 重爲 15
2.2.2. 其他的操作符
魔法方法 | 含義 |
---|---|
__mul__(self, other) |
定義乘法的行爲:* |
__truediv__(self, other) |
定義真除法的行爲:/ |
__floordiv__(self, other) |
定義整數除法的行爲:// |
__mod__(self, other) |
定義取模算法的行爲:% |
__divmod__(self, other) |
定義當被 divmod() 調用時的行爲 |
divmod(a, b) |
把除數和餘數運算結果結合起來,返回一個包含商和餘數的元組(a // b, a % b)。 |
__pow__(self, other[, module]) |
定義當被power() 調用或** 運算時的行爲 |
__lshift__(self, other) |
定義按位左移位的行爲:<< |
__rshift__(self, other) |
定義按位右移位的行爲:>> |
__and__(self, other) |
定義按位與操作的行爲:& |
__xor__(self, other) |
定義按位異或操作的行爲:^ |
__or__(self, other) |
定義按位或操作的行爲:| |
2.3. 反算術運算符
反運算魔方方法
,與算術運算符保持一一對應,不同之處就是反運算的魔法方法多了一個“r”。當文件左操作不支持相應的操作時被調用。
|魔法方法| 含義 |
|–|--|
|__radd__(self, other)
|定義加法的行爲:+
|__rsub__(self, other)
|定義減法的行爲:-
|__rmul__(self, other)
|定義乘法的行爲:*
|__rtruediv__(self, other)
|定義真除法的行爲:/
|__rfloordiv__(self, other)
|定義整數除法的行爲://
|__rmod__(self, other)
|定義取模算法的行爲:%
|__rdivmod__(self, other)
|定義當被divmod()
調用時的行爲
|__rpow__(self, other[, module])
|定義當被power()
調用或**
運算時的行爲
|__rlshift__(self, other)
|定義按位左移位的行爲:<<
|__rrshift__(self, other)
|定義按位右移位的行爲:>>
|__rand__(self, other)
|定義按位與操作的行爲:&
|__rxor__(self, other)
|定義按位異或操作的行爲:^
|__ror__(self, other)
|定義按位或操作的行爲:|
舉個栗子:a + b
這裏加數是a
,被加數是b
,因此是a
主動,反運算就是如果a
對象的__add__()
方法沒有實現或者不支持相應的操作,那麼 Python 就會調用b
的__radd__()
方法。
class Nint(int):
def __radd__(self, other):
return int.__sub__(other, self) # 注意 self 在後面
a = Nint(5)
b = Nint(3)
print(a + b) # 8
print(1 + b) # -2
2.4. 增量賦值運算符
魔法方法 | 含義 |
---|---|
__iadd__(self, other) |
定義賦值加法的行爲:+= |
__isub__(self, other) |
定義賦值減法的行爲:-= |
__imul__(self, other) |
定義賦值乘法的行爲:*= |
__itruediv__(self, other) |
定義賦值真除法的行爲:/= |
__ifloordiv__(self, other) |
定義賦值整數除法的行爲://= |
__imod__(self, other) |
定義賦值取模算法的行爲:%= |
__ipow__(self, other[, modulo]) |
定義賦值冪運算的行爲:**= |
__ilshift__(self, other) |
定義賦值按位左移位的行爲:<<= |
__irshift__(self, other) |
定義賦值按位右移位的行爲:>>= |
__iand__(self, other) |
定義賦值按位與操作的行爲:&= |
__ixor__(self, other) |
定義賦值按位異或操作的行爲:^= |
__ior__(self, other) |
定義賦值按位或操作的行爲:|= |
2.5. 一元運算符
魔法方法 | 含義 |
---|---|
__neg__(self) |
定義正號的行爲:+x |
__pos__(self) |
定義負號的行爲:-x |
__abs__(self) |
定義當被abs() 調用時的行爲 |
__invert__(self) |
定義按位求反的行爲:~x |
參考資料
- https://blog.csdn.net/LSGO_MYP/article/details/102887712
- https://www.runoob.com/python3/python3-tutorial.html
- https://www.bilibili.com/video/av4050443
- http://c.biancheng.net/view/2371.html
- https://www.cnblogs.com/seablog/p/7173107.html
- https://www.cnblogs.com/Jimmy1988/p/6804095.html
- https://blog.csdn.net/johnsonguo/article/details/585193