1. 程式人生 > 其它 >『無為則無心』Python面向物件 — 60、魔法屬性

『無為則無心』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__)

輸出結果:

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 = "北京"