2018年7月2日 星期一

Python物件導向--高階(一)




## 屬性的型別


– 屬性可分為類屬性和例項屬性


– 例項屬性可以通過在類中使用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語言及其應用》






http://www.buzzfunnews.com/20180723128.html

更多有趣新聞請上:http://www.buzzfunnews.com

沒有留言:

張貼留言