【Python】5.物件導向的Python
Python是一種物件導向程式設計的語言,Python中幾乎都是物件,簡單數值型別,程式碼模組,可以說是萬物皆物件。例如對於一個數值物件:
>>> type(1)
<class 'int'>
>>> dir(1)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
目錄
一、物件導向程式設計
物件導向程式設計的思想將物件作為程式的基本單元,物件=資料(屬性)+一套訪問和操作這些資料的方法。就像在引言中說的,Python中所有的資料型別都可以被視為物件我們也可以自定義物件,即物件導向中類的概念。
從程式導向的程式設計到物件導向的程式設計,從語句到函式到類,抽象程度不斷變高,但是更符合我們日常中的概念。
以學生成績表為例,語句表達:
std1 = { 'name': 'Michael', 'score': 98 }
std2 = { 'name': 'Bob', 'score': 81 }
通過函式列印:
def print_score(std):
print('%s: %s' % (std['name'], std['score']))
將物件資料:學生成績,對資料處理的方法:列印,整合在一起就是一個類。
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))
給物件發訊息實際上就是呼叫物件對應的關聯函式,即物件的方法:
bart = Student('Bart Simpson', 59)
lisa = Student('Lisa Simpson', 87)
bart.print_score()
lisa.print_score()
物件導向程式設計的好處主要有三個方面:
1)多型:可對不同型別的物件執行相同的操作。
2)封裝:對外部隱藏有關物件工作原理的細節。
3)繼承:可基於通用類建立出專用類。
二、類和物件
1.什麼是類和物件
類是一種物件的統稱,每個物件都屬於特定的類,物件是類的例項,是Python中程式的基本單元,要建立物件,就首先要建立一個類。
通過賦值語句可以給物件賦予名稱,名稱可以有很多個但是id只有一個。
a = complex(1,1)
2.自定義類:建立與呼叫
1)class語句和類的初始化
class <類名>:
def _init_(self,<參數列>):
def <方法名>(self,<參數列>):
_init_()是一個特殊的函式名,用於根據類的定義建立例項物件,第一個引數必須是self。
2)呼叫類和方法
obj = <類名>(<參數列>)
obj.<方法>()
類方法中的self就是obj物件例項本身
#在Python中約定,類名大寫字母開頭,函式小寫字母開頭
class Person:
def set_name(self, name):
self.name = name
def get_name(self):
return self.name
def greet(self):
print("Hello, world! I'm {}.".format(self.name))
>>> foo = Person() #先建立Person(),再將foo名稱與之關聯
>>> bar = Person()
>>> foo.set_name('Luke Skywalker')
>>> bar.set_name('Anakin Skywalker')
>>> foo.greet()
Hello, world! I'm Luke Skywalker.
>>> bar.greet()
Hello, world! I'm Anakin Skywalker.
3.屬性、函式和方法
方法和函式的區別表現在引數self上,方法中的第一個引數關聯到它所屬的例項,呼叫的時候無需這個引數,可以在類的外部將方法關聯到一個普通的函式,通過這種方法,也可以實現普通函式對類中self例項的訪問。
>>> class Class:
... def method(self):
... print('I have a self!')
...
>>> def function():
... print("I don't...")
...
>>> instance = Class()
>>> instance.method() I have a self!
>>> instance.method = function
>>> instance.method() I don't...
>>> class Bird:
... song = 'Squaawk!'
... def sing(self):
... print(self.song)
...
>>> bird = Bird()
>>> bird.sing()
Squaawk!
>>> birdsong = bird.sing
>>> birdsong()
Squaawk!
4.類名稱空間
在class語句中定義的程式碼都是在一個特殊的名稱空間(類的名稱空間)內執行的,而類的所有成員都可訪問這個名稱空間,例如:
class MemberCounter:
members = 0
def init(self):
MemberCounter.members += 1
>>> m1 = MemberCounter()
>>> m1.init()
>>> MemberCounter.members
1
>>> m2 = MemberCounter()
>>> m2.init()
>>> MemberCounter.members
2
如果給例項中的屬性members賦值,那麼該值將被寫入m1的一個屬性中,這個屬性遮住了類級變數。m1中的屬性將被覆蓋為定值(類似於外部傳遞進來的實參值覆蓋類名稱空間內的全域性變數),類中的操作不在影響該變數,但m1中的方法仍會影響其他例項中的該屬性(類級變數)。
>>> class MemberCounter:
members = 0
def init(self):
MemberCounter.members += 1
>>> m1 = MemberCounter()
>>> m1.init()
>>> m1.members
1
>>> m1.members=3
>>> m1.members
3
>>> m2= MemberCounter()
>>> m2.init()
>>> m2.members
2
>>> m1.init()
>>> m1.members
3
>>> m2.members
3
>>> m2.init()
>>> m2.members
4
三、繼承
1.繼承
1)定義一個class的時候,可以從某個現有的class繼承,新的class稱為子類(Subclass),而被繼承的class稱為基類、父類或超類(Base class、Super class)。
例如:Dog類和Cat類都繼承自Animal類。
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
pass
class Cat(Animal):
pass
2)通過這種方法,子類可以獲得父類全部的屬性和方法,並可以新增,或者重寫已有的方法。
class Filter:
def init(self):
self.blocked = []
def filter(self, sequence):
return [x for x in sequence if x not in self.blocked]
class SPAMFilter(Filter): # SPAMFilter是Filter的子類
def init(self): # 重寫超類Filter的方法init
self.blocked = ['SPAM']
>>> f = Filter()
>>> f.init()
>>> f.filter([1, 2, 3])
[1, 2, 3]
>>> s = SPAMFilter()
>>> s.init()
>>> s.filter(['SPAM', 'SPAM', 'SPAM', 'SPAM', 'eggs', 'bacon', 'SPAM'])
['eggs', 'bacon']
2.繼承查詢
1)要確定一個類是否是另一個類的子類,可使用內建方法issubclass
:
>>> issubclass(SPAMFilter, Filter)
True
>>> issubclass(Filter, SPAMFilter)
False
2)查詢基類,可訪問其特殊屬性 __bases__
;查詢物件屬於哪個類,可使用屬性__class__
:
>>> SPAMFilter.__bases__
(<class __main__.Filter at 0x171e40>,)
>>> Filter.__bases__
(<class 'object'>,)
3)確定物件是否是特定類的例項,可使用isinstance:
>>> s = SPAMFilter()
>>> isinstance(s, SPAMFilter)
True
>>> isinstance(s, Filter)
True
3.多個超類
1)多重繼承,繼承多個父類的屬性和方法:
class Calculator:
def calculate(self, expression):
self.value = eval(expression)
class Talker:
def talk(self):
print('Hi, my value is', self.value)
class TalkingCalculator(Calculator, Talker):
pass
>>> tc = TalkingCalculator()
>>> tc.calculate('1 + 2 * 3')
>>> tc.talk()
Hi, my value is 7
2)注意:如果多個超類以不同的方式實現了同一個方法(同名方法),必須在class語句中小心排列這些超類,因為位於前面的類的方法將覆蓋位於後面的類的方法。因此,在前面的示例中,如果Calculator類包含方法talk,那麼這個方法將覆蓋Talker
類的方法talk(導致它不可訪問)。
四、多型
1.什麼是多型
我們首先要對資料型別再作一點說明。當我們定義一個class的時候,我們實際上就定義了一種資料型別。我們定義的資料型別和Python自帶的資料型別,比如str、list、dict沒什麼兩樣,子類物件的資料型別是子類本身,同時也是父類的資料型別。
多型的用法例如,定義一個函式:
def run_twice(animal):
animal.run()
animal.run()
>>> run_twice(Animal())
Animal is running...
Animal is running...
>>> run_twice(Dog())
Dog is running...
Dog is running...
>>> run_twice(Cat())
Cat is running...
Cat is running..
2.開閉原則
多型的好處就是,由於Animal型別有run()方法,因此,傳入的任意型別,只要是Animal類或者子類,就會自動呼叫實際型別的run()方法,這就是多型的意思。呼叫方只管呼叫,不管細節,而當我們新增一種Animal的子類時,只要確保run()方法編寫正確,不用管原來的程式碼是如何呼叫的。這就是著名的“開閉”原則:
1)對擴充套件開放:允許新增Animal子類;
2)對修改封閉:不需要修改依賴Animal型別的run_twice()等函式。
3.鴨子型別
一個物件只要“看起來像鴨子,走起路來像鴨子”,那它就可以被看做是鴨子。
對於靜態語言(例如Java)來說,如果需要傳入Animal型別,則傳入的物件必須是Animal型別或者它的子類,否則,將無法呼叫run()方法。對於Python這樣的動態語言來說,則不一定需要傳入Animal型別。我們只需要保證傳入的物件有一個run()方法就可以了,實際上對於Python,就是針對函式中呼叫的方法,只要有,不管定義的型別是什麼,傳遞進去的型別是什麼,都可以:
>>> def runtwice(anywithrun):
anywithrun.run()
anywithrun.run()
五、封裝
在Class內部,可以有屬性和方法,而外部程式碼可以通過直接 呼叫例項變數的方法(讀寫) 來運算元據,這樣,就隱藏了內部的複雜邏輯。
1.私有變數
如果要讓內部屬性不被外部訪問,可以把屬性的名稱前加上兩個下劃線__
,在Python中,例項的變數名如果以__
開頭,就變成了一個私有變數(private),只有內部可以訪問,外部不能訪問。
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
>>> bart = Student('Bart Simpson', 59)
>>> bart.__name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'
注意:①如果變數名類似__xxx__
的,也就是以雙下劃線開頭,並且以雙下劃線結尾的,是特殊變數,特殊變數是可以直接訪問的,不是private變數,所以儘量避免使用這種變數。
②如果變數名以一個下劃線開頭,這樣的例項變數外部是可以訪問的,但是,意思就是,請當作私有變數不要隨意訪問。
③即使是private變數,Python也提供了訪問的方法,因為Python直譯器對外把__xxx
變數改成了_類名__xxx
,所有通過下面這種方式也可以訪問,但是儘量不要這樣做。
>>> bart._Student__name
'Bart Simpson'
2.讀寫方法
例如上面的例子,如果外部程式碼要獲取name和score,可以給Student類增加get_name和get_score這樣的方法,如果要允許外部程式碼修改score,可以再給Student類增加set_score方法:
class Student(object):
...
def get_name(self):
return self.__name
def get_score(self):
return self.__score
def set_score(self, score):
self.__score = score
相關文章
- Python——物件導向Python物件
- Python 物件導向Python物件
- python物件導向Python物件
- python物件導向一Python物件
- python物件導向(一)Python物件
- python物件導向(下)Python物件
- Python物件導向(上)Python物件
- python-程式導向、物件導向、類Python物件
- python物件導向[基礎]Python物件
- Python物件導向知多少?Python物件
- Python 物件導向介紹Python物件
- python 初識物件導向Python物件
- Python 物件導向筆記Python物件筆記
- python物件導向思想(類與物件)Python物件
- 如何吃透Python的物件導向(OOP)Python物件OOP
- 【python 物件導向】 python物件學習筆記《1》Python物件筆記
- 草根學Python(九) 物件導向Python物件
- Python物件導向三大特性Python物件
- python-物件導向入門Python物件
- 2.1.0 Python初識物件導向Python物件
- 面向Python,物件導向(基礎)Python物件
- python之成員(物件導向)Python物件
- Python物件導向程式設計Python物件程式設計
- Python物件導向之九:反射Python物件反射
- Python 物件導向程式設計Python物件程式設計
- Python基礎之物件導向Python物件
- Python進階之物件導向Python物件
- python---之物件導向selfPython物件
- Python之物件導向和麵向過程Python物件
- Python學習筆記|Python之物件導向Python筆記物件
- 2.1.1 Python物件導向三大特性Python物件
- Python進階教程5——物件導向Python物件
- Python OOP 物件導向程式設計PythonOOP物件程式設計
- python物件導向練習題01Python物件
- Python - 物件導向程式設計 - @propertyPython物件程式設計
- Python - 物件導向程式設計 - super()Python物件程式設計
- 面向Python,物件導向(基礎3)Python物件
- python技能--物件導向程式設計Python物件程式設計