python中幾個常見的魔法方法


首先,什么是魔法方法呢?在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法。

__ init__()方法

  • 當一個實例被創建的時候調用的初始化方法,在創建對象時默認調用。
  • __ init __()方法中默認有一個參數名字為self,如果在創建對象時傳遞了2個參數,那么__init __()方法除了self作為第一個形參外還需要2個形參,例如__init __(self,x,y)。

之前我們是這樣給對象添加屬性的:

class Student:
	pass
	
stu1 = Student()

stu1.name = "張三"
stu1.age = 18

現在我們利用__init__()方法簡化代碼

class Student:
	def __init__(self, name, age):
		self.name = name
		self.age = age
	
stu1 = Student("張三", 18)

是不是代碼看起來簡潔多了呢

__str __()方法

  • 一般用於說明對象,或者自己定義一個想要輸出的結果。
  • 當調用str()時會調用__str __(),即該對象被強制轉換成字符串類型。
  • 當使用print()輸出該對象時也會調用__str __()方法,只要自己定義了__str __()方法,那么就會打印這個方法中return中的數據。

沒有定義__str __()方法時:

class Student:
	def __init__(self, name, age):
		self.name = name
		self.age = age
	
stu1 = Student("張三", 18)
print(stu1)

s = str(stu1)
print(s)

"""
輸出結果:
<__main__.Student object at 0x03C3BCD0>
<__main__.Student object at 0x03C3BCD0>
"""

沒有定義__str __()方法時,它默認返回該對象的內存地址。
定義了__str __()方法是這樣的:

class Student:
	def __init__(self, name, age):
		self.name = name
		self.age = age
	def __str__(self):
		return "姓名:%s\t年齡:%d"%(self.name, self.age)
	
stu1 = Student("張三", 18)
print(stu1)

s = str(stu1)
print(s)

"""
輸出結果:
姓名:張三	年齡:18
姓名:張三	年齡:18
"""

__del __()方法

當刪除一個對象時,python解釋器會默認調用一個方法,這個方法為__del__()方法。
首先應該先了解一個概念,那就是對象的引用個數。我們需要sys模塊中的getrefcount()用來測量一個對象的引用個數,返回值=實際的引用個數+1。若返回2則說明該對象的實際引用個數為1,此時有1個變量引用了該對象。

import sys
class A:
	pass
a = A()
# 現在只有變量a引用了A類創建的對象
print(sys.getrefcount(a))
"""
輸出結果:
2
"""
# 那么現在再創建一個變量b,也引用a所引用的對象,那么它的引用個數就會加1,實際引用個數變成2.
b = a
print(sys.getrefcount(a))
"""
輸出結果:
3
"""

當python解釋器檢測到,這個對象的實際引用個數為0時,就會刪除這個對象,此時也就會相應的調用__del __()方法。還有一種情況就是該程序已經全部執行完了,那么相應的內存會被釋放掉,它也會執行__del __()方法。
這是程序正常執行完的情況:

import sys
class A:
	def __del__(self):
		print("該對象被銷毀")
a = A()
"""
輸出結果:
該對象被銷毀
"""

還有一種是手動刪除變量引用的情況:

import sys
class A:
	def __del__(self):
		print("該對象被銷毀")
a = A() # 此時實際引用個數為1
b = a # 此時實際引用個數為2

print("刪除了變量a") 
del a # 刪除變量a,此時實際引用個數為1

print("刪除了變量b") 
del b # 刪除變量b,此時實際引用個數為0,python解釋器就會刪除該對象,即調用__del __()方法
print("程序結束")
"""
輸出結果:
刪除了變量a
刪除了變量b
該對象被銷毀
程序結束
"""

__new __()方法

  • __new __也是類在創建實例時調用的方法,它比__init __調用的時間還早。
  • __new __至少要有一個參數cls,代表要實例化的類,此參數在實例化時由python解釋器自動提供。
  • __new __必須要有返回值,返回實例化出來的實例,這點在自己實現__new__時要特別注意,可以return父類__new__出來的實例,或者直接是object的__new__出來的實例。在Python3中每個類都默認繼承的object父類。
  • __init__有一個參數self,就是這個__new__返回的實例,__init__在__new__的基礎上可以完成一些其它初始化的動作,__init__不需要返回值
class A:
    def __init__(self):
        print("調用了init方法")

    def __new__(cls):
        print("調用了new方法")
        return super().__new__(cls)
a = A()

"""
輸出結果:
調用了new方法
調用了init方法
"""

拓展:可以通過重寫__new __方法,實現一個單例模式

代碼如下:

class A:
	# 定義一個私有的類屬性,用於存儲實例化出來的對象
    _isinstance = None
    
    def __new__(cls):
        print("調用了new方法")
        # 判斷如果_isinstance為None,則創建一個實例,否則直接返回_isinstance
        if not cls._isinstance:
            cls._isinstance = super().__new__(cls)
        return cls._isinstance


print(id(A))
print(id(A))
print(id(A))
print(id(A))
"""
輸出結果:
19888488
19888488
19888488
19888488
"""

__slots __屬性

我們都知道python是一門動態語言,可以在程序運行的過程中添加屬性。如果我們想要限制實例的屬性該怎么辦?例如,只允許對Person實例添加name和age屬性。
為了達到限制的⽬的,Python允許在定義class的時候,定義⼀個特殊的 __slots__變量,來限制該class實例能添加的屬性:

class Person(object):
	__slots__ = ("name", "age") 
P = Person() 
P.name = "⽼王" 
P.age = 20 
P.score = 100 

"""
輸出結果:
Traceback (most recent call last):
  File "<input>", line 6, in <module>
AttributeError: 'Person' object has no attribute 'score'
"""

注意:使⽤__slots__要注意,__slots__定義的屬性僅對當前類實例起作⽤,對 繼承的⼦類是不起作⽤的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM