亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python中類(lèi)創(chuàng)建和實(shí)例化的過(guò)程詳解

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

一、 type()

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

方式一

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

我們創(chuàng)建了一個(gè)名為MyClass的類(lèi),并實(shí)例化了這個(gè)類(lèi),得到其對(duì)象myc

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

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

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

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

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

方式二

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

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

打印結(jié)果:

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

要?jiǎng)?chuàng)建一個(gè)class對(duì)象,type()函數(shù)依次傳入3個(gè)參數(shù):

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

通過(guò)type()函數(shù)創(chuàng)建的類(lèi)和直接寫(xiě)class是完全一樣的,因?yàn)镻ython解釋器遇到class定義時(shí),僅僅是掃描一下class定義的語(yǔ)法,然后調(diào)用type()函數(shù)創(chuàng)建出class。

type就是創(chuàng)建類(lèi)對(duì)象的類(lèi)。你可以通過(guò)檢查_(kāi)_class__屬性來(lái)看到這一點(diǎn)。Python中所有的東西,注意,我是指所有的東西——都是對(duì)象。這包括整數(shù)、字符串、函數(shù)以及類(lèi)。它們?nèi)慷际菍?duì)象,而且它們都是從一個(gè)類(lèi)(元類(lèi),默認(rèn)為type,也可以自定制)創(chuàng)建而來(lái)。type也是由type創(chuàng)建。

二、元類(lèi)(metaclass)

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

metaclass,直譯為元類(lèi),簡(jiǎn)單的解釋就是:

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

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

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

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

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

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

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

使用metaclass的兩種方式

class MyType(type):  # 自定義一個(gè)type的派生類(lèi)
    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類(lèi),當(dāng)程序運(yùn)行,用到class Foo時(shí),即調(diào)用MyType的__init__方法,創(chuàng)建Foo類(lèi)
    def __init__(self,name):
        self.name = name
 
 
#方式二    在Flask的wtform的源碼中用到過(guò)
# class Foo(with_metaclass(object)):
#     def __init__(self,name):
#         self.name = name
 
 
a=Foo('name')
 

方式一:即用類(lèi)的形式

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

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

  • 在metaclass里面定義的方法會(huì)成為類(lèi)的方法,可以直接通過(guò)類(lèi)名來(lái)調(diào)用

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

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

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

metaclass 原理

1.基礎(chǔ)

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

說(shuō)說(shuō)這個(gè)方法:__new__(cls, name, bases, attrs)

  • cls: 將要?jiǎng)?chuàng)建的類(lèi),類(lèi)似與self,但是self指向的是instance,而這里cls指向的是class

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

  • bases: 基類(lèi)

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

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

getattr和setattr(just an advice)

2.查找順序

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

如果“元類(lèi)”存在,它就被使用了。

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

否則,如果一個(gè)名為元類(lèi)的全局變量存在,就會(huì)使用它。

三、 __init__,__new__,__call__三個(gè)特殊方法

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

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

  • __call__: 對(duì)象可call,注意不是類(lèi),是對(duì)象。

1.對(duì)于__new__

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

打印結(jié)果為:

<__main__.Bar object at 0x0090F930>

可以看到,輸出來(lái)是一個(gè)Bar對(duì)象。

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

2.對(duì)于__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)建對(duì)象
      print('執(zhí)行__new__方法')
      return obj
 
p1 = Person('hc', 24)
print(p1)

打印結(jié)果:

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

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

若__new__()沒(méi)有正確返回當(dāng)前類(lèi)cls的實(shí)例,那__init__()將不會(huì)被調(diào)用,即使是父類(lèi)的實(shí)例也不行。

3.對(duì)于__call__

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

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

4、實(shí)例化對(duì)象的完整過(guò)程

class Foo(Bar):
    pass

當(dāng)我們寫(xiě)如這段代碼時(shí),Python做了如下的操作:

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

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

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

那么什么可以用來(lái)創(chuàng)建一個(gè)類(lèi)呢?

type,或者任何使用到type或者子類(lèi)化type的東東都可以。

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

obj()會(huì)執(zhí)行Foo類(lèi)的__call__方法,沒(méi)有則用父類(lèi)的

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

元類(lèi)處理過(guò)程:定義一個(gè)類(lèi)時(shí),使用聲明或者默認(rèn)的元類(lèi)對(duì)該類(lèi)進(jìn)行創(chuàng)建,對(duì)元類(lèi)求type運(yùn)算,得到父元類(lèi)(該類(lèi)聲明的元類(lèi)的父元類(lèi)),調(diào)用父元類(lèi)的__call__函數(shù),在父元類(lèi)的__call__函數(shù)中, 調(diào)用該類(lèi)聲明的元類(lèi)的__new__函數(shù)來(lái)創(chuàng)建對(duì)象(該函數(shù)需要返回一個(gè)對(duì)象(指類(lèi))實(shí)例),然后再調(diào)用該元類(lèi)的__init__初始化該對(duì)象(此處對(duì)象是指類(lèi),因?yàn)槭窃?lèi)創(chuàng)建的對(duì)象),最終返回該類(lèi)

1.對(duì)象是類(lèi)創(chuàng)建,創(chuàng)建對(duì)象時(shí)候類(lèi)的__init__方法自動(dòng)執(zhí)行,對(duì)象()執(zhí)行類(lèi)的__call__方法
2.類(lèi)是type創(chuàng)建,創(chuàng)建類(lèi)時(shí)候type的__init__方法自動(dòng)執(zhí)行,類(lèi)() 執(zhí)行type的__call__方法(類(lèi)的__new__方法,類(lèi)的__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

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

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

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

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

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

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

相關(guān)文章

  • 淺談Selenium+Webdriver 常用的元素定位方式

    淺談Selenium+Webdriver 常用的元素定位方式

    這篇文章主要介紹了淺談Selenium+Webdriver 常用的元素定位方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Python實(shí)現(xiàn)敏感詞過(guò)濾的4種方法

    Python實(shí)現(xiàn)敏感詞過(guò)濾的4種方法

    這篇文章主要介紹了Python實(shí)現(xiàn)敏感詞過(guò)濾的4種方法,幫助大家處理不和諧的言論,感興趣的朋友可以了解下
    2020-09-09
  • Python中利用all()來(lái)優(yōu)化減少判斷的實(shí)例分析

    Python中利用all()來(lái)優(yōu)化減少判斷的實(shí)例分析

    在本篇文章里小編給大家整理的是一篇關(guān)于Python中利用all()來(lái)優(yōu)化減少判斷的實(shí)例分析內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。
    2021-06-06
  • Python實(shí)現(xiàn)字符串格式化輸出的方法詳解

    Python實(shí)現(xiàn)字符串格式化輸出的方法詳解

    這篇文章主要介紹了Python實(shí)現(xiàn)字符串格式化輸出的方法,結(jié)合具體實(shí)例形式總結(jié)分析了Python字符串格式化輸出的各種常用操作技巧,需要的朋友可以參考下
    2017-09-09
  • Python中的作用域規(guī)則詳解

    Python中的作用域規(guī)則詳解

    這篇文章主要介紹了Python中的作用域規(guī)則詳解了局部作用域、全局作用域、內(nèi)置作用域、嵌套作用域等內(nèi)容,本文講解了,需要的朋友可以參考下
    2015-01-01
  • 關(guān)于Python參數(shù)解析器argparse的應(yīng)用場(chǎng)景

    關(guān)于Python參數(shù)解析器argparse的應(yīng)用場(chǎng)景

    這篇文章主要介紹了關(guān)于Python參數(shù)解析器argparse的應(yīng)用場(chǎng)景,argparse 模塊使編寫(xiě)用戶(hù)友好的命令行界面變得容易,程序定義了所需的參數(shù),而 argparse 將找出如何從 sys.argv 中解析這些參數(shù),需要的朋友可以參考下
    2023-08-08
  • python3.6使用urllib完成下載的實(shí)例

    python3.6使用urllib完成下載的實(shí)例

    今天小編就為大家分享一篇python3.6使用urllib完成下載的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • python-OpenCV 實(shí)現(xiàn)將數(shù)組轉(zhuǎn)換成灰度圖和彩圖

    python-OpenCV 實(shí)現(xiàn)將數(shù)組轉(zhuǎn)換成灰度圖和彩圖

    今天小編就為大家分享一篇python-OpenCV 實(shí)現(xiàn)將數(shù)組轉(zhuǎn)換成灰度圖和彩圖,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-01-01
  • pandas如何解決excel科學(xué)計(jì)數(shù)法問(wèn)題

    pandas如何解決excel科學(xué)計(jì)數(shù)法問(wèn)題

    這篇文章主要介紹了pandas如何解決excel科學(xué)計(jì)數(shù)法問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 教你怎么用PyCharm為同一服務(wù)器配置多個(gè)python解釋器

    教你怎么用PyCharm為同一服務(wù)器配置多個(gè)python解釋器

    當(dāng)我們?cè)诜?wù)器上創(chuàng)建了多個(gè)虛擬環(huán)境時(shí),也可以在 PyCharm 中配置這些虛擬環(huán)境,方便不同的項(xiàng)目使用不同的環(huán)境,然而按照網(wǎng)上教程添加多個(gè)python解釋器后,PyCharm會(huì)自動(dòng)幫我們創(chuàng)建多個(gè)重復(fù)的服務(wù)器,本文主要給出該問(wèn)題的解決方法,同時(shí)也對(duì)添加解釋器做一個(gè)詳細(xì)的講解
    2021-05-05

最新評(píng)論