本系列主要學(xué)習(xí)Python的基本使用和語法知識(shí),后續(xù)可能會(huì)圍繞著AI學(xué)習(xí)展開。
Python3 (1) Python語言的簡(jiǎn)介
Python3 (2) Python語法基礎(chǔ)
Python3 (3) Python函數(shù)
Python3 (4) Python高級(jí)特性
Python3(5) Python 函數(shù)式編程
Python3(6) Python 模塊
Python3(7) Python 面向?qū)ο缶幊?/a>
面向?qū)ο缶幊淌且环N編程思想,主要與面向過程編程比較學(xué)習(xí),在經(jīng)歷了 C++、C#、Java 的面向?qū)ο蟮膶W(xué)習(xí),相信學(xué)習(xí) Python 的面向?qū)ο髸?huì)讓自己對(duì) OOP 有更深的理解。
面向?qū)ο笈c面向過程的比較
面向?qū)ο缶幊獭狾bject Oriented Programming,簡(jiǎn)稱OOP,是一種程序設(shè)計(jì)思想。OOP把對(duì)象作為程序的基本單元,一個(gè)對(duì)象包含了數(shù)據(jù)和操作數(shù)據(jù)的函數(shù)。
面向過程編程——面向過程的程序設(shè)計(jì)把計(jì)算機(jī)程序視為一系列的命令集合,即一組函數(shù)的順序執(zhí)行。為了簡(jiǎn)化程序設(shè)計(jì),面向過程把函數(shù)繼續(xù)切分為子函數(shù),即把大塊函數(shù)通過切割成小塊函數(shù)來降低系統(tǒng)的復(fù)雜度。
#面向?qū)ο?class Student(object):
def __init__(self, name, age):
self.name = name
self.age = age
def print_age(self):
print('%s: %s' % (self.name, self.age))
bart = Student('張三', 15)
lisa = Student('李四', 16)
bart.print_age()
lisa.print_age()
#面向過程
def print_age(std):
print('%s: %s' % (std['name'], std['age']))
std1 = { 'name': '張三', 'age': 17 }
std2 = { 'name': '李四', 'age': 18 }
print_age(std1)
print_age(std2)
輸出結(jié)果:
張三: 15
李四: 16
張三: 17
李四: 18
在Python中,所有數(shù)據(jù)類型都可以視為對(duì)象,當(dāng)然也可以自定義對(duì)象。Student的實(shí)例就是一個(gè)個(gè)對(duì)象。
類與實(shí)例
類與實(shí)例與java相同,就是普通的 Class 和 Class的實(shí)例化 ,類可以看成一個(gè)模板,可以實(shí)例出不用的對(duì)象。
下面我們分析一下上面面向?qū)ο蟮?示例:
-
class Student(object)Student 類的定義,繼承自object -
def __init__(self, name, age)含義跟java構(gòu)造函數(shù)相同,創(chuàng)建了實(shí)例時(shí)可以綁定一些數(shù)據(jù)。 - 創(chuàng)建實(shí)例 在類名后+
()即可,沒有new關(guān)鍵字跟kotlin使用一致。 - 在類中定義的函數(shù)有個(gè)共同的特點(diǎn)就是第一個(gè)參數(shù)是
self。 - Python允許對(duì)實(shí)例變量綁定任何數(shù)據(jù),與靜態(tài)語言不同。
數(shù)據(jù)封裝
數(shù)據(jù)的封裝,其實(shí)就是定義一些函數(shù),來實(shí)現(xiàn)特定的功能,類的實(shí)例調(diào)用對(duì)應(yīng)的方法就可以實(shí)現(xiàn)對(duì)應(yīng)的功能,不需要關(guān)注函數(shù)的具體實(shí)現(xiàn)和數(shù)據(jù)的具體傳遞。
訪問限制
在前面我們已經(jīng)學(xué)習(xí)過,除特殊的變量,以
_xxx和__xxx命名的變量是私有的,我們可以通過設(shè)置get、set來訪問私有變量。這就體現(xiàn)了代碼的封裝性,可以使我們的程序更加的安全,規(guī)范,健壯。但是不是設(shè)置成私有的就一定不能被外界直接訪問只是不符合編碼規(guī)則,例如:__namepython解釋器會(huì)編譯成_Student__name不同的版本也可能有不同的編譯方式,所以盡量不要這樣使用。
繼承
OOP程序設(shè)計(jì)中,當(dāng)我們定義一個(gè)class的時(shí)候,可以從某個(gè)現(xiàn)有的class繼承,新的class稱為子類(Subclass),而被繼承的class稱為基類、父類或超類(Base class、Super class)。繼承的作用就是子類可以繼承到父類的所有功能。也可以重寫對(duì)應(yīng)的功能。
多態(tài)
多態(tài)的概念其實(shí)是在繼承,重寫的應(yīng)用,我們可以通過繼承派生出不同的子類,重寫子類的具體實(shí)現(xiàn),在調(diào)用時(shí)用他們的共同基類做參數(shù),這樣基類派生出的各種子類都可以傳遞進(jìn)去,系統(tǒng)會(huì)根據(jù)傳入的具體類型實(shí)現(xiàn)具體的功能。
開閉原則
多態(tài)的設(shè)計(jì)采用的就是開閉原則:調(diào)用方只管調(diào)用,不管細(xì)節(jié),不需要任何更改。
1. 對(duì)擴(kuò)展開放:允許新增子類;
2. 對(duì)修改封閉:不需要修改用基類作為參數(shù)的方法
鴨子類型
這是Python強(qiáng)大之處,決定了繼承不像靜態(tài)語言那樣是必須的。
鴨子類型:不要求嚴(yán)格的繼承體系,一個(gè)對(duì)象只要“看起來像鴨子,走起路來像鴨子”,那它就可以被看做是鴨子,具體講就是傳入的對(duì)象,有需要的方法就可以傳入并使用,不需要嚴(yán)格的來自它的繼承。
下面通過一個(gè)示例來演示繼承、多態(tài)、鴨子類型:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#基類
class Car(object):
def run(self):
return "car running...."
#子類
class SmallCar(Car):
def run(self):
return 'small car running...'
#子類
class BigCar(Car):
def run(self):
return 'bag car running...'
#子類的子類
class PoliceCar(SmallCar):
def run(self):
return 'police car running...'
def stop(self):
return 'police car stopped...'
#鴨子類型
class SchoolCar(object):
def run(self):
return 'school car running...'
#方法的調(diào)用
def look(car):
print('I look a ',car.run())
#多態(tài)的使用場(chǎng)景
look(Car())
look(SmallCar())
look(BigCar())
look(PoliceCar())
#鴨子類型的調(diào)用
look(SchoolCar())
輸出結(jié)果:
I look a car running....
I look a small car running...
I look a bag car running...
I look a police car running...
I look a school car running...
獲取對(duì)象信息
python中內(nèi)置了各種函數(shù),方便我們獲取對(duì)象的信息。如
type()、isinstance()、dir()、getattr()、setattr()以及hasattr()
下面是對(duì)獲取對(duì)象信息 內(nèi)置函數(shù)的使用示例:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#基類
import types
class Car(object):
weight = 2000
def run(self):
return "car running...."
#子類
class SmallCar(Car):
def run(self):
return 'small car running...'
#子類
class BigCar(Car):
def run(self):
return 'bag car running...'
#子類的子類
class PoliceCar(SmallCar):
def run(self):
return 'police car running...'
def stop(self):
return 'police car stopped...'
#鴨子類型
class SchoolCar(object):
def run(self):
return 'school car running...'
#方法的調(diào)用
def look(car):
print('I look a ',car.run())
#type()的使用
s = SmallCar()
s1 = SmallCar()
p = PoliceCar()
c = Car()
print(type(s),type(s1))
print(type(s)==SmallCar)
print(type(s)==type(c))
print("---------------------------")
#type的高級(jí)使用
print(type(look)==types.FunctionType)
print(type(abs)==types.BuiltinFunctionType)
print(type(lambda x: x)==types.LambdaType)
print(type((x for x in range(10)))==types.GeneratorType)
print("---------------------------")
#isinstance()的使用
print(isinstance(s,SmallCar))
print(isinstance(s,Car))
print(isinstance(s,PoliceCar))
print(isinstance(s,(SmallCar,PoliceCar)))#括號(hào)中是或的關(guān)系
print("---------------------------")
#dir() 的使用
print(dir(p))
print("---------------------------")
#getattr()、setattr()、hasattr() 的使用
#屬性
print(hasattr(p,'weight'))
print(getattr(p,'weight'))
setattr(p,'weight',3000)
print(getattr(p,'weight'))
print(getattr(p,'height',404))
#方法
print(hasattr(p,'run'))
print(getattr(p,'run'))
setattr(p,'run',123456)
print(getattr(p,'run'))
#attr正確用法,去阻止鴨式類型之外的對(duì)象
def look(car):
if hasattr(car, 'run'):
print('I look a ', car.run())
return None
class Ambulance(object):
def shop(self):
return 'ambulance car stopped...'
print(look(Ambulance()))
輸出結(jié)果:
<class '__main__.SmallCar'> <class '__main__.SmallCar'>
True
False
---------------------------
True
True
True
True
---------------------------
True
True
False
True
---------------------------
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'run', 'stop', 'weight']
---------------------------
True
2000
3000
404
True
<bound method PoliceCar.run of <__main__.PoliceCar object at 0x0000020D453CC0F0>>
123456
None
實(shí)例屬性和類屬性
這里主要強(qiáng)調(diào)一下實(shí)例屬性與類屬性的區(qū)別,由于Python是動(dòng)態(tài)語言,根據(jù)類創(chuàng)建的實(shí)例可以任意綁定屬性。包括類的屬性
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
class Car(object):
name = 'car'
def __init__(self, name,weight):
self.name = name
self.weight = weight
c = Car('small car',2000);
print(Car.name)
print(c.name)
print(c.weight)
del c.name,c.weight
print(c.name)
print(getattr(c,'weight',3000))
輸出結(jié)果:
car
small car
2000
car
3000
從上面可以看出如果刪除了實(shí)例的屬性,實(shí)例的屬性會(huì)自動(dòng)訪問類的屬性。所以一定要注意實(shí)例的屬性名與類的屬性名不要重復(fù)。