Python - 物件導向程式設計 - 類變數、例項變數/類屬性、例項屬性

小菠蘿測試筆記發表於2021-08-28

什麼是物件和類

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

 

例項物件屬性引用的查詢過程

 

 

相關文章