029_Python知識點_面向對象進階_元類&抽象基類&自省機制&slots

1. 元類

1.1 理解類、對象

Python中一切皆對象。 --> 所以類也是對象 --> 那麼,誰創建了類? --> 元類
元類:類的類,也就是類的模板。元類的實例爲類,正如類的實例爲對象。

  • 分支語句動態創建類:結合分支語句等,使用class關鍵字動態的創建類。當使用class關鍵字時,Python解釋器自動創建這個對象。
  • type函數動態創建類:
    • type函數功能一:判斷對象的類型。–> eg:type('abc')
    • type函數功能二:動態的創建類。type可以接受一個類的描述作爲參數,然後返回一個類。
# type函數創建類:
# 語法:type(函數名, (父類, ), {屬性, 函數, ...})
def hello():
    print("--hello--")

myclass = type("MyClass", (object, ), {'my_args': 'haha', 'hello': hello})
print(myclass.my_args)
myclass.hello()

1.2 元類的使用場景

元類的使用:

  1. 攔截類的創建
  2. 修改類
  3. 返回修改之後的類

動態生成類,不能控制類是如何生成的。python3 的metaclass可動態創建類。
4). 很多Web框架都會使用metaclass 來創建類。掌握元類對理解源代碼至關重要。eg: ORM框架類

應用:自定義元類實現單例模式

class Singleton(type):
    """自定義元類實現單例模式"""
    cache = {}
    def __call__(cls):
        if cls not in cls.cache:
            cls.cache[cls] = super(Singleton, cls).__call__()
        return cls.cache[cls]

class Person(object, metaclass=Singleton):  # metaclass一個指定元類的參數
    pass

if __name__ == '__main__':
	# 注意:Person是Singleton元類實例化出的對象, Person()就是對象(), 執行Singleton.__call__魔術方法.
    p1 = Person()
    p2 = Person()
    print("單例模式是否成功:", p1 is p2)

2. 抽象基類

抽象基類有兩個特點:

  1. 規定繼承類 (子類) 必須具有抽象基類中指定的方法,即用@abc.abstractmethod裝飾的方法
  2. 抽象基類無法實例化

基於上述兩個特點,抽象基類主要用於接口設計
實現抽象基類可以使用內置的abc模塊
代碼示例:

import abc

class Human(metaclass=abc.ABCMeta):
    # 該裝飾器規定:繼承抽象類的子類在定義時必須要定義的抽象方法
    @abc.abstractmethod
    def introduce(self):
        print("__抽象類__")
	
	# 因爲沒有@abc.abstractmethod裝飾器,在子類中hello方法不是必須的
    def hello(self):
        print("__hello__")

class Person(Human):
    # 1. 規定子類中必須具有抽象基類指定的方法
    def introduce(self):
        print("__子類__抽象類__")

# 2. 抽象基類無法實例化
# TypeError: Can't instantiate abstract class Human with abstract methods introduce
# h = Human()

p = Person()
p.introduce()

3. 自省機制

自省機制:

  1. 在日常生活中,自省 (introspection) 是一種自我檢查行爲。
  2. 在計算機編程中,自省是指這種能力:檢查某些事物以確定它是什麼、它知道什麼以及它能做什麼。自省向程序員提供了極大的靈活性和控制力。
  3. 例如Python、Ruby、object-C、C++都有自省的能力,這裏面的C++的自省的能力最弱,只能夠知道是什麼類型,而像Python可以知道是什麼類型,還有什麼屬性。

Python中常見的自省機制:
函數用法有: dir()、type()、hasattr(),、setattr()、getattr()、delattr()、isinstance(),通過這些函數,我們能夠在程序運行時得知對象的類型,判斷對象是否存在某個屬性,訪問對象的屬性。

>>> s = "abc"
# 1. 查看 s 的全面屬性和方法
>>> dir(s) 
['__add__',
 '__class__',
 '__contains__',
 '__delattr__',
 ...
 'translate',
 'upper',
 'zfill']
 
 # 2. 返回對象類型
>>> type(s)
str

 # 3. 判斷對象類型,返回bool值
>>> isinstance(s, str)
True

>>> def hello():
   ...:     pass
# 4. 設置對象屬性,如 hello.name = 'xiaohong'
>>> setattr(hello, "name", "xiaohong")

# 5. 判斷對象中是否包含某個屬性,返回bool值
>>> hasattr(hello, "name")
True

# 6. 獲取對象中的某個屬性值
>>> getattr(hello, "name")
'xiaohong'

# 7. 刪除對象中的某個屬性
>>> delattr(hello, "name")
>>> hasattr(hello, "name")
False

4. __slots__

Python是動態語言,動態語言與靜態語言的不同之處是:

  1. 動態語言:可以在運行的過程中,修改代碼
  2. 靜態語言:編譯時已經確定好代碼,運行過程中不能修改

如何要限制實例中的屬性

  1. Python允許在定義class的時候,定義一個特殊的 __slots__變量,來限制該class實例能添加的屬性。
  2. 使用__slots__要注意,__slots__定義的屬性僅對當前類實例起作用,對繼承的子類是不起作用的

代碼示例:

import time

class Date(object):
	# 限制示例中能夠添加的屬性有:'__year', '__month', '__day'
    __slots__ = '__year', '__month', '__day'

    def __init__(self, year, month, day):
        self.__year = year
        self.__month = month
        self.__day = day

    @property
    def year(self):
        return self.__year

    @property
    def month(self):
        return self.__month

    @property
    def day(self):
        return self.__day

    @classmethod
    def today(cls):
        time_tuple = time.localtime()
        return cls(time_tuple.tm_year, time_tuple.tm_mon, time_tuple.tm_mday)  # 返回實例化對象

    def __str__(self):
        return "%s-%s-%s" % (self.year, self.month, self.day)


if __name__ == '__main__':
    date = Date(2020, 1, 4)
    print("date數據類型: ", type(date))
    print("date有year屬性嗎?", hasattr(date, "year"))
    print("date有time屬性嗎?", hasattr(date, "time"))
    # setattr(date, "time", "2020-11-11") # AttributeError: 'Date' object has no attribute 'time'
    # print(getattr(date, "time"))
    today = date.today()
    print("today數據類型: ", type(today))
    # print("今天是%s年%s月的第%s天" % (today.year, today.month, today.day))
    print(today)

執行結果:
在這裏插入圖片描述

發佈了49 篇原創文章 · 獲贊 0 · 訪問量 6642
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章