1. 程式人生 > >Python基礎:Python類(真累~)

Python基礎:Python類(真累~)

理解 技術 rowspan num 重新 說明 區分 第一個 構造

類的聲明:

一、類的屬性

(私有屬性和公有屬性)

(類屬性)

二、類的方法

(構造方法、析構方法、自定義方法、特殊成員方法)

(靜態方法、類方法、類屬性)

三、類的繼承

(方法和屬性的繼承,方法的重構)

(抽象類,多重繼承)

四、類的多態

(實現接口的重用)

五、類的特殊裝飾

(@staticmethod、@classmethod、@property)

六、類的來源和原類(metaclass)

七、反射

  • 類的聲明

    使用class聲明類,建議類名單詞首字母大寫。

    “新式類”和“經典類”的區分在Python 3之後就已經不存在,在Python 3.x之後的版本,因為所有的類都派生自內置類型object(即使沒有顯示的繼承object類型),即所有的類都是“新式類”。

    新式類:

class Management(object):

    def add():
        pass

經典類:

class Management:
    pass

  • 類的屬性

    類的屬性就是類定義的變量值。

公有屬性:在類裏直接定義的屬性,它在類名下面直接定義。

調用:1、類中調用:類名.屬性名 ,更改原公有屬性值

2、實例調用:實例.屬性名

class Management(object):
    num = 10

    def add(self):
        Management.num +=10            # 類中調用公有屬性並更改值,num=11
        pass

s1 = Management()
s2 = Management()

# 第一種情況:s1實例中調用公有屬性,s2實例沒有調用公有屬性
s1.num +=1
Management.num += 2
"""
<結果>
s1不變,s2和Management都改變了
s1_num:11   s2_num:12   Manage_num:12
"""

# 第二種情況:先調用s1實例公有屬性,再通過S1調用add更改,然後再使用類更改
s1.num +=1
s1.add()
Management.num += 2
"""
<結果>
先調用的s1實例num依然不變,s2和Management都被修改了
s1_num:11   s2_num:22   Manage_num:22

"""

問題:為什麽修改num的值以後,實例s1和實例s2會有不同的結果呢 ?

因為公有屬性查找的順序是:先找實例的公有屬性,沒找到再找類裏的公有屬性

可以這樣理解:Management相當於一個微信群,num是群裏發的一張照片,S1和S2是群裏面的兩個人。

情況1:S1把照片存到本地,P了個雙眼皮,S2說太難看了,我也不會P圖,不保存。這個時候發照片的Management說我也覺得難看,把圖撤回,重新發了一個P的圖。S2就只能保存最新的圖片。

情況2:S1找到Management說你的圖太醜了,重新改一下吧,Management說好!撤回圖片修改了~

私有屬性:加兩個下劃線,__membername,編譯的時候自動加上類名,變成_classname__membername,這種技術叫變量名壓縮(mangling),以達到外部不能調用的目的。實際使用_classname__membername是可以調用的,但是不符合規定。標準方法是通過定義函數來獲取。

class Classname(object):
 '''this is a demo!'''
 def __init__(self):
  self.__membername = 88

 def read_membername(self):            # 標準的外部訪問方法,使用函數來讀取私有屬性。
  return self.__membername

s= Classname()
print(s._Classname__membername)
print(s.read_membername())
'''
<結果>
88
88
------像下面的調用,會出現AttributeError錯誤------
print(s.__membername)
'''

類屬性: 類自帶的屬性,需要註意的是實例化的類屬性,和原類的類屬性不同。用上面的例子作演示。

屬性
作用
示例
結果
__doc__類的文檔字符串print(s.__doc__)
print(Classname.__doc__)

this is a demo!

this is a demo!

__dict__類的屬性組成的字典print(s.__dict__)
print(Classname.__dict__)

{'_Classname__membername': 88}

{'__init__':, '__module__': '__main__', '__doc__': '\nthis is a demo!\n', 'read_membername':}

__name__類的名字(字符串)##不能用於實例print(s.__name__ )
print(Classname.__name__ )


Classname

__bases__類的所有父類組成的元組#不能用於實例print(s.__bases__)
print(Classname.__bases__)


(,)為什麽沒有值?可能是編譯器問題

__module__類所屬的模塊print(s.__module__)
print(Classname.__module__)
__main__
__main__
__class__類對象的類型print(s.__class__)
print(Classname.__class__)
待測
__slots__

限定類屬性,在類屬性位置定義

未在slots定義的屬性都是非法屬性

__slots__.('name','age','sexy')使用'name','age','sexy'的以外屬性會報錯

  • 類的方法

    類的方法就是類裏面定義的函數。類的構造方法、析構方法、自定義類方法、靜態方法、類方法、屬性方法、特殊成員方法。

    構造方法:__init__

    實例化類的時候就會運行的函數。希望初始化的參數放置在init下面。(個人覺得,這個初始化參數可以是一切對象!)

class A(object):
 def instense(self):
  print("init obj A")
  
class B(object):
 def __init__(self, para):
  self.init_para = para
  self.obj_A = A()
  self.num = 1
 
 def show(self):
  print(self.init_para)
  self.obj_A.instense()
  print(self.num)
haha = B("this is para")
haha.show()


----------
this is para

init obj A

1

析構方法:

__del__:銷毀實例時,方法才會執行。

class Hello(object):
    def __del__(self):
        print("你刪除了實例")
# 在python上測試
instance = Hello()
del instance
# 當然也可以使用實例調用,但沒有這麽用的~~
instance.__del__()


自定義方法:

除去類中自帶的以_下劃線開頭的函數,在類中定義一個函數,實現相應的功能。

class Person(object):
    def __init__(self,person_name, person_age)

靜態方法:

@staticmethod,不需要訪問類裏的任何參數。所帶的參數都是從外部傳入的。

class Person(object):
    def __init__(self,person_name, person_age):
        self.name = person_name
        self.age = person_age
        
    @staticmethod
    def info(country):
        print(country)

類方法:

@classmethod,第一個參數必須是類屬性。

class Person(object):
    country = "china"
    def __init__(self,person_name, person_age):
        self.name = person_name
        self.age = person_age
        
    @classmethod
    def info(country):
        print(country)

屬性方法:

@property把一個函數變成一個靜態屬性

直接調用函數名字,不需要加括號,就能獲取到函數返回值。一般用在不註重過程,只要結果的情況!

class Person(object):
    country = "china"
    def __init__(self,person_name, person_age):
        self.name = person_name
        self.age = person_age

    @property
    def health_point(self):
        print("HP:【{}】".format(self.age*2))
        return self.age*2

P = Person("laowang",23)
P.health_point                # 不需要括號,看起來完全是一個屬性,這就是屬性方法


特殊成員方法:

方法
作用示例結果
__call__

默認未定義

類實例化後,調用實例運行的方法

p = Person()

p()

Person是類名

實例p沒有調用函數,加()運行call方法

__str__

默認未定義,定義時必須有返回值

定義時,打印實例,輸入str返回值

p = Person()

print (p)

Person是類名

打印實例p,運行str方法,打印返回值

__getitem__
用於索引操作,如字典。獲取數據

p = Person()

p['name']

自動運行getitem
__setitem__
用於索引操作,如字典。賦值

p = Person()

p['name'] = 'David'

自動運行setitem
__delitem__
用於索引操作,如字典。刪除數據

p = Person()

del p['name']

自動運行delitem
__new__

類實例化時,執行__new__,並且會阻止

init運行,可以在new裏調用init


p = Person()參照例子二
__len__
待續


__cmp__待續
'''例子一call\str\getitem\setitem\delitem方法'''
class Person(object):
 def __call__(self):
  print("print call")
 
 def __str__(self):
  print("print str:",end='')
  return "1"
  
 def __getitem__(self,key):  
  print("getitem:",key)
  
 def __setitem__(self,key,value):
  print('setitem:',key,value)
 
 def __delitem__(self,key):
  print('delitem:',key)
  
p = Person()
p()
print(p)
print('-----------')
get = p['name']
p['name'] = 'David'
del p['name']
'''例子二:__new__/__init__'''
class Person(object):

 def __init__(self):

  print('this is init!')
  

 def __new__(self):

  print("this is new!")

  self.__init__(self)        # 如果去掉這一行,init不能執行
  
p = Person()


類的來源和元類:

http://blog.jobbole.com/21351/中文版詳細解答。下面寫一個自己理解的簡版的。

首先,類也是對象,可以:

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

2) 你可以拷貝它

3) 你可以為它增加屬性

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

類也是是由type()這個函數創建的,type是類的類,類的爹。學名叫元類!

也許有人會問那為啥type()能查看到數據類型呢?因為數據類型在Python中都是類定義的,這也說明了,為什麽數字,字符等等全是對象。


type格式:

type(類名,(父類元組),{屬性字典},{方法詞典}) , 父類元組可以沒有;後面兩個典省略時,默認值為None。

'''一言不合就上例子'''
class Person(object):
    country = 'china'

Person = type('Person',('object',),{'country':china})


未完待續。。。

  • 類的繼承

  • 類的多態

  • 反射

Python基礎:Python類(真累~)