當前位置:
首頁 > 知識 > Python 面向對象(進階篇)

Python 面向對象(進階篇)

(點擊

上方藍字

,快速關注我們)




來源:Mr.Seven


www.cnblogs.com/wupeiqi/p/4766801.html


如有好文章投稿,請點擊 → 這裡了解詳情




上一篇《Python 面向對象(初級篇)》文章介紹了面向對象基本知識:





  • 面向對象是一種編程方式,此編程方式的實現是基於對 類 和 對象 的使用



  • 類 是一個模板,模板中包裝了多個「函數」供使用(可以講多函數中公用的變數封裝到對象中)



  • 對象,根據模板創建的實例(即:對象),實例用於調用被包裝在類中的函數



  • 面向對象三大特性:封裝、繼承和多態




本篇將詳細介紹Python 類的成員、成員修飾符、類的特殊成員。




類的成員



類的成員可以分為三大類:欄位、方法和屬性





註:所有成員中,只有普通欄位的內容保存對象中,即:根據此類創建了多少對象,在內存中就有多少個普通欄位。而其他的成員,則都是保存在類中,即:無論對象的多少,在內存中只創建一份。




一、欄位




欄位包括:普通欄位和靜態欄位,他們在定義和使用中有所區別,而最本質的區別是內存中保存的位置不同,





  • 普通欄位屬於對象



  • 靜態欄位屬於類





class

Province

:


 


    

# 靜態欄位


    

country

"中國"


 


    

def __init__

(

self

,

name

)

:


 


        

# 普通欄位


        

self

.

name

=

name


 


 


# 直接訪問普通欄位


obj

=

Province

(

"河北省"

)


print

obj

.

name


 


# 直接訪問靜態欄位


Province

.

country




由上述代碼可以看出【普通欄位需要通過對象來訪問】【靜態欄位通過類訪問】,在使用上可以看出普通欄位和靜態欄位的歸屬是不同的。其在內容的存儲方式類似如下圖:







由上圖可是:






  • 靜態欄位在內存中只保存一份



  • 普通欄位在每個對象中都要保存一份




應用場景: 通過類創建對象時,如果每個對象都具有相同的欄位,那麼就使用靜態欄位




二、方法




方法包括:普通方法、靜態方法和類方法,三種方法在內存中都歸屬於類,區別在於調用方式不同。






  • 普通方法:由對象調用;至少一個self參數;執行普通方法時,自動將調用該方法的對象賦值給self;



  • 類方法:由類調用; 至少一個cls參數;執行類方法時,自動將調用該方法的類複製給cls;



  • 靜態方法:由類調用;無默認參數;





class

Foo

:


 


    

def __init__

(

self

,

name

)

:


        

self

.

name

=

name


 


    def ord_func

(

self

)

:


        

""" 定義普通方法,至少有一個self參數 """


 


        

# print self.name


        

print

"普通方法"


 


    

@

classmethod


    def class_func

(

cls

)

:


        

""" 定義類方法,至少有一個cls參數 """


 


        

print

"類方法"


 


    

@

staticmethod


    def static_func

()

:


        

""" 定義靜態方法 ,無默認參數"""


 


        

print

"靜態方法"


 


 


# 調用普通方法


f

=

Foo

()


f

.

ord_func

()


 


# 調用類方法


Foo

.

class_func

()


 


# 調用靜態方法


Foo

.

static_func

()







相同點:對於所有的方法而言,均屬於類(非對象)中,所以,在內存中也只保存一份。




不同點:方法調用者不同、調用方法時自動傳入的參數不同。




三、屬性  




如果你已經了解Python類中的方法,那麼屬性就非常簡單了,因為Python中的屬性其實是普通方法的變種。




對於屬性,有以下三個知識點:






  • 屬性的基本使用



  • 屬性的兩種定義方式




1、屬性的基本使用





# ############### 定義 ###############


class

Foo

:


 


    

def func

(

self

)

:


        

pass


 


    

# 定義屬性


    

@

property


    

def prop

(

self

)

:


        

pass


# ############### 調用 ###############


foo_obj

=

Foo

()


 


foo_obj

.

func

()


foo_obj

.

prop

  

#調用屬性







由屬性的定義和調用要注意一下幾點:






  • 定義時,在普通方法的基礎上添加 @property 裝飾器;



  • 定義時,屬性僅有一個self參數



  • 調用時,無需括弧



  • 方法:foo_obj.func()



  • 屬性:foo_obj.prop




注意:屬性存在意義是:訪問屬性時可以製造出和訪問欄位完全相同的假象




屬性由方法變種而來,如果Python中沒有屬性,方法完全可以代替其功能。




實例:對於主機列表頁面,每次請求不可能把資料庫中的所有內容都顯示到頁面上,而是通過分頁的功能局部顯示,所以在向資料庫中請求數據時就要顯示的指定獲取從第m條到第n條的所有數據(即:limit m,n),這個分頁的功能包括:






  • 根據用戶請求的當前頁和總數據條數計算出 m 和 n



  • 根據m 和 n 去資料庫中請求數據





# ############### 定義 ###############


class

Pager

:


    


    

def __init__

(

self

,

current_page

)

:


        

# 用戶當前請求的頁碼(第一頁、第二頁...)


        

self

.

current_page

=

current_page


        

# 每頁默認顯示10條數據


        

self

.

per_items

=

10


 


 


    

@

property


    

def start

(

self

)

:


        

val

=

(

self

.

current_page

-

1

)

*

self

.

per_items


        

return

val


 


    

@

property


    

def

end

(

self

)

:


        

val

=

self

.

current_page *

self

.

per_items


        

return

val


 


# ############### 調用 ###############


 


p

=

Pager

(

1

)


p

.

start

就是起始值,即:

m


p

.

end

  

就是結束值,即:

n




從上述可見,Python的屬性的功能是:屬性內部進行一系列的邏輯計算,最終將計算結果返回。




2、屬性的兩種定義方式




屬性的定義有兩種方式:






  • 裝飾器 即:在方法上應用裝飾器



  • 靜態欄位 即:在類中定義值為property對象的靜態欄位




裝飾器方式:在類的普通方法上應用@property裝飾器




我們知道Python中的類有經典類和新式類,新式類的屬性比經典類的屬性豐富。( 如果類繼object,那麼該類是新式類 )




經典類,具有一種@property裝飾器(如上一步實例)





# ############### 定義 ###############    


class

Goods

:


 


    

@

property


    

def price

(

self

)

:


        

return

"wupeiqi"


# ############### 調用 ###############


obj

=

Goods

()


result

=

obj

.

price

  

# 自動執行 @property 修飾的 price 方法,並獲取方法的返回值




新式類,具有三種@property裝飾器





# ############### 定義 ###############


class

Goods

(

object

)

:


 


    

@

property


    

def price

(

self

)

:


        

print

"@property"


 


    

@

price

.

setter


    def price

(

self

,

value

)

:


        

print

"@price.setter"


 


    

@

price

.

deleter


    def price

(

self

)

:


        

print

"@price.deleter"


 


# ############### 調用 ###############


obj

=

Goods

()


 


obj

.

price

          

# 自動執行 @property 修飾的 price 方法,並獲取方法的返回值


 


obj

.

price

=

123

    

# 自動執行 @price.setter 修飾的 price 方法,並將  123 賦值給方法的參數


 


del

obj

.

price

      

# 自動執行 @price.deleter 修飾的 price 方法




註:經典類中的屬性只有一種訪問方式,其對應被 @property 修飾的方法


新式類中的屬性有三種訪問方式,並分別對應了三個被@property、@方法名.setter、@方法名.deleter修飾的方法




由於新式類中具有三種訪問方式,我們可以根據他們幾個屬性的訪問特點,分別將三個方法定義為對同一個屬性:獲取、修改、刪除





class

Goods

(

object

)

:


 


    

def __init__

(

self

)

:


        

# 原價


        

self

.

original_price

=

100


        

# 折扣


        

self

.

discount

=

0.8


 


    

@

property


    

def price

(

self

)

:


        

# 實際價格 = 原價 * 折扣


        

new_price

=

self

.

original_price *

self

.

discount


        

return

new

_

price


 


    

@

price

.

setter


    def price

(

self

,

value

)

:


        

self

.

original_price

=

value


 


    

@

price

.

deltter


    def price

(

self

,

value

)

:


        

del

self

.

original_price


 


obj

=

Goods

()


obj

.

price

        

# 獲取商品價格


obj

.

price

=

200

  

# 修改商品原價


del

obj

.

price

    

# 刪除商品原價




靜態欄位方式,創建值為property對象的靜態欄位




當使用靜態欄位的方式創建屬性時,經典類和新式類無區別





class

Foo

:


 


    

def get_bar

(

self

)

:


        

return

"wupeiqi"


 


    

BAR

=

property

(

get_bar

)


 


obj

=

Foo

()


reuslt

=

obj

.

BAR

        

# 自動調用get_bar方法,並獲取方法的返回值


print

reuslt




property的構造方法中有個四個參數






  • 第一個參數是方法名,調用 對象.屬性 時自動觸發執行方法



  • 第二個參數是方法名,調用 對象.屬性 = XXX 時自動觸發執行方法



  • 第三個參數是方法名,調用 del 對象.屬性 時自動觸發執行方法



  • 第四個參數是字元串,調用 對象.屬性.__doc__ ,此參數是該屬性的描述信息





class

Foo


 


    

def get_bar

(

self

)

:


        

return

"wupeiqi"


 


    

# *必須兩個參數


    

def set_bar

(

self

,

value

)

:


        

return

return

"set value"

+

value


 


    def del_bar

(

self

)

:


        

return

"wupeiqi"


 


    

BAR

property

(

get_bar

,

set_bar

,

del_bar

,

"description..."

)


 


obj

=

Foo

()


 


obj

.

BAR

              

# 自動調用第一個參數中定義的方法:get_bar


obj

.

BAR

=

"alex"

    

# 自動調用第二個參數中定義的方法:set_bar方法,並將「alex」當作參數傳入


del

Foo

.

BAR

          

# 自動調用第三個參數中定義的方法:del_bar方法


obj

.

BAE

.

__doc__

      

# 自動獲取第四個參數中設置的值:description...




由於靜態欄位方式創建屬性具有三種訪問方式,我們可以根據他們幾個屬性的訪問特點,分別將三個方法定義為對同一個屬性:獲取、修改、刪除





class

Goods

(

object

)

:


 


    

def __init__

(

self

)

:


        

# 原價


        

self

.

original_price

=

100


        

# 折扣


        

self

.

discount

=

0.8


 


    

def get_price

(

self

)

:


        

# 實際價格 = 原價 * 折扣


        

new_price

=

self

.

original_price *

self

.

discount


        

return

new_price


 


    def set_price

(

self

,

value

)

:


        

self

.

original_price

=

value


 


    def del_price

(

self

,

value

)

:


        

del

self

.

original_price


 


    

PRICE

=

property

(

get_price

,

set_price

,

del_price

,

"價格屬性描述..."

)


 


obj

=

Goods

()


obj

.

PRICE

        

# 獲取商品價格


obj

.

PRICE

=

200

  

# 修改商品原價


del

obj

.

PRICE

    

# 刪除商品原價




注意:Python WEB框架 Django 的視圖中 request.POST 就是使用的靜態欄位的方式創建的屬性





class

WSGIRequest

(

http

.

HttpRequest

)

:


    

def __init__

(

self

,

environ

)

:


        

script_name

=

get_script_name

(

environ

)


        

path_info

=

get_path_info

(

environ

)


        

if

not

path_info

:


            

# Sometimes PATH_INFO exists, but is empty (e.g. accessing


            

# the SCRIPT_NAME URL without a trailing slash). We really need to


            

# operate as if they"d requested "/". Not amazingly nice to force


            

# the path like this, but should be harmless.


            

path_info

=

"/"


        

self

.

environ

=

environ


        

self

.

path_info

=

path_info


        

self

.

path

=

"%s/%s"

%

(

script_name

.

rstrip

(

"/"

),

path_info

.

lstrip

(

"/"

))


        

self

.

META

=

environ


        

self

.

META

[

"PATH_INFO"

]

=

path_info


        

self

.

META

[

"SCRIPT_NAME"

]

=

script_name


        

self

.

method

=

environ

[

"REQUEST_METHOD"

].

upper

()


        

_

,

content_params

=

cgi

.

parse_header

(

environ

.

get

(

"CONTENT_TYPE"

,

""

))


        

if

"charset"

in

content_params

:


            

try

:


                

codecs

.

lookup

(

content_params

[

"charset"

])


            

except

LookupError

:


                

pass


            

else

:


                

self

.

encoding

=

content_params

[

"charset"

]


        

self

.

_post_parse_error

=

False


        

try

:


            

content_length

=

int

(

environ

.

get

(

"CONTENT_LENGTH"

))


        

except

(

ValueError

,

TypeError

)

:


            

content_length

=

0


        

self

.

_stream

=

LimitedStream

(

self

.

environ

[

"wsgi.input"

],

content_length

)


        

self

.

_read_started

=

False


        

self

.

resolver_match

=

None


 


    def _get_scheme

(

self

)

:


        

return

self

.

environ

.

get

(

"wsgi.url_scheme"

)


 


    

def _get_request

(

self

)

:


        

warnings

.

warn

(

"`request.REQUEST` is deprecated, use `request.GET` or "


                      

"`request.POST` instead."

,

RemovedInDjango19Warning

,

2

)


        

if

not

hasattr

(

self

,

"_request"

)

:


            

self

.

_request

=

datastructures

.

MergeDict

(

self

.

POST

,

self

.

GET

)


        

return

self

.

_request


 


    

@

cached_property


    def GET

(

self

)

:


        

# The WSGI spec says "QUERY_STRING" may be absent.


        

raw_query_string

=

get_bytes_from_wsgi

(

self

.

environ

,

"QUERY_STRING"

,

""

)


        

return

http

.

QueryDict

(

raw_query_string

,

encoding

=

self

.

_encoding

)


    


    

# ############### 看這裡看這裡  ###############


    

def _get_post

(

self

)

:


        

if

not

hasattr

(

self

,

"_post"

)

:


            

self

.

_load_post_and_files

()


        

return

self

.

_post


 


    

# ############### 看這裡看這裡  ###############


    

def _set_post

(

self

,

post

)

:


        

self

.

_post

=

post


 


    

@

cached_property


    def COOKIES

(

self

)

:


        

raw_cookie

=

get_str_from_wsgi

(

self

.

environ

,

"HTTP_COOKIE"

,

""

)


        

return

http

.

parse_cookie

(

raw_cookie

)


 


    

def _get_files

(

self

)

:


        

if

not

hasattr

(

self

,

"_files"

)

:


            

self

.

_load_post_and_files

()


        

return

self

.

_files


 


    

# ############### 看這裡看這裡  ###############


    

POST

=

property

(

_get_post

,

_set_post

)


    


    

FILES

=

property

(

_get_files

)


    

REQUEST

=

property

(

_get_request

)




所以,定義屬性共有兩種方式,分別是【裝飾器】和【靜態欄位】,而【裝飾器】方式針對經典類和新式類又有所不同。




類成員的修飾符




類的所有成員在上一步驟中已經做了詳細的介紹,對於每一個類的成員而言都有兩種形式:






  • 公有成員,在任何地方都能訪問



  • 私有成員,只有在類的內部才能方法




私有成員和公有成員的定義不同

:私有成員命名時,前兩個字元是下劃線。(特殊成員除外,例如:__init__、__call__、__dict__等)





class

C

:



    

def __init__

(

self

)

:


        

self

.

name

=

"公有欄位"


        

self

.

__foo

=

"私有欄位"




私有成員和公有成員的訪問限制不同:




靜態欄位






  • 公有靜態欄位:類可以訪問;類內部可以訪問;派生類中可以訪問



  • 私有靜態欄位:僅類內部可以訪問;





class

C

:


 


    

name

=

"公有靜態欄位"


 


    

def func

(

self

)

:


        

print

C

.

name


 


class

D

(

C

)

:


 


    

def show

(

self

)

:


        

print

C

.

name


 


 


C

.

name

        

# 類訪問


 


obj

=

C

()


obj

.

func

()

    

# 類內部可以訪問


 


obj_son

=

D

()


obj_son

.

show

()

# 派生類中可以訪問





class

C

:


 


    

__name

=

"公有靜態欄位"


 


    

def func

(

self

)

:


        

print

C

.

__name


 


class

D

(

C

)

:


 


    

def show

(

self

)

:


        

print

C

.

_

_

name


 


 


C

.

__name

      

# 類訪問            ==> 錯誤


 


obj

=

C

()


obj

.

func

()

    

# 類內部可以訪問     ==> 正確


 


obj_son

=

D

()


obj_son

.

show

()

# 派生類中可以訪問   ==> 錯誤




普通欄位






  • 公有普通欄位:對象可以訪問;類內部可以訪問;派生類中可以訪問



  • 私有普通欄位:僅類內部可以訪問;




ps:如果想要強制訪問私有欄位,可以通過 【對象._類名__私有欄位明 】訪問(如:obj._C__foo),不建議強制訪問私有成員。





class

C

:


    


    

def __init__

(

self

)

:


        

self

.

foo

=

"公有欄位"


 


    

def func

(

self

)

:


        

print

self

.

foo

 

# 類內部訪問


 


class

D

(

C

)

:


    


    

def show

(

self

)

:


        

print

self

.

foo

 # 派生類中訪問


 


obj

=

C

()


 


obj

.

foo

    

# 通過對象訪問


obj

.

func

()

  

# 類內部訪問


 


obj_son

=

D

();


obj_son

.

show

()

  

# 派生類中訪問





class

C

:


    


    

def __init__

(

self

)

:


        

self

.

__foo

=

"私有欄位"


 


    

def func

(

self

)

:


        

print

self

.

foo

 

# 類內部訪問


 


class

D

(

C

)

:


    


    

def show

(

self

)

:


        

print

self

.

foo

 # 派生類中訪問


 


obj

=

C

()


 


obj

.

__foo

    

# 通過對象訪問    ==> 錯誤


obj

.

func

()

  

# 類內部訪問        ==> 正確


 


obj_son

=

D

();


obj_son

.

show

()

  

# 派生類中訪問  ==> 錯誤




方法、屬性的訪問於上述方式相似,即:私有成員只能在類內部使用




ps:非要訪問私有屬性的話,可以通過 對象._類__屬性名




類的特殊成員




上文介紹了Python的類成員以及成員修飾符,從而了解到類中有欄位、方法和屬性三大類成員,並且成員名前如果有兩個下劃線,則表示該成員是私有成員,私有成員只能由類內部調用。無論人或事物往往都有不按套路出牌的情況,Python的類成員也是如此,存在著一些具有特殊含義的成員,詳情如下:




1. __doc__




表示類的描述信息





class

Foo

:


    

""" 描述類信息,這是用於看片的神奇 """


 


    

def func

(

self

)

:


        

pass


 


print

Foo

.

__doc__


#輸出:類的描述信息




2. __module__ 和 __class__




__module__ 表示當前操作的對象在那個模塊




__class__ 表示當前操作的對象的類是什麼





#!/usr/bin/env python


# -*- coding:utf-8 -*-


 


class

C

:


 


    

def __init__

(

self

)

:


        

self

.

name

=

"wupeiqi"


 


lib

/

aa

.

py





from

lib

.

aa

import

C


 


obj

=

C

()


print

obj

.

__module__

  

# 輸出 lib.aa,即:輸出模塊


print

obj

.

__class__

      

# 輸出 lib.aa.C,即:輸出類




3. __init__




構造方法,通過類創建對象時,自動觸發執行。





class

Foo

:


 


    

def __init__

(

self

,

name

)

:


        

self

.

name

=

name


        

self

.

age

=

18


 


 


obj

=

Foo

(

"wupeiqi"

)

# 自動執行類中的 __init__ 方法




4. __del__




析構方法,當對象在內存中被釋放時,自動觸發執行。




註:此方法一般無須定義,因為Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,因為此工作都是交給Python解釋器來執行,所以,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。





class

Foo

:


 


    

def __del__

(

self

)

:


        

pass




5. __call__




對象後面加括弧,觸發執行。




註:構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象後加括弧觸發的,即:對象() 或者 類()()





class

Foo

:


 


    

def __init__

(

self

)

:


        

pass


    


    def __call__

(

self

,

*

args

,

**

kwargs

)

:


 


        

print

"__call__"


 


 


obj

=

Foo

()

# 執行 __init__


obj

()

      

# 執行 __call__




6. __dict__




類或對象中的所有成員




上文中我們知道:類的普通欄位屬於對象;類中的靜態欄位和方法等屬於類,即:








class

Province

:


 


    

country

=

"China"


 


    

def __init__

(

self

,

name

,

count

)

:


        

self

.

name

=

name


        

self

.

count

=

count


 


    def func

(

self

,

*

args

,

**

kwargs

)

:


        

print

"func"


 


# 獲取類的成員,即:靜態欄位、方法、


print

Province

.

__dict__


# 輸出:{"country": "China", "__module__": "__main__", "func": <function func at 0x10be30f50>, "__init__": <function __init__ at 0x10be30ed8>, "__doc__": None}


 


obj1

=

Province

(

"HeBei"

,

10000

)


print

obj1

.

__dict__


# 獲取 對象obj1 的成員


# 輸出:{"count": 10000, "name": "HeBei"}


 


obj2

=

Province

(

"HeNan"

,

3888

)


print

obj2

.

__dict__


# 獲取 對象obj1 的成員


# 輸出:{"count": 3888, "name": "HeNan"}




7. __str__




如果一個類中定義了__str__方法,那麼在列印 對象 時,默認輸出該方法的返回值。





class

Foo

:


 


    

def __str__

(

self

)

:


        

return

"wupeiqi"


 


 


obj

=

Foo

()


print

obj


# 輸出:wupeiqi




8、__getitem__、__setitem__、__delitem__




用於索引操作,如字典。以上分別表示獲取、設置、刪除數據





#!/usr/bin/env python


# -*- coding:utf-8 -*-



class

Foo

(

object

)

:



    

def __getitem__

(

self

,

key

)

:


        

print

"__getitem__"

,

key



    def __setitem__

(

self

,

key

,

value

)

:


        

print

"__setitem__"

,

key

,

value



    def __delitem__

(

self

,

key

)

:


        

print

"__delitem__"

,

key




obj

=

Foo

()



result

=

obj

[

"k1"

]

      

# 自動觸發執行 __getitem__


obj

[

"k2"

]

=

"wupeiqi"

  

# 自動觸發執行 __setitem__


del

obj

[

"k1"

]

          

# 自動觸發執行 __delitem__




9、__getslice__、__setslice__、__delslice__




該三個方法用於分片操作,如:列表





#!/usr/bin/env python


# -*- coding:utf-8 -*-



class

Foo

(

object

)

:



    

def __getslice__

(

self

,

i

,

j

)

:


        

print

"__getslice__"

,

i

,

j



    

def __setslice__

(

self

,

i

,

j

,

sequence

)

:


        

print

"__setslice__"

,

i

,

j



    

def __delslice__

(

self

,

i

,

j

)

:


        

print

"__delslice__"

,

i

,

j



obj

=

Foo

()



obj

[

-

1

:

1

]

                  

# 自動觸發執行 __getslice__


obj

[

0

:

1

]

=

[

11

,

22

,

33

,

44

]

    

# 自動觸發執行 __setslice__


del

obj

[

0

:

2

]

                

# 自動觸發執行 __delslice__




10. __iter__




用於迭代器,之所以列表、字典、元組可以進行for循環,是因為類型內部定義了 __iter__





class

Foo

(

object

)

:


    

pass


 


 


obj

=

Foo

()


 


for

i

in

obj

:


    

print

i


    


# 報錯:TypeError: "Foo" object is not iterable





#!/usr/bin/env python


# -*- coding:utf-8 -*-


 


class

Foo

(

object

)

:


    


    

def __iter__

(

self

)

:


        

pass


 


obj

=

Foo

()


 


for

i

in

obj

:


    

print

i


 


# 報錯:TypeError: iter() returned non-iterator of type "NoneType"





#!/usr/bin/env python


# -*- coding:utf-8 -*-


 


class

Foo

(

object

)

:


 


    

def __init__

(

self

,

sq

)

:


        

self

.

sq

=

sq


 


    def __iter__

(

self

)

:


        

return

iter

(

self

.

sq

)


 


obj

=

Foo

([

11

,

22

,

33

,

44

])


 


for

i

in

obj

:


    

print

i




以上步驟可以看出,for循環迭代的其實是 iter([11,22,33,44]) ,所以執行流程可以變更為:





#!/usr/bin/env python


# -*- coding:utf-8 -*-



obj

=

iter

([

11

,

22

,

33

,

44

])



for

i

in

obj

:


    

print

i





#!/usr/bin/env python


# -*- coding:utf-8 -*-


 


obj

=

iter

([

11

,

22

,

33

,

44

])


 


while

True

:


    

val

=

obj

.

next

()


    

print

val




11. __new__ 和 __metaclass__




閱讀以下代碼:





class

Foo

(

object

)

:



    

def __init__

(

self

)

:


        

pass



obj

=

Foo

()

  

# obj是通過Foo類實例化的對象




上述代碼中,obj 是通過 Foo 類實例化的對象,其實,不僅 obj 是一個對象,Foo類本身也是一個對象,因為

在Python中一切事物都是對象




如果按照一切事物都是對象的理論:obj對象是通過執行Foo類的構造方法創建,那麼Foo類對象應該也是通過執行某個類的 構造方法 創建。





print type

(

obj

)

# 輸出:<class "__main__.Foo">     表示,obj 對象由Foo類創建


print type

(

Foo

)

# 輸出:<type "type">              表示,Foo類對象由 type 類創建




所以,obj對象是Foo類的一個實例,Foo類對象是 type 類的一個實例,即:Foo類對象 是通過type類的構造方法創建。




那麼,創建類就可以有兩種方式:




a). 普通方式





class

Foo

(

object

)

:


 


    

def func

(

self

)

:


        

print

"hello wupeiqi"




b).特殊方式(type類的構造函數)





def func

(

self

)

:


    

print

"hello wupeiqi"


 


Foo

=

type

(

"Foo"

,(

object

,),

{

"func"

:

func

})


#type第一個參數:類名


#type第二個參數:當前類的基類


#type第三個參數:類的成員




==》 類 是由 type 類實例化產生




那麼問題來了,類默認是由 type 類實例化產生,type類中如何實現的創建類?類又是如何創建對象?




答:類中有一個屬性 __metaclass__,其用來表示該類由 誰 來實例化創建,所以,我們可以為 __metaclass__ 設置一個type類的派生類,從而查看 類 創建的過程。








class

MyType

(

type

)

:


 


    

def __init__

(

self

,

what

,

bases

=

None

,

dict

=

None

)

:


        

super

(

MyType

,

self

).

__init__

(

what

,

bases

,

dict

)


 


    

def __call__

(

self

,

*

args

,

**

kwargs

)

:


        

obj

=

self

.

__new__

(

self

,

*

args

,

**

kwargs

)


 


        

self

.

__init__

(

obj

)


 


class

Foo

(

object

)

:


 


    

__metaclass__

=

MyType


 


    def __init__

(

self

,

name

)

:


        

self

.

name

=

name


 


    def __new__

(

cls

,

*

args

,

**

kwargs

)

:


        

return

object

.

__new__

(

cls

,

*

args

,

**

kwargs

)


 


# 第一階段:解釋器從上到下執行代碼創建Foo類


# 第二階段:通過Foo類創建obj對象


obj

=

Foo

()




以上就是面向對象進階篇的所有內容,歡迎拍磚…




看完本文有收穫?請轉

發分享給更多人


關注「P

ython開發者」,提升Python技能


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Python開發者 的精彩文章:

一步一步教你如何搭建自己的視頻聚合站
Python 面向對象(初級篇)
使用 Sphinx 製作簡潔而又美觀的文檔
直擊「黑產」痛點,金融反欺詐大賽等你奪魁
用 Python 進行貝葉斯模型建模(4)

TAG:Python開發者 |

您可能感興趣

Perl 面向對象
Python指南:面向對象程序設計
TensorFlow官方最新tf.keras指南:面向對象構建深度網路
學慣用 Thonny 寫代碼:一個面向初學者的Python IDE
三星或正在研發第二款Bixby智能音箱,對標Google Home Mini面向低端市場
Bantam Tools 桌面 PCB 銑床通過 Digi-Key 面向全球即時供貨
AppleCare+ for Mac正式面向中國市場推出
華擎推出Phantom Gaming系列A卡,面向礦工的顯卡?
Facebook Reality Labs正式成立面向VR/AR開發
Dell宣布與Google合作:面向商務領域推出Chromebook
Surface Phone:ARW處理器和觸屏筆,將面向高端市場開放
Matterport公司面向開發者推出3D SDK
微軟Chromium版Edge瀏覽器Dev版面向Windows 7/8.1推出
思科聯合Pure Storage發布面向AI的FlashStack融合系統
蘋果AppleCare+for Mac正式面向中國市場推出
Google發布面向Linux和Mac的VR180 Creator
Unity 編輯器現已正式面向 Linux 推出
Lua 面向對象
Google只發布面向Linux和Mac的VR180 Creator
[圖]不亞於WannaCry:微軟面向Windows XP發布緊急修復補丁