## 屬性的型別
– 屬性可分為類屬性和例項屬性
– 例項屬性可以通過在類中使用self定義,或者直接在類外部使用例項變數定義
1 class Person(object): 2 def __init__(self, name, age): 3 self.name = name 4 self.age = age 5 6 7 per1 = Person("Stanley", 22) 8 print(per1.name) # 輸出:Stanley 9 per1.weight = "50kg" 10 print(per1.weight) # 輸出:50kg
– 類屬性則直接在類中定義
– 類屬性通過類名訪問,也可以通過例項訪問
1 class Person(object): 2 class_name = "Person" 3 4 def __init__(self, name, age): 5 self.name = name 6 self.age = age 7 8 9 per1 = Person("Stanley", 22) 10 print(per1.class_name) # 輸出:Person 11 12 print(Person.class_name) # 輸出:Person
– 注意:
– 如果例項屬性和類屬性使用了相同的名字,則例項化後例項屬性將覆蓋類屬性,例項將無法在訪問該同名類屬性,而通過類名訪問類屬性將不受影響
1 class Person(object): 2 name = "Person" 3 4 def __init__(self, name, age): 5 self.name = name 6 self.age = age 7 8 9 print(Person.name) # 輸出:Person 10 11 per1 = Person("Stanley", 22) 12 print(per1.name) # 輸出:Stanley 13 print(Person.name) # 輸出:Person
## 方法的型別
– 在一個類中可以存在三種類型的方法
– 在類的定義中,以self(即例項本身)作為第一個引數的方法為例項方法
1 class Person(object): 2 3 def __init__(self, name, age): 4 self.name = name 5 self.age = age 6 7 # 這是一個例項方法,self為例項本身,作為第一個引數傳入,通過例項呼叫 8 def eat(self): 9 print("I'm %s, I want to eat!" % self.name) 10 11 12 per1 = Person("Stanley", 22) 13 per1.eat() # 輸出:I'm Stanley, I want to eat!
– 在類的內部定義,用修飾符@classmethod指定的方法是類方法
– 類方法會作用於整個類,該方法對類做出的改變會影響該類的所有例項
– 與例項方法類似,類方法的第一個引數是類本身,通常寫作cls
class Person(object): count = 0 def __init__(self, name, age): self.name = name self.age = age Person.count += 1 # 每例項化一個物件,count加1 # 這是一個例項方法,self作為第一個引數傳入,通過例項呼叫 def eat(self): print("I'm %s, I want to eat!" % self.name) @classmethod # 使用@classmethod修飾 def kids(cls): # 第一個引數為類本身,這是一個類方法 print("class %s has %d instance(es)." % (cls.__name__, Person.count)) per1 = Person("Stanley", 22) per2 = Person("Bob", 18) per3 = Person("Lily", 17) Person.kids() # 輸出:class Person has 3 instance(es).
– 第三種方法型別稱為靜態方法
– 靜態方法使用@staticmethod修飾,它不需要self引數或者cls引數
– 靜態方法的存在不會影響類也不會影響類的例項,僅僅是爲了程式碼的邏輯性
– 靜態方法可以通過類名或者例項呼叫
1 class Person(object): 2 def __init__(self, name, age): 3 self.name = name 4 self.age = age 5 6 @staticmethod 7 def say_hi(): 8 print("I'm a static method. I say Hi.") 9 10 11 per1 = Person("Stanley", 22) 12 per1.say_hi() # 輸出:I'm a static method. I say Hi. 13 Person.say_hi() # 輸出:I'm a static method. I say Hi.
## 使用property對attribute進行訪問和設定
– 對於一些語言比如Java來說,對於私有屬性的訪問需要使用setter和getter方法
– Python不需要,因為Python所有屬性都是公開的,但是也可以編寫setter和getter限制對屬性的訪問
1 class Person(object): 2 def __init__(self, name, age): 3 self.__name = name # 私有屬性 4 self.age = age 5 6 def set_name(self, name): 7 self.__name = name 8 9 def get_name(self): 10 return self.__name 11 12 13 per1 = Person("Stanley", 22) 14 print(per1.get_name()) # 輸出:Stanley 15 per1.set_name("Lily") # 修改屬性值 16 print(per1.get_name()) # 輸出:Lily 17 print(per1.__name) # 無法直接訪問私有屬性,AttributeError: 'Person' object has no attribute '__name'
– 以上寫法達到了限制訪問的目的
– 但更Pythonic的寫法是使用property()
1 class Person(object): 2 def __init__(self, name, age): 3 self.__name = name 4 self.age = age 5 6 def set_name(self, name): 7 self.__name = name 8 9 def get_name(self): 10 return self.__name 11 12 # 使用property函式將getter和setter定義爲了name屬性 13 name = property(get_name, set_name) 14 15 16 per1 = Person("Stanley", 22) 17 print(per1.name) # 訪問屬性時自動呼叫getter方法,輸出:Stanley 18 per1.name = "Lily" # 設定屬性時自動呼叫setter方法 19 print(per1.name) # 輸出:Lily 20 print(per1.get_name()) # 也可以顯式的呼叫getter或者setter方法
– 還有一種方法進行訪問限制,那麼就是使用修飾符,並定義兩個同名方法
1 class Person(object): 2 def __init__(self, name, age): 3 self.__name = name 4 self.age = age 5 6 @property # @property 用於指示getter方法 7 def name(self): # 兩個同名函式 8 return self.__name 9 10 @name.setter # @name.setter 用於指示setter方法 11 def name(self, name): # 兩個同名函式 12 if isinstance(name, str): 13 self.__name = name 14 else: 15 raise TypeError("Name must be string!") 16 17 18 per1 = Person("Stanley", 22) 19 print(per1.name) # 輸出:Stanley 20 per1.name = "Lily" 21 print(per1.name) # 輸出:Lily
– 使用了@property修飾的方法就變成了屬性
1 import datetime 2 3 4 class Person(object): 5 def __init__(self, name, age): 6 self.__name = name 7 self.age = age 8 9 @property 10 def birth_year(self): 11 return datetime.datetime.now().year - self.age 12 13 14 per1 = Person("Stanley", 22) 15 print(per1.birth_year) # 輸出:1996 16 per1.birth_year = 2000 # 沒有指定setter屬性(@birth_year.setter),所以無法從外部對它的值進行設定,這使得這個birth_year這個屬性成為只讀屬性
本文參考:
[美]Bill Lubanovic 《Python語言及其應用》