python元類深入理解

来源:https://www.cnblogs.com/jiaojianglong/archive/2019/07/28/11260944.html
-Advertisement-
Play Games

1.python 中的類 在python中,類也是一個對象,只不過這個對象擁有生成實例的能力,我們一般使用class XXX來定義一個類,在python解釋器執行到這個地方的時候會自動創建出這個對象,python也為我們提供了手動創建類的方法,type()。type()這個方法對我們來說並不陌生,我 ...


1.python 中的類

在python中,類也是一個對象,只不過這個對象擁有生成實例的能力,我們一般使用class XXX來定義一個類,在python解釋器執行到這個地方的時候會自動創建出這個對象,python也為我們提供了手動創建類的方法,type()。type()這個方法對我們來說並不陌生,我們所熟知的用法是:class = type(instance),當傳入一個參數時,type()返回這個參數的類。而今天我們要用到的是type的另一個功能。type("classname",(object,),{"name":"jiao"})。當給type傳入三個參數時,就是一個手動創建類的方式。

class A():
    def __init__(self,name):
        self.name = name
        print("創建了一個實例")

a = type("a",(A,),{"name":"jiao"}) 
print(a)              #<class '__main__.a'>
print(a.name)          #jiao
print(a("jiang"))      #創建了一個實例  
                        #<__main__.a object at 0x00000280A973AA58>

 

type接收三個參數分別是:

classname: 要創建的class 的名稱

object:要創建類的父類所組成的元組

sttr_dict: 要創建類的屬性

type返回一個class,我們接收並賦值到一個變數上,現在這個變數就指向我們所創建的類,我們可以通過這個變數來使用類。

 

2.python 中的type

在python 中,幾乎所有的東西都是對象,這包括整數、字元串、函數以及類。它們全部都是對象,而且它們都是從一個類創建而來——type

3.__metaclass__屬性

python在創建類時,會按照如下的流程進行:

 

Foo中有__metaclass__這個屬性嗎?如果是,Python會在記憶體中通過__metaclass__創建一個名字為Foo的類對象(我說的是類對象,請緊跟我的思路)。如果Python沒有找到__metaclass__,它會繼續在Bar(父類)中尋找__metaclass__屬性,並嘗試做和前面同樣的操作。如果Python在任何父類中都找不到__metaclass__,它就會在模塊層次中去尋找__metaclass__,並嘗試做同樣的操作。如果還是找不到__metaclass__,Python就會用內置的type來創建這個類對象。

那麼在__metaclass__中放置什麼樣的代碼可以創建類呢?type,或者任何使用到type或者子類化type的東東都可以。

 

4.自定義元類

class UpperAttrMetaClass(type):
    def __new__(cls,class_name,class_parents,class_attr, *args, **kwargs):
        print("__new__")
        class_attr['name'] = "jiao"
        return type.__new__(cls,class_name,class_parents,class_attr)

    def __init__(self,*args,**kwargs):
        print("__init__")
        super().__init__(*args, **kwargs)
        self.__cache = {}

    def __call__(self, *args, **kwargs):
        print("__call__")
        if args in self.__cache:
            return self.__cache[args]
        else:
            obj = super().__call__(*args)
            self.__cache[args] = obj
            return obj


class A(metaclass=UpperAttrMetaClass):
    def __init__(self,name):
        self.name = name
        print("a.__init__")

 

 

5.類的創建流程

1.元類的__new__(),返回創建好的類。當我們想要改變創建方式的時候就要重寫這個方法。

2.元類的__init__(),初始化一些類的屬性

 

6.實例創建流程

1.元類的__call__(),創建一個實例時,首先調用這個方法,返回創建好的實例,所以我們可以通過改寫這個方法來改變實例創建過程,比如實現單例模式

2.類的__init__(),初始化實例屬性

 

7.元類的應用

1.單例模式

class Singleton(type):
    def __init__(cls,*args,**kwargs):
        cls.__instance = None
        super().__init__(*args,**kwargs)

    def __call__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__call__(*args,**kwargs)
            return cls.__instance
        else:
            return cls.__instance

class Spam(metaclass=Singleton):
    def __init__(self):
        print("Creating Spam")

 

2.緩存模式
import weakref

class Cached(type):
    def __init__(cls,*args,**kwargs):
        super().__init__(*args,**kwargs)
        cls.__cache = weakref.WeakValueDictionary()

    def __call__(cls, *args, **kwargs):
        if args in cls.__cache:
            return cls.__cache[args]
        else:
            obj = super().__call__(*args)
            cls.__cache[args] = obj
            return obj


class Spams(metaclass=Cached):
    def __init__(self,name):
        print("Creating Spam({!r})".format(name))
        self.name = name

 

3.獲取屬性的定義順序

 

能過獲取到屬性的定義順序,我們就可以通過簡單的方法實現屬性到數據的映射,可以更加簡單的將類中的屬性數據化。

from collections import OrderedDict

class Typed:
    _excepted_type = type(None)

    def __init__(self,name=None):
        self._name = name

    def __set__(self, instance, value):
        if not isinstance(value,self._excepted_type):
            raise TypeError("Excepted"+str(self._excepted_type))
        instance.__dict__[self._name] = value

class Integer(Typed):
    _excepted_type = int

class Float(Typed):
    _excepted_type = float

class String(Typed):
    _excepted_type = str

class OrderedMeta(type):

    def __new__(cls, clsname,bases,clsdict):
        d = dict(clsdict)
        order = []
        for name,value in clsdict.items():
            if isinstance(value,Typed):
                value._name = name
                order.append(name)
                d['_order'] = order
       return type.__new__(cls,clsname,bases,d)

    @classmethod
    def __prepare__(metacls, name, bases):
        return OrderedDict()

#註:__prepare__該方法會在類定義一開始的時候調用,調用時以類名和基類名稱作為參數,它必須返回一個映射對象,供處理類定義體時調用


#eg.
class Structure(metaclass=OrderedMeta):

    def as_csv(self):
        return ','.join(str(getattr(self,name)) for name in self._order)

class Stock(metaclass=OrderedMeta):
    name = String()
    shares = Integer()
    price = Float()
    def __init__(self,name,shares,price):
        self.name = name
        self.shares = shares
        self.price = price

s = Stock("haha",23,23.3)
print(s.name)
s = Stock(34,23,34)
# print(s.as_csv())

 

 

8.小結

元類主要就是在類和實例創建的時候發揮作用,來實現一些功能。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一個可以沉迷於技術的程式猿,wx加入加入技術群:fsx641385712 ...
  • 1.字元串的定義 可以使用""雙引號,也可以使用''單引號定義字元串,一般使用雙引號定義。 2.字元串的操作 判斷類型: 查找和替換 大小寫切換: 文本對齊 註:string.center(weight,str) 以str填充對齊,其他兩個方法類似,都可以拓展。 去除空白字元 拆分和鏈接 3.字元串 ...
  • 新聞 "Fantomas 3.0" "宣告.NET Core 3.0預覽版7" ".NET Core 3.0預覽版7中ASP.NET Core與Blazor的升級" "Visual Studio 2019版本16.2正式版本與16.3預覽版1" "Mac上的Visual Studio 2019版本8 ...
  • 1.數組: java.lang.ArrayIndexOutOfBoundsException:5 下標越界異常 java.lang.NullPointerException 空指針異常 arr.length獲取數組長度 數組存儲的是多個數,數據的操作離不開迴圈2數組初始化:int[] arr=new ...
  • 一、Gateway 和 Zuul 的區別 Zuul 基於servlet 2.5 (works with 3.x),使用阻塞API。它不支持任何長期的連接,如websocket。 Gateway建立在Spring Framework 5,Project Reactor 和Spring Boot 2 上 ...
  • ReadWriteLock介面 讀寫鎖維護一對關聯鎖,一個只用於讀操作,一個只用於寫操作。讀鎖可以由多個線程同時持有,又稱共用鎖。寫鎖同一時間只能由一個線程持有,又稱互斥鎖。同一時間,兩把鎖不能被不同線程持有。讀寫鎖適合讀取操作多於寫入操作的場景,改進互斥鎖的性能,比如集合的併發安全性改造,緩存組件 ...
  • 1.元組的定義 Tuple (元組)與列表類似,元組的元素 不能修改 元組通常保存 不同類型 的數據 元組用()定義 info_tuple = ("張三", 18, 1.75) 定義 元組名 = (元素1, 元素2, 元素3) 2.元組的創建 空元組 元組名 = () ,很少使用,因為定義後,元組無 ...
  • # 元組。關鍵字:tuple# 定義好了,就不可以修改。只能讀。數據之間全部都是用,隔開。# 定義:()my_tuple = () # 空元組my_tuple2 = ("xj","female",18,170)# 定義方式二my_tuple3 = "hello","python","class17" ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...