婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > Python進階學習之帶你探尋Python類的鼻祖-元類

Python進階學習之帶你探尋Python類的鼻祖-元類

熱門標簽:唐山智能外呼系統一般多少錢 廣告地圖標注app 激戰2地圖標注 白銀外呼系統 騰訊外呼線路 哈爾濱ai外呼系統定制 陜西金融外呼系統 海南400電話如何申請 公司電話機器人

Python是一門面向對象的語言,所以Python中數字、字符串、列表、集合、字典、函數、類等都是對象。

利用 type() 來查看Python中的各對象類型

In [11]: # 數字

In [12]: type(10)
Out[12]: int

In [13]: type(3.1415926)
Out[13]: float

In [14]: # 字符串

In [15]: type('a')
Out[15]: str

In [16]: type("abc")
Out[16]: str

In [17]: # 列表

In [18]: type(list)
Out[18]: type

In [19]: type([])
Out[19]: list

In [20]: # 集合

In [21]: type(set)
Out[21]: type

In [22]: my_set = {1, 2, 3}

In [23]: type(my_set)
Out[23]: set

In [24]: # 字典

In [25]: type(dict)
Out[25]: type

In [26]: my_dict = {'name': 'hui'}

In [27]: type(my_dict)
Out[27]: dict

In [28]: # 函數

In [29]: def func():
    ...:     pass
    ...:

In [30]: type(func)
Out[30]: function

In [31]: # 類

In [32]: class Foo(object):
    ...:     pass
    ...:

In [33]: type(Foo)
Out[33]: type

In [34]: f = Foo()

In [35]: type(f)
Out[35]: __main__.Foo

In [36]: # type

In [37]: type(type)
Out[37]: type

可以看出

數字 1int類型 的對象

字符串 abcstr類型 的對象

列表、集合、字典是 type類型 的對象,其創建出來的對象才分別屬于 list、set、dict 類型

函數 funcfunction類型 的對象

自定義類 Foo 創建出來的對象 fFoo 類型,其類本身 Foo 則是 type類型 的對象。

type 本身都是type類型的對象

一、類也是對象

類就是擁有相等功能和相同的屬性的對象的集合

在大多數編程語言中,類就是一組用來描述如何生成一個對象的代碼段。在 Python 中這一點仍然成立:

In [1]: class ObjectCreator(object):
   ...:     pass
   ...:

In [2]: my_object = ObjectCreator()

In [3]: print(my_object)
__main__.ObjectCreator object at 0x0000021257B5A248>

但是,Python中的類還遠不止如此。類同樣也是一種對象。是的,沒錯,就是對象。只要你 使用關鍵字 class,Python解釋器在執行的時候就會創建一個對象。

下面的代碼段:

>>> class ObjectCreator(object):
…       pass
…

將在內存中創建一個對象,名字就是 ObjectCreator。這個 對象(類對象ObjectCreator)擁有創建對象(實例對象)的能力。但是,它的本質仍然是一個對象,于是乎你可以對它做如下的操作:

1.你可以將它賦值給一個變量

2.你可以拷貝它

3.你可以為它增加屬性

4.你可以將它作為函數參數進行傳遞

如下示例:

In [39]: class ObjectCreator(object):
    ...:     pass
    ...:

In [40]: print(ObjectCreator)
class '__main__.ObjectCreator'>

In [41]:# 當作參數傳遞

In [41]: def out(obj):
    ...:     print(obj)
    ...:

In [42]: out(ObjectCreator)
class '__main__.ObjectCreator'>

In [43]: # hasattr 判斷一個類是否有某種屬性

In [44]: hasattr(ObjectCreator, 'name')
Out[44]: False

In [45]: # 新增類屬性

In [46]: ObjectCreator.name = 'hui'

In [47]: hasattr(ObjectCreator, 'name')
Out[47]: True

In [48]: ObjectCreator.name
Out[48]: 'hui'

In [49]: # 將類賦值給變量

In [50]: obj = ObjectCreator

In [51]: obj()
Out[51]: __main__.ObjectCreator at 0x212596a7248>

In [52]:

二、動態地創建類

因為類也是對象,你可以在運行時動態的創建它們,就像其他任何對象一樣。首先,你可以在函數中創建類,使用 class 關鍵字即可。

def cls_factory(cls_name):
    """
    創建類工廠
    :param: cls_name 創建類的名稱
    """
    if cls_name == 'Foo':
        class Foo():
            pass
        return Foo  # 返回的是類,不是類的實例

    elif cls_name == 'Bar':
        class Bar():
            pass
        return Bar

IPython 測驗

MyClass = cls_factory('Foo')

In [60]: MyClass
Out[60]: __main__.cls_factory.locals>.Foo # 函數返回的是類,不是類的實例

In [61]: MyClass()
Out[61]: __main__.cls_factory.locals>.Foo at 0x21258b1a9c8>

但這還不夠動態,因為你仍然需要自己編寫整個類的代碼。由于類也是對象,所以它們必須是通過什么東西來生成的才對。

當你使用class關鍵字時,Python解釋器自動創建這個對象。但就和Python中的大多數事情一樣,Python仍然提供給你手動處理的方法。

三、使用 type 創建類

type 還有一種完全不同的功能,動態的創建類。

type可以接受一個類的描述作為參數,然后返回一個類。(要知道,根據傳入參數的不同,同一個函數擁有兩種完全不同的用法是一件很傻的事情,但這在Python中是為了保持向后兼容性)

type 可以像這樣工作:

type(類名, 由父類名稱組成的元組(針對繼承的情況,可以為空),包含屬性的字典(名稱和值))

比如下面的代碼:

In [63]: class Test:
    ...:     pass
    ...:

In [64]: Test()
Out[64]: __main__.Test at 0x21258b34048>

In [65]:

可以手動像這樣創建:

In [69]:# 使用type定義類

In [69]: Test2 = type('Test2', (), {})

In [70]: Test2()
Out[70]: __main__.Test2 at 0x21259665808>

我們使用 Test2 作為類名,并且也可以把它當做一個變量來作為類的引用。類和變量是不同的,這里沒有任何理由把事情弄的復雜。即 type函數 中第1個實參,也可以叫做其他的名字,這個名字表示類的名字

In [71]: UserCls = type('User', (), {})

In [72]: print(UserCls)
class '__main__.User'>

In [73]:

使用 help 來測試這2個類

In [74]: # 用 help 查看 Test類

In [75]: help(Test)
Help on class Test in module __main__:

class Test(builtins.object)
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)


In [76]: # 用 help 查看 Test2類

In [77]: help(Test2)
Help on class Test2 in module __main__:

class Test2(builtins.object)
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)


In [78]:

四、使用type創建帶有屬性的類

type 接受一個字典來為類定義屬性,因此

Parent = type('Parent', (), {'name': 'hui'})

可以翻譯為:

class Parent(object):
	name = 'hui'

并且可以將 Parent 當成一個普通的類一樣使用:

In [79]: Parent = type('Parent', (), {'name': 'hui'})

In [80]: print(Parent)
class '__main__.Parent'>

In [81]: Parent.name
Out[81]: 'hui'

In [82]: p = Parent()

In [83]: p.name
Out[83]: 'hui'

當然,你可以繼承這個類,代碼如下:

class Child1(Parent):
    name = 'jack'
    sex =  '男'
    
class Child2(Parent):
    name = 'mary'
    sex = '女'

就可以寫成:

Child1 = type('Child1', (Parent, ), {'name': 'jack', 'sex': '男'})

In [85]: Child2 = type('Child2', (Parent, ), {'name': 'mary', 'sex': '女'})

In [87]: Child1.name, Child1.sex
Out[87]: ('jack', '男')

In [88]: Child2.name, Child2.sex
Out[88]: ('mary', '女')

注意:

  • type 的第2個參數,元組中是父類的名字,而不是字符串
  • 添加的屬性是 類屬性,并不是實例屬性

五、使用type創建帶有方法的類

最終你會希望為你的類增加方法。只需要定義一個有著恰當簽名的函數并將其作為屬性賦值就可以了。

添加實例方法

Child1 = type('Child1', (Parent, ), {'name': 'jack', 'sex': '男'})

In [85]: Child2 = type('Child2', (Parent, ), {'name': 'mary', 'sex': '女'})

In [87]: Child1.name, Child1.sex
Out[87]: ('jack', '男')

In [88]: Child2.name, Child2.sex
Out[88]: ('mary', '女')

添加靜態方法

In [96]: Parent = type('Parent', (), {'name': 'hui'})

In [97]: # 定義靜態方法
    
In [98]: @staticmethod
    ...: def test_static():
    ...:     print('static method called...')
    ...:

In [100]: Child4 = type('Child4', (Parent, ), {'name': 'zhangsan', 'test_static': test_static})

In [101]: c4 = Child4()

In [102]: c4.test_static()
static method called...

In [103]: Child4.test_static()
static method called...

添加類方法

In [105]: Parent = type('Parent', (), {'name': 'hui'})

In [106]: # 定義類方法

In [107]: @classmethod
     ...: def test_class(cls):
     ...:     print(cls.name)
     ...:

In [108]: Child5 = type('Child5', (Parent, ), {'name': 'lisi', 'test_class': test_class})

In [109]: c5 = Child5()

In [110]: c5.test_class()
lisi

In [111]: Child5.test_class()
lisi

你可以看到,在Python中,類也是對象,你可以動態的創建類。這就是當你使用關鍵字 classPython 在幕后做的事情,就是通過元類來實現的。

較為完整的使用 type 創建類的方式:

class Animal(object):
    
    def eat(self):
        print('吃東西')


def dog_eat(self):
    print('喜歡吃骨頭')

def cat_eat(self):
    print('喜歡吃魚')


Dog = type('Dog', (Animal, ), {'tyep': '哺乳類', 'eat': dog_eat})

Cat = type('Cat', (Animal, ), {'tyep': '哺乳類', 'eat': cat_eat})

# ipython 測驗
In [125]: animal = Animal()

In [126]: dog = Dog()

In [127]: cat = Cat()

In [128]: animal.eat()
吃東西

In [129]: dog.eat()
喜歡吃骨頭

In [130]: cat.eat()
喜歡吃魚

六、到底什么是元類(終于到主題了)

元類就是用來創建類的【東西】。你創建類就是為了創建類的實例對象,不是嗎?但是我們已經學習到了Python中的類也是對象。

元類就是用來創建這些類(對象)的,元類就是類的類,你可以這樣理解為:

MyClass = MetaClass() # 使用元類創建出一個對象,這個對象稱為“類”
my_object = MyClass() # 使用“類”來創建出實例對象

你已經看到了type可以讓你像這樣做:

MyClass = type('MyClass', (), {})

這是因為函數 type 實際上是一個元類。type 就是 Python在背后用來創建所有類的元類?,F在你想知道那為什么 type 會全部采用小寫形式而不是 Type 呢?好吧,我猜這是為了和 str 保持一致性,str是用來創建字符串對象的類,而 int 是用來創建整數對象的類。type 就是創建類對象的類。你可以通過檢查 __class__ 屬性來看到這一點。因此 Python中萬物皆對象

現在,對于任何一個 __class____class__ 屬性又是什么呢?

In [136]: a = 10

In [137]: b = 'acb'

In [138]: li = [1, 2, 3]

In [139]: a.__class__.__class__
Out[139]: type

In [140]: b.__class__.__class__
Out[140]: type

In [141]: li.__class__.__class__
Out[141]: type

In [142]: li.__class__.__class__.__class__
Out[142]: type

因此,元類就是創建類這種對象的東西。type 就是 Python的內建元類,當然了,你也可以創建自己的元類。

七、metaclass屬性

你可以在定義一個類的時候為其添加 __metaclass__ 屬性。

class Foo(object):
    __metaclass__ = something…
    ...省略...

如果你這么做了,Python就會用元類來創建類Foo。小心點,這里面有些技巧。你首先寫下 class Foo(object),但是類Foo還沒有在內存中創建。Python會在類的定義中尋找 __metaclass__ 屬性,如果找到了,Python就會用它來創建類Foo,如果沒有找到,就會用內建的 type 來創建這個類。

class Foo(Bar):
    pass

Python做了如下的操作:

1.Foo中有 __metaclass__ 這個屬性嗎?如果有,Python會通過 __metaclass__ 創建一個名字為Foo的類(對象)

2.如果Python沒有找到 __metaclass__,它會繼續在 Bar(父類) 中尋找 __metaclass__ 屬性,并嘗試做和前面同樣的操作。

3.如果Python在任何父類中都找不到 __metaclass__,它就會在模塊層次中去尋找 __metaclass__,并嘗試做同樣的操作。

4.如果還是找不到 __metaclass__ ,Python就會用內置的 type 來創建這個類對象。

現在的問題就是,你可以在 __metaclass__ 中放置些什么代碼呢?

答案就是:可以創建一個類的東西。那么什么可以用來創建一個類呢?type,或者任何使用到type或者子類化的type都可以。

八、自定義元類

元類的主要目的就是為了當創建類時能夠自動地改變類。

假想一個很傻的例子,你決定在你的模塊里所有的類的屬性都應該是大寫形式。有好幾種方法可以辦到,但其中一種就是通過在模塊級別設定 __metaclass__。采用這種方法,這個模塊中的所有類都會通過這個元類來創建,我們只需要告訴元類把所有的屬性都改成大寫形式就萬事大吉了。

幸運的是,__metaclass__ 實際上可以被任意調用,它并不需要是一個正式的類。所以,我們這里就先以一個簡單的函數作為例子開始。

python2中

# -*- coding:utf-8 -*-
def upper_attr(class_name, class_parents, class_attr):

    # class_name 會保存類的名字 Foo
    # class_parents 會保存類的父類 object
    # class_attr 會以字典的方式保存所有的類屬性

    # 遍歷屬性字典,把不是__開頭的屬性名字變為大寫
    new_attr = {}
    for name, value in class_attr.items():
        if not name.startswith("__"):
            new_attr[name.upper()] = value

    # 調用type來創建一個類
    return type(class_name, class_parents, new_attr)

class Foo(object):
    __metaclass__ = upper_attr # 設置Foo類的元類為upper_attr
    bar = 'bip'

print(hasattr(Foo, 'bar'))
# Flase
print(hasattr(Foo, 'BAR'))
# True

f = Foo()
print(f.BAR)

python3中

# -*- coding:utf-8 -*-
def upper_attr(class_name, class_parents, class_attr):

    #遍歷屬性字典,把不是__開頭的屬性名字變為大寫
    new_attr = {}
    for name,value in class_attr.items():
        if not name.startswith("__"):
            new_attr[name.upper()] = value

    #調用type來創建一個類
    return type(class_name, class_parents, new_attr)

# 再類的繼承()中使用metaclass
class Foo(object, metaclass=upper_attr):
    bar = 'bip'

print(hasattr(Foo, 'bar'))
# Flase
print(hasattr(Foo, 'BAR'))
# True

f = Foo()
print(f.BAR)

再做一次,這一次用一個真正的 class 來當做元類。

class UpperAttrMetaClass(type):
    
    def __new__(cls, class_name, class_parents, class_attr):
        # 遍歷屬性字典,把不是__開頭的屬性名字變為大寫
        new_attr = {}
        for name, value in class_attr.items():
            if not name.startswith("__"):
                new_attr[name.upper()] = value

        # 方法1:通過'type'來做類對象的創建
        return type(class_name, class_parents, new_attr)

        # 方法2:復用type.__new__方法
        # 這就是基本的OOP編程,沒什么魔法
        # return type.__new__(cls, class_name, class_parents, new_attr)

        
# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
    bar = 'bip'

# python2的用法
class Foo(object):
	__metaclass__ = UpperAttrMetaClass
    bar = 'bip'


print(hasattr(Foo, 'bar'))
# 輸出: False
print(hasattr(Foo, 'BAR'))
# 輸出: True

f = Foo()
print(f.BAR)
# 輸出: 'bip'

__new__ 是在__init__之前被調用的特殊方法
__new__是用來創建對象并返回之的方法
而__init__只是用來將傳入的參數初始化給對象
這里,創建的對象是類,我們希望能夠自定義它,所以我們這里改寫__new__

就是這樣,除此之外,關于元類真的沒有別的可說的了。但就元類本身而言,它們其實是很簡單的:

1.攔截類的創建

2.修改類

3.返回修改之后的類

總結

現在回到我們的大主題上來,究竟是為什么你會去使用這樣一種容易出錯且晦澀的特性?

好吧,一般來說,你根本就用不上它:

“元類就是深度的魔法,99%的用戶應該根本不必為此操心。如果你想搞清楚究竟是否需要用到元類,那么你就不需要它。那些實際用到元類的人都非常清楚地知道他們需要做什么,而且根本不需要解釋為什么要用元類。” —— Python界的領袖 Tim Peters

到此這篇關于Python進階學習之帶你探尋Python類的鼻祖-元類的文章就介紹到這了,更多相關Python元類內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Python中的Nonetype類型怎么判斷
  • python數據類型相關知識擴展
  • 一篇文章帶你搞懂Python類的相關知識
  • 用 Python 元類的特性實現 ORM 框架
  • 詳細總結Python類的多繼承知識
  • python 使用Tensorflow訓練BP神經網絡實現鳶尾花分類
  • Python-typing: 類型標注與支持 Any類型詳解
  • python中必會的四大高級數據類型(字符,元組,列表,字典)
  • Python如何把不同類型數據的json序列化
  • Python基礎之元類詳解
  • Python入門學習之類的相關知識總結

標簽:四川 惠州 黑龍江 黔西 常德 鷹潭 益陽 上海

巨人網絡通訊聲明:本文標題《Python進階學習之帶你探尋Python類的鼻祖-元類》,本文關鍵詞  Python,進階,學,習之,帶你,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Python進階學習之帶你探尋Python類的鼻祖-元類》相關的同類信息!
  • 本頁收集關于Python進階學習之帶你探尋Python類的鼻祖-元類的相關信息資訊供網民參考!
  • 推薦文章
    主站蜘蛛池模板: 岳普湖县| 高雄市| 江口县| 布尔津县| 安吉县| 都兰县| 曲沃县| 元朗区| 永修县| 沈丘县| 霸州市| 抚顺市| 崇阳县| 黑龙江省| 开封县| 吉木萨尔县| 乐昌市| 扎鲁特旗| 仁布县| 合水县| 黄龙县| 泽普县| 伊金霍洛旗| 麦盖提县| 紫阳县| 隆德县| 湘潭县| 个旧市| 原阳县| 通化市| 察隅县| 慈溪市| 临桂县| 乌恰县| 五大连池市| 海南省| 丹棱县| 顺平县| 博客| 临朐县| 繁昌县|