最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python中類創(chuàng)建和實例化的過程詳解

 更新時間:2024年06月03日 09:14:21   作者:王二空間  
這篇文章主要介紹了Python中類創(chuàng)建和實例化過程,文中通過代碼示例講解的非常詳細,對大家的學(xué)習或工作有一定的幫助,需要的朋友可以參考下

一、 type()

1、創(chuàng)建類的兩種方式

方式一

class MyClass(object):
    def func(self,name):
        print(name)
 
myc = MyClass()
 
print(MyClass, type(MyClass))
print(myc, type(myc))

我們創(chuàng)建了一個名為MyClass的類,并實例化了這個類,得到其對象myc

上面代碼打印的結(jié)果為:

<class '__main__.MyClass'>    <class 'type'>
<__main__.MyClass object at 0x0288F8F0>   <class '__main__.MyClass'>

type()函數(shù)可以查看一個類型或變量的類型,MyClass是一個class,它的類型就是type,而myc是一個實例,它的類型就是class MyClass。

我們說class的定義是運行時動態(tài)創(chuàng)建的,而創(chuàng)建class的方法就是使用type()函數(shù)。

type()函數(shù)既可以返回一個對象的類型,又可以創(chuàng)建出新的類型,比如,我們可以通過type()函數(shù)創(chuàng)建出MyClass類,而無需通過Class MyClass(object)...的定義:

方式二

動態(tài)創(chuàng)建類
type(類名, 父類的元組(針對繼承的情況,可以為空),包含屬性的字典(名稱和值))

def fn(self, name='world'): # 先定義函數(shù)
    print('Hello, %s.' % name)
 
MyClass = type('MyClass', (object,), {'func':fn}) # 創(chuàng)建MyClass類,得到一個type的類對象
# MyClass = type('MyClass', (object,), {'func':lambda self,name:name}) # 創(chuàng)建MyClass類
 
myc=MyClass()
 
print(MyClass, type(MyClass))
print(myc, type(myc))

打印結(jié)果:

<class '__main__.MyClass'>   <class 'type'>
<__main__.MyClass object at 0x0364B830>   <class '__main__.MyClass'>

要創(chuàng)建一個class對象,type()函數(shù)依次傳入3個參數(shù):

  • class的名稱;
  • 繼承的父類集合,注意Python支持多重繼承,如果只有一個父類,別忘了tuple的單元素寫法;
  • class的方法名稱與函數(shù)綁定,這里我們把函數(shù)fn綁定到方法名func上。

通過type()函數(shù)創(chuàng)建的類和直接寫class是完全一樣的,因為Python解釋器遇到class定義時,僅僅是掃描一下class定義的語法,然后調(diào)用type()函數(shù)創(chuàng)建出class。

type就是創(chuàng)建類對象的類。你可以通過檢查__class__屬性來看到這一點。Python中所有的東西,注意,我是指所有的東西——都是對象。這包括整數(shù)、字符串、函數(shù)以及類。它們?nèi)慷际菍ο螅宜鼈兌际菑囊粋€類(元類,默認為type,也可以自定制)創(chuàng)建而來。type也是由type創(chuàng)建。

二、元類(metaclass)

除了使用type()動態(tài)創(chuàng)建類以外,要控制類的創(chuàng)建行為,還可以使用metaclass。

metaclass,直譯為元類,簡單的解釋就是:

當我們定義了類以后,就可以根據(jù)這個類創(chuàng)建出實例,所以:先定義類,然后創(chuàng)建實例。

但是如果我們想創(chuàng)建出類呢?那就必須根據(jù)metaclass創(chuàng)建出類,所以:先定義元類(不自定義時,默認用type),然后創(chuàng)建類。

連接起來就是:先定義metaclass,就可以創(chuàng)建類,最后創(chuàng)建實例。

所以,metaclass允許你創(chuàng)建類或者修改類。換句話說,你可以把類看成是元類創(chuàng)建出來的“實例”。

默認情況下,類是使用type()構(gòu)造的。類主體在一個新的名稱空間中執(zhí)行,類名在本地綁定到類型的結(jié)果(名稱、基、名稱空間)。

可以通過在類定義行中傳遞元類關(guān)鍵字參數(shù)來定制類創(chuàng)建過程,或者從包含此類參數(shù)的現(xiàn)有類繼承。在下面的示例中,MyClass和MySubclass都是Meta的實例:

class Meta(type):
    pass
 
class MyClass(metaclass=Meta):
    pass
 
class MySubclass(MyClass):
    pass

使用metaclass的兩種方式

class MyType(type):  # 自定義一個type的派生類
    def __init__(self,*args,**kwargs):
    print('xx')
       super(MyType,self).__init__(*args,**kwargs)
 
    def __call__(cls, *args, **kwargs):
        obj = cls.__new__(cls,*args, **kwargs)
        cls.__init__(obj,*args, **kwargs)
        return obj
 
def with_metaclass(base):
    return MyType("MyType2",(base,),{})
 
# 方式一
class Foo(metaclass=MyType):  # metaclass=MyType,即指定了由MyType創(chuàng)建Foo類,當程序運行,用到class Foo時,即調(diào)用MyType的__init__方法,創(chuàng)建Foo類
    def __init__(self,name):
        self.name = name
 
 
#方式二    在Flask的wtform的源碼中用到過
# class Foo(with_metaclass(object)):
#     def __init__(self,name):
#         self.name = name
 
 
a=Foo('name')
 

方式一:即用類的形式

執(zhí)行代碼后,當遇到class Foo時即聲明要創(chuàng)建一個Foo類,就會調(diào)用type的__init__方法創(chuàng)建類,由于此處(metaclass=MyType),即指定了Foo類的創(chuàng)建方式,所以會執(zhí)行type的派生類MyType的__init__方法,創(chuàng)建Foo類,打印一次'xx'

  • 一般情況下, 如果你要用類來實現(xiàn)metaclass的話,該類需要繼承于type,而且通常會重寫type的__new__方法來控制創(chuàng)建過程。

  • 在metaclass里面定義的方法會成為類的方法,可以直接通過類名來調(diào)用

方式二:用函數(shù)的形式

構(gòu)建一個函數(shù),返回一個type的派生類對象,例如叫type的派生類, 需要3個參數(shù):name, bases, attrs

  • name: 類的名字
  • bases: 基類,通常是tuple類型
  • attrs: dict類型,就是類的屬性或者函數(shù)

metaclass 原理

1.基礎(chǔ)

metaclass的原理其實是這樣的:當定義好類之后,創(chuàng)建類的時候其實是調(diào)用了type的__new__方法為這個類分配內(nèi)存空間,創(chuàng)建好了之后再調(diào)用type的__init__方法初始化(做一些賦值等)。所以metaclass的所有magic其實就在于這個__new__方法里面了。

說說這個方法:__new__(cls, name, bases, attrs)

  • cls: 將要創(chuàng)建的類,類似與self,但是self指向的是instance,而這里cls指向的是class

  • name: 類的名字,也就是我們通常用類名.__name__獲取的。

  • bases: 基類

  • attrs: 屬性的dict。dict的內(nèi)容可以是變量(類屬性),也可以是函數(shù)(類方法)。

所以在創(chuàng)建類的過程,我們可以在這個函數(shù)里面修改name,bases,attrs的值來自由的達到我們的功能。這里常用的配合方法是

getattr和setattr(just an advice)

2.查找順序

元類是由以下優(yōu)先規(guī)則決定的:

如果“元類”存在,它就被使用了。

否則,如果至少有一個基類,則使用它的元類(這首先查找類屬性,如果沒有找到,則使用它的類型)。

否則,如果一個名為元類的全局變量存在,就會使用它。

三、 __init__,__new__,__call__三個特殊方法

  • __new__: 對象的創(chuàng)建,是一個靜態(tài)方法,第一個參數(shù)是cls。(想想也是,不可能是self,對象還沒創(chuàng)建,哪來的self),其必須要有返回值,返回實例化出來的實例,需要注意的是,可以return父類__new__()出來的實例,也可以直接將object的__new__()出來的實例返回。

  • __init__ : 對象的初始化, 是一個實例方法,第一個參數(shù)是self,該self參數(shù)就是__new__()返回的實例,__init__()__new__()的基礎(chǔ)上可以完成一些其它初始化的動作,__init__()不需要返回值。

  • __call__: 對象可call,注意不是類,是對象。

1.對于__new__

class Bar(object):
    pass
 
class Foo(object):
    def __new__(cls, *args, **kwargs):
        return Bar()
 
print(Foo()) 

打印結(jié)果為:

<__main__.Bar object at 0x0090F930>

可以看到,輸出來是一個Bar對象。

__new__方法在類定義中不是必須寫的,如果沒定義,默認會調(diào)用object.__new__去創(chuàng)建一個對象。如果定義了,就是會覆蓋,使用自定義的,這樣就可以自定制創(chuàng)建對象的行為。

2.對于__init__

class Person(object):
 
  def __init__(self, name, age):
    self.name = name
    self.age = age
    print('執(zhí)行__init__')
 
  def __new__(cls, *args, **kwargs):
      obj = object.__new__(cls) # 創(chuàng)建對象
      print('執(zhí)行__new__方法')
      return obj
 
p1 = Person('hc', 24)
print(p1)

打印結(jié)果:

執(zhí)行__new__方法
執(zhí)行__init__
<__main__.Person object at 0x028EB830>

__init__方法通常用在初始化一個類實例的時候,但__init__其實不是實例化一個類的時候第一個被調(diào)用 的方法。當使用 Persion(name, age) 這樣的表達式來實例化一個類時,最先被調(diào)用的方法 其實是 __new__ 方法。從打印結(jié)果就可以看出來

若__new__()沒有正確返回當前類cls的實例,那__init__()將不會被調(diào)用,即使是父類的實例也不行。

3.對于__call__

對象通過提供__call__(slef, *args ,**kwargs)方法可以模擬函數(shù)的行為,如果一個對象x提供了該方法,就可以像函數(shù)一樣使用它,也就是說x(arg1, arg2...) 等同于調(diào)用x.__call__(self, arg1, arg2)

class Foo(object): 
  def __call__(self): 
    pass 
#學(xué)習中遇到問題沒人解答?小編創(chuàng)建了一個Python學(xué)習交流群:153708845 
f = Foo()    #類(),即執(zhí)行元類的__call__
f()    #對象(),即執(zhí)行Foo的__call__ 

4、實例化對象的完整過程

class Foo(Bar):
    pass

當我們寫如這段代碼時,Python做了如下的操作:

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

把上面這段話反復(fù)讀幾次,現(xiàn)在的問題就是,你可以在metaclass中放置些什么代碼呢?

答案就是:可以創(chuàng)建一個類的東西。

那么什么可以用來創(chuàng)建一個類呢?

type,或者任何使用到type或者子類化type的東東都可以。

以上面的代碼為例,我們實例化一個對象obj=Foo()時,會先執(zhí)行Foo類的__new__方法,沒寫時,用父類的__new__方法,創(chuàng)建一個對象,并返回,然后執(zhí)行__init__方法(自己有就用自己的,沒有就用父類的),對創(chuàng)建的對象進行初始化。

obj()會執(zhí)行Foo類的__call__方法,沒有則用父類的

我們現(xiàn)在已經(jīng)知道,類也是對象,是元類的對象,即我們實例化一個類時,調(diào)用其元類的__call__方法。

元類處理過程:定義一個類時,使用聲明或者默認的元類對該類進行創(chuàng)建,對元類求type運算,得到父元類(該類聲明的元類的父元類),調(diào)用父元類的__call__函數(shù),在父元類的__call__函數(shù)中, 調(diào)用該類聲明的元類的__new__函數(shù)來創(chuàng)建對象(該函數(shù)需要返回一個對象(指類)實例),然后再調(diào)用該元類的__init__初始化該對象(此處對象是指類,因為是元類創(chuàng)建的對象),最終返回該類

1.對象是類創(chuàng)建,創(chuàng)建對象時候類的__init__方法自動執(zhí)行,對象()執(zhí)行類的__call__方法
2.類是type創(chuàng)建,創(chuàng)建類時候type的__init__方法自動執(zhí)行,類() 執(zhí)行type的__call__方法(類的__new__方法,類的__init__方法)

原始type的__call__應(yīng)該是參數(shù)結(jié)構(gòu)應(yīng)該是:

metaname, clsname, baseclasses, attrs

原始type的__new__

metaname, clsname, baseclasses, attrs

原始type的__init__

class_obj, clsname, baseclasses, attrs

元類的__new__和__init__影響的是創(chuàng)建類對象的行為,父元類的__call__控制對子元類的 __new__,__init__的調(diào)用,就是說控制類對象的創(chuàng)建和初始化。父元類的__new__和__init__由更上層的控制,

一般來說,原始type是最初的父元類,其__new__和__init__是具有普遍意義的,即應(yīng)該是分配內(nèi)存、初始化相關(guān)信息等

元類__call__影響的是創(chuàng)建類的實例對象的行為,此時如果類自定義了__new__和__init__就可以控制類的對象實例的創(chuàng)建和初始化

__new__和__init__影響的是創(chuàng)建對象的行為,當這些函數(shù)在元類中時,影響創(chuàng)建的是類;同理,當這倆個函數(shù)在普通類中時,影響創(chuàng)建的是普通的對象實例。

__call__影響()調(diào)用行為, __call__是在創(chuàng)建類的時候調(diào)用,即: class Test(object): __metaclass__=type, 定義類時就是創(chuàng)建類,此時會調(diào)用元類的__call__,如果元類有繼承,子元類定義時執(zhí)行的是父元類的__call__。
如果是普通類實例化對象,調(diào)用的是普通類的__call__

以上就是Python中類創(chuàng)建和實例化的過程詳解的詳細內(nèi)容,更多關(guān)于Python類創(chuàng)建和實例化的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用Matplotlib將圖片保存為.tiff格式

    使用Matplotlib將圖片保存為.tiff格式

    這篇文章主要介紹了使用Matplotlib將圖片保存為.tiff格式問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Python安裝jieba庫詳細教程

    Python安裝jieba庫詳細教程

    jieba庫是一款優(yōu)秀的 Python 第三方中文分詞庫,jieba 支持三種分詞模式:精確模式、全模式和搜索引擎模式,這篇文章主要介紹了Python安裝jieba庫教程,需要的朋友可以參考下
    2023-03-03
  • 簡單講解Python中的數(shù)字類型及基本的數(shù)學(xué)計算

    簡單講解Python中的數(shù)字類型及基本的數(shù)學(xué)計算

    這篇文章主要介紹了Python中的數(shù)字類型及基本的數(shù)學(xué)計算,與其他語言一樣,除法相對復(fù)雜些,不過本文并未就此深入,需要的朋友可以參考下
    2016-03-03
  • Tensorflow2.10使用BERT從文本中抽取答案實現(xiàn)詳解

    Tensorflow2.10使用BERT從文本中抽取答案實現(xiàn)詳解

    這篇文章主要為大家介紹了Tensorflow2.10使用BERT從文本中抽取答案實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • Python?OpenCV實現(xiàn)圖形檢測示例詳解

    Python?OpenCV實現(xiàn)圖形檢測示例詳解

    圖形檢測在計算機視覺開發(fā)中是一項非常重要的操作,算法通過對圖像的檢測,分析出圖像中可能存在哪些形狀。本文詳細介紹了Python+OpenCV如何實現(xiàn)圖形檢測,感興趣的可以了解一下
    2022-04-04
  • 一文詳解Python中哈希表的使用

    一文詳解Python中哈希表的使用

    哈希表或稱為散列表,是一種常見的、使用頻率非常高的數(shù)據(jù)存儲方案。本文將站在開發(fā)者的角度,帶著大家一起探究哈希的世界,感興趣的小伙伴可以跟隨小編一起學(xué)習一下
    2022-05-05
  • 淺談python和C語言混編的幾種方式(推薦)

    淺談python和C語言混編的幾種方式(推薦)

    下面小編就為大家?guī)硪黄獪\談python和C語言混編的幾種方式(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • Python decimal模塊使用方法詳解

    Python decimal模塊使用方法詳解

    這篇文章主要介紹了Python decimal模塊使用方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友可以參考下
    2020-06-06
  • Python辦公自動化實戰(zhàn)之打造智能郵件發(fā)送工具

    Python辦公自動化實戰(zhàn)之打造智能郵件發(fā)送工具

    在數(shù)字化辦公場景中,郵件自動化是提升工作效率的關(guān)鍵技能,本文將演示如何使用Python的smtplib和email庫構(gòu)建一個支持圖文混排,多附件,多收件人的智能郵件系統(tǒng)
    2025-07-07
  • Python實現(xiàn)石頭剪刀布游戲

    Python實現(xiàn)石頭剪刀布游戲

    這篇文章主要為大家詳細介紹了Python實現(xiàn)石頭剪刀布游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-01-01

最新評論

芦山县| 邵武市| 海丰县| 嵊泗县| 黄龙县| 宜川县| 水富县| 怀安县| 鲁山县| 松滋市| 高州市| 霞浦县| 虹口区| 临汾市| 伊宁市| 彭阳县| 若尔盖县| 丘北县| 长沙县| 泰来县| 秦安县| 祥云县| 邵武市| 共和县| 德江县| 沅江市| 丰台区| 广南县| 原平市| 娄底市| 曲周县| 屏南县| 绥江县| 都安| 当阳市| 洛隆县| 廊坊市| 百色市| 延边| 沅陵县| 丹棱县|