什麼是物件和類
https://www.cnblogs.com/poloyy/p/15178423.html
什麼是 Python 類、類物件、例項物件
https://www.cnblogs.com/poloyy/p/15178456.html
類變數、例項變數/類屬性、例項屬性
前言
只是叫法不一樣
例項屬性 = 例項變數
類屬性 = 類變數
個人認為叫屬性更恰當
類屬性和例項屬性區別
- 類屬性,所有例項物件共享該屬性
- 例項屬性,屬於某一個例項物件的屬性,用於描述具體的物件
從實際栗子瞭解類屬性、例項屬性
有一個表格,四個常見的明星
姓名 | 年齡 |
---|---|
周潤發 | 58 |
成龍 | 55 |
劉德華 | 53 |
周星馳 | 54 |
總結一下
- 四個人歸類為明星
- 每個明星都有兩個屬性:姓名、年齡
- 明星這個群體具有一個屬性:明星數量,在這張表是 4
- 姓名和年齡等屬性是用來描述具體的一個物件
- 明星的數量是用於描述明星這個類別的
使用物件導向程式設計思想來總結的話
- 周潤發、成龍、劉德華、周星馳都是例項物件
- 他們都屬於明星,明星是類
- 屬於例項物件的屬性有:姓名、年齡,所以也叫例項屬性
- 屬於明星類的屬性有:數量,所以也叫類屬性
類裡面的三種型別變數
- 在所有方法之外定義的變數,稱為類屬性/類變數
- 在方法內部,通過 self.變數名 方式定義的變數,稱為例項屬性/例項變數
- 在方法內部,通過 變數名=變數值 方式定義的變數,稱為區域性變數
類屬性
類屬性在類中的定義
class 類名: 類屬性1 = 值 類屬性2 = 值 def func(self): ...
類屬性、類方法注意點
- 無論是類屬性還是類方法,都無法像普通變數或者函式那樣,在類的外部直接使用它們(類方法後面詳解)
- 可以將類看做一個獨立的空間,類屬性其實也是在類體中定義的變數,類方法是在類體中定義的函式
- 需要通過類物件/例項物件來呼叫類屬性 ClassName.classProperty (類方法後面詳解)
類屬性的栗子
# 類屬性 class PoloBlog: # 這就是在所有方法之外 下面定義了 2 個類變數 name = "小菠蘿測試筆記" blog = "https://www.cnblogs.com/poloyy/" # 通過類名呼叫類屬性 print(PoloBlog.name) print(PoloBlog.blog) # 輸出結果 小菠蘿測試筆記 https://www.cnblogs.com/poloyy/
通過 Pycharm 的程式碼聯想,可以看到 blog、name、__doc__ 三個類屬性
類屬性的呼叫方式
有兩種
- 直接通過類名呼叫
- 也可以通過類的例項物件呼叫
呼叫類屬性的栗子
# 呼叫類屬性的兩種方式 class PoloBlog: # 這就是在所有方法之外 下面定義了 2 個類變數 name = "小菠蘿測試筆記" blog = "https://www.cnblogs.com/poloyy/" # 通過類名直接呼叫 print(PoloBlog.name) print(PoloBlog.blog) # 修改類屬性 PoloBlog.name = "blogyuan" PoloBlog.blog = "https://www.cnblogs.com/" # 通過例項物件呼叫修改後的類屬性 poloBlog = PoloBlog() print(poloBlog.name) print(poloBlog.blog) # 輸出結果 小菠蘿測試筆記 https://www.cnblogs.com/poloyy/ blogyuan https://www.cnblogs.com/
通過類名修改類屬性的值,會影響所有的例項化物件
例項物件修改類屬性
# 修改類屬性 poloBlog.name = "小菠蘿回來了" # 再看看類物件呼叫修改後的類屬性 print(PoloBlog.name) print(poloBlog.name) # 輸出結果 blogyuan 小菠蘿回來了
- 會發現,類名.name 仍然返回之前的值,而 例項物件.name 會返回修改的值
- 原因: 例項物件.name 本質上並不是修改類屬性的值,而是在定義一個新的例項屬性(下面詳解)
動態新增類屬性
PoloBlog.age = 24 print(PoloBlog.age) print(poloBlog.age) # 輸出結果 24 24
- age 沒有在類體中定義
- 可以直接通過 類名.new_property_name 的方式定義一個新的類屬性
例項屬性
- 屬於具體物件的屬性,用於描述具體的物件
- 只能通過例項物件訪問,無法通過類名訪問
例項屬性的栗子
class PoloBlog: def __init__(self): # 在方法內部,通過 self.name 的方式定義的變數就是例項變數 self.name = "小菠蘿測試筆記" self.add = "https://www.cnblogs.com/poloyy/" # 下面定義了一個 say 例項方法 def say(self): self.age = 13 # 例項化物件 blog = PoloBlog() blog.say() print(blog.name, blog.add, blog.age) # 輸出結果 小菠蘿測試筆記 https://www.cnblogs.com/poloyy/ 13
- 重點:__init__ 會在例項化物件的時候自動呼叫,因此 blog1 建立成功就有 name、add 兩個例項屬性
- 呼叫 say() 方法之後才有第三個例項屬性 age
修改例項屬性的栗子
blog.name = "小菠蘿" blog.add = "xiaopolo.com" blog.age = 24 print(blog.name, blog.add, blog.age) # 輸出結果 小菠蘿 xiaopolo.com 24
動態新增例項屬性
blog.phone = 13501489999 print(blog.phone) # 輸出結果 13501489999
上面也有說到,通過 例項物件.屬性名 的方式並不會給類變數賦值,而是定義一個新的例項變數
綜合栗子
# 綜合栗子 class PoloBlogObjectTest: # 類變數 sum = 0 # 初始化方法 def __init__(self, name, age): # 例項變數 self.name = name self.age = age # 類變數 PoloBlogObjectTest.sum += 1 # 例項方法 def printNameAge(self): print(self.name, self.age) poloTest1 = PoloBlogObjectTest("小菠蘿一號", 24) poloTest2 = PoloBlogObjectTest("小菠蘿二號", 14) print(PoloBlogObjectTest.sum) # 呼叫例項方法 poloTest1.printNameAge() poloTest2.printNameAge() # 輸出結果 2 小菠蘿一號 24 小菠蘿二號 14
不推薦例項屬性和類屬性同名
- 類中,例項屬性和類屬性可以同名
- 但這種情況下使用例項物件將無法呼叫類變數,它會首選例項變數,無論這個變數是否已定義
- 例項獨享繫結新的例項屬性時,會直接覆蓋掉重名的類屬性
例項屬性、類屬性同名栗子
class Person: # 只有一個類變數 name = "cool guy" # 例項化一個物件 p = Person() # 列印例項屬性 name,因為例項物件並沒有name屬性,所以會繼續查詢class的name屬性 print(p.name) # 列印類屬性 name print(Person.name) # 給例項繫結 name、age 屬性 p.name = "bad guy" p.age = 12 # 列印 name、age 屬性 print(p.age) # 由於例項屬性優先順序比類屬性高,因此,它會遮蔽掉類的 name 屬性 print(p.name) # 仍然列印類的 name 屬性 print(Person.name) # 輸出結果 cool guy cool guy 12 bad guy cool guy
例項物件屬性引用的查詢過程