1. 程式人生 > >簡述Python中的類與對象

簡述Python中的類與對象

新增 error attribute base 得到 object類 cts dir() 所有

Python中的類

類的定義

示例:

class Person:
    country = "China"
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def speak(self, word):
        print(word)

其中 country 是類屬性,即 Person類 的靜態屬性,speak() 為 Person類的函數屬性,即類的動態屬性~

類的實例化

對上述示例的類進行實例化:

>>> p = Person(‘Kitty‘, 18)       # 實例化 Person類,得到對象 p
>>> p.name                              # 調用對象 p 的name屬性
‘Kitty‘ 
>>> p.speak(‘hello‘)                 # 調用對象 p 的綁定方法
hello

?
類中的 __init__ 方法用於初始化對象,而在類的是實例化過程中,對應類中第一個被調用的並不是 __init__ 方法,第一個被調用的是 __new__方法。在對象的初始化之前首先要創建對象,__new__方法正是用來創建這個對象~
?
類的實例化過程也可以通過如下語句來實現:

>>> p = object.__new__(Person)        # __new__方法繼承自 object類
>>> Person.__init__(p, ‘Kitty‘, 18)
>>> p.name
‘Kitty‘

在Person類中重寫 __new__方法:

class Person:
    country = "China"
    def __new__(cls, name, age):
        print(‘__new__ called‘)
        return super(Person, cls).__new__(cls)

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def speak(self, word):
        print(word)

p = Person(‘Kitty‘, 18)          # 實例化對象
print(‘name : %s‘ % p.name)

# 輸出結果:
__new__ called
name : Kitty

很明顯 __new__方法 是先於 __init__ 方法被調用的~
類的實例化過程大致步驟如下:
1、p = Person(‘Kitty‘, 18) ,會調用 Person類的__new__方法,並傳遞 name 和 age 參數
2、__new__方法 會創建一個 Person類的對象並返回
3、最後利用這個對象調用類的 __init__ 方法 完成初始化,__init__ 方法的第一個參數是self,對象在調用 __init__ 方法時會將自己當做參數傳遞給 這個self。
?
註意:__init__方法沒有返回值~,__init__ 方法僅完成對象的初始化工作~
?

self是什麽?
在類的內部,self 就是一個對象。使用對象調用方法時(對象的綁定方法),當前對象會被自動傳遞給 self,即 self 表示調用該方法的對象~

類屬性的調用

操作類的變量屬性:

>>> Person.country                  # 調用類屬性
‘China‘
>>> Person.country = ‘USA‘     # 修改類屬性
>>> Person.country
‘USA‘
>>> del Person.country           # 刪除類屬性
>>> Person.country                 # 刪除後無法再調用
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object ‘Person‘ has no attribute ‘country‘

?
調用類的函數屬性:
這裏僅介紹綁定方法的調用(即第一個參數是self的方法),類中的其他方法暫先不做介紹~
?
speak() 是類的函數屬性,對象調用不需要傳遞 self參數(對象調用 會自動完成self參數傳值,下面會介紹),若是類來調用,則需要手動傳遞這個 self參數,即需要傳遞一個Person類的對象~

class Person:
    country = "China"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def speak(self, word):
        print(word)

p = Person(‘Kitty‘, 18) 
p.speak(‘hello‘)                  # 對象調用,會自動將 對象p 作為第一個參數傳遞給 self
Person.speak(p, ‘你好‘)     # 類調用需要手動傳遞 self 的值

# 輸出結果:
hello
你好

類的名稱空間

類名.__dict__ 用來查看一個類(或對象)的名稱空間,可以這樣理解。其實__dict__是類的一個內置屬性,存儲所有實例共享的變量和函數(類屬性,方法等),類的__dict__並不包含其父類的屬性。對象中的 __dict__ 屬性下面會介紹~
?
這裏註意和 dir() 方法的區別,dir(類名或對象名) 會返回一個類(或對象)的所有屬性,包括從父類中繼承的屬性。

Person類的__dict__屬性
{‘__module__‘: ‘__main__‘,        # 所處模塊
‘__init__‘: <function Person.__init__ at 0x11023b378>,   # __init__方法
‘speak‘: <function Person.speak at 0x11023b400>,       # speak 方法
‘__dict__‘: <attribute ‘__dict__‘ of ‘Person‘ objects>,      # 應該就是指  類的__dict__屬性,具體參閱:https://blog.csdn.net/lis_12/article/details/53519060
‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Person‘ objects>, 
‘__doc__‘: None}             # # class說明文檔

?
調用類的屬性,首先會去類的名稱空間中(Person.__dict__)尋找對應名稱的key,相當於Person.__dict__[‘country‘],也可以直接這樣調用:

>>> Person.__dict__[‘country‘]
‘China‘
>>> Person.__dict__[‘country‘] = ‘USA‘
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: ‘mappingproxy‘ object does not support item assignment

?
註意:
__dict__ 對於類中的屬性只能查看,不能修改~

Python內置屬性

除了 __dict__,Python中的類還有很多別的內置屬性:
__doc__ :類的說明
__name__: 類名
__module__: 類定義所在的模塊
__bases__ : 包含了類的所有父類 的元組
?
示例如下:

class Person:
    ‘‘‘human being‘‘‘
    country = "China"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def speak(self, word):
        print(word)

print(Person.__doc__)
print(Person.__name__)
print(Person.__module__)
print(Person.__bases__)

#結果輸出:
human being
Person
__main__
(<class ‘object‘>,)

Python中的對象

對象的名稱空間

class Person:
    country = "China"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def speak(self, word):
        print(word)

實例化一個Person類的對象 的過程中,init方法會將參數賦值給 name 與 age 屬性,可以通過 實例的__dict__ 查看,註意:實例的__dict__ 僅存儲與該實例相關的實例屬性,沒有函數屬性,也沒有共有屬性~

>>> p = Person(‘Kitty‘, 18)
>>> print(p.__dict__)
{‘name‘: ‘Kitty‘, ‘age‘: 18}

?
註意 實例.__dict__ 與 類.__dict__ 的區別~
?
通過 類.__dict__ 可以查看類中的屬性,但是不能修改,但是通過 實例.__dict__ 除了查看,還可以進行修改~

>>> p.__dict__[‘name‘]
‘Kitty‘
>>> p.__dict__[‘age‘]
18
>>> p.__dict__[‘name‘] = ‘abc‘
>>> p.__dict__[‘age‘] = 20
>>> p.name
‘abc‘
>>> p.age 
20

對象的變量屬性調用

通過對象可以直接調用該對象的變量屬性,例如 p對象 的 name屬性 和 age屬性~

>>> p = Person(‘Kitty‘, 18)
>>> p.name
‘Kitty‘
>>> p.age
18

也可以通過 p對象 調用對應類(這裏是Person類)的變量屬性,若是類的變量屬性發生變化,則所有對象獲取到的類變量屬性都會改變~

>>> p.country
‘China‘

>>> Person.country = ‘UK‘       # 修改 類的變量屬性
>>> p2 = Person(‘baby‘, 22)
>>> p.country
‘UK‘
>>> p2.country
‘UK‘

Tip:

  • 可以將所有類共有的屬性設置成類屬性;
  • 對象尋找屬性會先在自己的名稱空間中尋找,若是沒有再去類的名稱空間中尋找~

註意1
在修改類的變量屬性時,若變量是不可變類型,則僅能通過 類名.變量屬性 來修改,如下示例:

>>> Person.country = ‘USA‘     # 修改類屬性
>>> p.country   
‘USA‘
>>> p.country = ‘UK‘
>>> p.country
‘UK‘
>>> Person.country
‘USA‘
>>> p2.country
‘USA‘

p.country 並沒有修改類屬性,而是給自己添加了一個新的屬性,這個新添加的屬性存放在對象自己的名稱空間中,類的變量屬性 country 並沒有發生改變~

>>> p.__dict__
{‘country‘: ‘UK‘, ‘age‘: 20, ‘name‘: ‘abc‘}

?
在類中 self 表示當前調用的對象,當 self 引用的變量和類變量同名的時候,需要註意區分:這兩個變量之間沒有關聯,self 引用的變量屬於對象,放在對象的名稱空間中,類變量則放在類名稱空間中

class Person:
    country = "China"
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.country = ‘AUS‘     # 添加對象屬性
    def speak(self):
        print(self.country)
############
>>> p = Person(‘Kitty‘, 18)
>>> p.country
‘AUS‘
>>> p.speak()
AUS
>>> Person.country
‘China‘

註意2
當類變量為可變類型時,需要區分對象的 2種 操作:

class Person:
    country = "China"
    lst = []
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.lst.append(name)
    def speak(self):
        print(self.name)
############
>>> p = Person(‘Kitty‘, 18)
>>> p.__dict__
{‘age‘: 18, ‘name‘: ‘Kitty‘}
>>> Person.lst
[‘Kitty‘]

上述示例中,self 針對 lst 變量並不是一個賦值操作,而是調用了 lst的append方法,所以這個過程會先在對象的名稱空間中尋找 lst 屬性,對象的名稱空間中沒有,然後再去類的名稱空間中尋找,Person類中存在該屬性,於是調用其 append 方法。
?
這個過程通過對象修改了類的可變類型的變量~
?
若 self 針對 lst 變量是一個賦值操作,這樣就為當前對象新增了一個 lst 屬性

class Person:
    country = "China"
    lst = []
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.lst = name
    def speak(self):
        print(self.name)
############
>>> p = Person(‘Kitty‘, 18)
>>> p.__dict__
{‘age‘: 18, ‘name‘: ‘Kitty‘, ‘lst‘: ‘Kitty‘}
>>> Person.__dict__
{‘__module__‘: ‘__main__‘, ‘country‘: ‘China‘, ‘lst‘: [], ‘__doc__‘: None, ‘__init__‘: <function __init__ at 0x105f5fc08>, ‘speak‘: <function speak at 0x105f5c0c8>}

對象的方法(綁定方法)

class Person:
    country = "China"
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def speak(self):
        print(self.name + ‘, ‘ + str(self.age))
############
>>> p1 = Person(‘Kitty‘, 18)
>>> p2 = Person(‘baby‘, 22)
>>> p1.__dict__
{‘age‘: 18, ‘name‘: ‘Kitty‘}
>>> p2.__dict__
{‘age‘: 22, ‘name‘: ‘baby‘}

可以看到對象的名稱空間中沒有函數屬性,函數屬性在類的名稱空間當中
?

>>> Person.speak
<unbound method Person.speak>
>>> p1.speak
<bound method Person.speak of <__main__.Person instance at 0x105f727a0>>
>>> p2.speak
<bound method Person.speak of <__main__.Person instance at 0x105f728c0>>

p1 和 p2 的 speak 方法為綁定方法(bound method),且 p1 和 p2 的 speak 方法內存地址不一致,這兩個對象的 speak 方法都執行 類中對應的方法。
?
通過對象調用綁定方法的時候,會自動將 當前對象傳遞給方法的第一個參數(self,一般都叫self,也可以寫成別的名稱),若使用類調用,則第一個參數需要手動傳值~

>>> p1.speak()
Kitty, 18
>>> p2.speak()
baby, 22
>>> Person.speak(p1)     # 通過類調用
Kitty, 18

這裏僅對綁定到對象的方法做簡單介紹,類中還有綁定到類的方法,還有非綁定方法等...,之後會介紹

.................^_^

簡述Python中的類與對象