『無為則無心』Python面向對象 — 60、魔法屬性

Python 類中,凡是以雙下劃線 “__” 開頭和結尾命名的成員(屬性和方法),這些特殊成員存在著一些特殊含義,都被稱為類的特殊成員(特殊屬性和特殊方法)。

我們把特殊屬性也可以稱之為魔法屬性,或者內置類屬性。

1、魔法屬性__name__

__name__是用來標識模組名字的一個系統變數。

這裡分兩種情況:

  • 第一種情況指的是當前運行的模組,那麼當前模組__name__的值就為__main__
  • 第二種情況指的是該模組是使用import導入的模組,那麼這個被導入模組的__name__變數的值為該模組的文件名(去掉.py)。

示例:

Demo1.py文件:

# 在當前文件中直接調用__name__屬性
def my_func():
    print("我的模組名是", __name__)


# __name__屬性在模組中可直接調用
# 在當期模組中調用
# 結果:我的模組名是 __main__
if __name__ == "__main__":
    my_func()

Demo2.py文件:

# 導入Demo1模組,使用模組中的my_func()方法
from Demo1 import *

# 執行my_func()方法
# 結果:我的模組名是 Demo1
my_func()

2、魔法屬性__bases__

Python 為所有類都提供了一個__bases__屬性,通過該屬性可以查看該類的所有直接父類,該屬性返回所有直接父類組成的元組。(直接父類)

class A(object):
    pass


class B(A):
    pass


class C(B):
    pass


class D(C,B,A):
    pass

# 類名直接調用__bases__屬性
print(C.__bases__)
print(D.__bases__)
"""
輸出結果:
(<class '__main__.B'>,)
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>)
"""

注意:在類的實例對象中沒有__bases__屬性。

3、魔法屬性__mro__

Python的每一個有父類的類,都有一個與方法解析順序相關的特殊屬性__mro__屬性, 它是一個tuple(元組), 裝著方法解析時的對象查找順序,越靠前的優先順序越高。

執行下面的程式碼:

class A(object):
    pass


class B(A):
    pass


class C(B):
    pass


# 類名直接調用__bases__屬性
print(C.__bases__)
print(C.__mro__)
"""
輸出結果:
(<class '__main__.B'>,)
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
"""

說明:__mro__屬性和__bases__屬性的區別。

__bases__屬性是查看當前類的直接父類,返回一個元組。

__mro__屬性是指在有繼承關係中,包括單繼承,多重繼承,多層繼承中。使用super調用父類的方法和屬性的時候,優先查找的順序。

4、魔法屬性__doc__

作用:表示類的描述文檔資訊。

class Person:
    """
    這裡是類的描述類資訊。
    """

    def func(self):
        """
         這裡是類中方法的描述類資訊。
        """
        pass

# 因為是屬性,不用加()
print(Person.__doc__)

輸出結果:

image

5、魔法屬性__module__ __class__

__module__ 屬性:表示當前操作的對象屬於哪個模組。

__class__屬相:表示當前操作的對象的是由哪個類創建的。

# 定義一個類
class Person(object):
    pass


obj = Person()
print(obj.__module__)
print(obj.__class__)
"""
輸出結果:
__main__ : 表示前擋模組
<class '__main__.Person'> : 表示該對象屬於當前模組中的Python類
"""

6、魔法屬性__dict__

列出類中或者對象中的所有成員,以字典的形式返回。這個屬性不用我們再類中覆寫,類和對象默認自帶。

class Person(object):

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def tellMe(self):
        print(f'我叫{self.name},今年{self.age}')


# 獲取類的所有成員
print(Person.__dict__)

# # 獲取對象的所有成員
obj1 = Person('美猴王', "18")
obj2 = Person('齊天大聖', "30")
print(obj1.__dict__)
print(obj2.__dict__)
"""
輸出結果 : 

類的所有成員:
{'__module__': '__main__', 
    '__init__': <function Person.__init__ at 0x0000000002425828>, 
    'tellMe': <function Person.tellMe at 0x0000000002425A68>, 
    '__dict__': <attribute '__dict__' of 'Person' objects>,
     '__weakref__': <attribute '__weakref__' of 'Person' objects>, 
     '__doc__': None}
注意:__weakref__,和垃圾回收機制,還有弱引用的知識點有關。

對象的所有成員:
{'name': '美猴王', 'age': '18'}
{'name': '齊天大聖', 'age': '30'}

"""

注意:從上面的結果可以看出,對象調用__dict__屬性,沒有看到對象中的方法。

  • 類的實例屬性屬於對象,類的實例方法不屬於對象。也就是說__dict__屬性不列印處對象的中方法。
  • 類中的類屬性和方法等都屬於類。

7、魔法屬性__slots__

Python是動態語言,對於普通的類,可以為類的實例對象賦值任何屬性,這些屬性會存儲在__dict__中。

而類中定義了__slots__屬性,它僅允許動態綁定__slots__裡邊定義的屬性。

示例:

# 創建一個Student類
class Student():
    # 定義__slots__
    __slots__ = ('name', 'age')


# 創建一個學生對象
stu = Student()
# 動態添加__slots__屬性中定義的屬性,可以添加
stu.name = '孫悟空'
stu.age = 18

# 而__slots__屬性中沒有定義的屬性,是添加不了的。
# 結果:AttributeError: 'Student' object has no attribute 'addr'
stu.addr = "北京"