摘要:面向對象編程之旅編程是什么大家好,作為小白,最近學習了很多編程的知識,因為腦容量有限,特此一一按照學習順序記錄下來,如果哪里有錯誤,還請大神盡快指出,以免誤導他人。。。繼承也允許把一個派生類的對象作為一個基類對象對待。
Python面向對象編程之旅 OOP編程是什么
大家好,作為小白,最近學習了很多Python OOP編程的知識,因為腦容量有限,特此一一按照學習順序記錄下來,如果哪里有錯誤,還請大神盡快指出,以免誤導他人。。。
首先讓我們簡單了解一下何為面向對象編程:
把一組數據結構和處理它們的方法組成對象(object),把相同行為的對象歸納為類(class),通過類的封裝(encapsulation)隱藏內部細節,通過繼承(inheritance)實現類的特化(specialization)和泛化(generalization),通過多態(polymorphism)實現基于對象類型的動態分派。
這樣一說貌似有些復雜,簡單來看的話可以參考下面的解釋:
常見概念一覽概念 | 解釋 |
---|---|
類(Class) | 用來描述具有相同的屬性和方法的對象的集合。它定義了該集合中每個對象所共有的屬性和方法。對象是類的實例 |
類變量 | 類變量在整個實例化的對象中是公用的。類變量定義在類中且在函數體之外。類變量通常不作為實例變量使用 |
數據成員 | 類變量或者實例變量, 用于處理類及其實例對象的相關的數據 |
方法重寫 | 如果從父類繼承的方法不能滿足子類的需求,可以對其進行改寫,這個過程叫方法的覆蓋(override),也稱為方法的重寫 |
局部變量 | 定義在方法中的變量,只作用于當前實例的類 |
實例變量 | 在類的聲明中,屬性是用變量來表示的。這種變量就稱為實例變量,是在類聲明的內部但是在類的其他成員方法之外聲明的 |
繼承 | 即一個派生類(derived class)繼承基類(base class)的字段和方法。繼承也允許把一個派生類的對象作為一個基類對象對待。例如,有這樣一個設計:一個Dog類型的對象派生自Animal類,這是模擬"是一個(is-a)"關系(例圖,Dog是一個Animal) |
實例化 | 創建一個類的實例,類的具體對象 |
方法 | 類中定義的函數 |
對象 | 通過類定義的數據結構實例。對象包括兩個數據成員(類變量和實例變量)和方法 |
下面讓我們簡單定義一個汽車類:
class Car: def __init__(self, color, model, year): self.color = color self.model = model self.year = year
這里我們創建了一個汽車類Car,它有三個公共屬性,分別是color(顏色),model(型號),year(生產年份)
創建實例對象,訪問屬性現在讓我們新建一個對象my_car:
my_car = Car("yellow", "beetle", 1967)
查看一下my_car的屬性
print(f" My {my_car.color} car {my_car.model} is made in {my_car.year}") # My yellow car beetle is made in 1967添加新屬性
我們想要給my_car添加一個新屬性wheels
my_car.wheels = 5 print(f"Wheels: {my_car.wheels}") # Wheels: 5
使用dir(my_car)可以讓我們確認一下屬性是否存在:
dir(my_car) Out: ["__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__", "color", "model", "wheels", <====已經添加成功啦 "year"]類變量,修改類變量的值
在Python中,我們在類外聲明一個類變量,下面讓我們修改一下Car類:
class Car: wheels = 0 def __init__(self, color, model, year): self.color = color self.model = model self.year = year
這樣的話,我們在調用wheels這個變量時,可以通過實例,或者直接調用Car.wheels:
my_car = Car("yellow", "beetle", 1967) print(f"My car is {my_car.color}") print(f"It has {Car.wheels} wheels") print(f"It has {my_car.wheels} wheels") Out: My car is yellow It has 0 wheels It has 0 wheels
這里需要注意一下,如果想要通過my_car.wheels =xxx來修改wheels的值,不會真正修改類變量wheels的值,我們來看一個具體的例子:
my_car = Car("yellow", "Beetle", "1966") my_other_car = Car("red", "corvette", "1999") print(f"My car is {my_car.color}") print(f"It has {my_car.wheels} wheels") print(f"My other car is {my_other_car.color}") print(f"It has {my_other_car.wheels} wheels") Out: My car is yellow It has 0 wheels My other car is red It has 0 wheels
我們首先創建兩個實例my_car 和my_other_car ,默認的wheels=0,下面我們首先直接通過Car這個類來修改類變量的值:
# Change the class variable value Car.wheels = 4 print(f"My car has {my_car.wheels} wheels") print(f"My other car has {my_other_car.wheels} wheels") Out: My car has 4 wheels My other car has 4 wheels
可以看到這樣修改的話,Car類擁有的所有實例中的wheels值會被全部修改,如果我們通過my_other_car 來修改呢?
# Change the instance variable value for my_car my_car.wheels = 5 print(f"My car has {my_car.wheels} wheels") print(f"My other car has {my_other_car.wheels} wheels") Out: My car has 5 wheels My other car has 4 wheels
現在大家可以發現區別了,僅僅是修改了my_car中wheels的值,對類本身不會造成影響
私有和公有屬性在Python中的所有屬性都是public,可能有c++和java的同學覺得神奇,其實python最初規定了一種特殊的命名方式來區分public還是private,那就是下劃線_
我還是拿一樣的例子說明:
class Car: wheels = 0 def __init__(self, color, model, year): self.color = color self.model = model self.year = year self._cupholders = 6 my_car = Car("yellow", "Beetle", "1969") print(f"It was built in {my_car.year}") Out: It was built in 1969
這里Car類中的杯托 _cupholders就是“私有“屬性,為什么我這里加上了引號,是因為Python只是名義上規定這種寫法,但是在實際訪問上沒啥卵用,依然可以直接用._cupholders來訪問:
my_car.year = 1966 print(f"It was built in {my_car.year}") print(f"It has {my_car._cupholders} cupholders.") Out: It was built in 1966 It has 6 cupholders.
后來Python決定使用雙下劃線__來替換單下劃線,這樣可以最大程度避免“意外訪問“,然而還是沒有卵用,再來展示一下新方案:
class Car: wheels = 0 def __init__(self, color, model, year): self.color = color self.model = model self.year = year self.__cupholders = 6
其實某種程度上,這回效果還是很明顯的,如果我們還像剛才一樣嘗試調用my_car.cupholders 會報錯:
my_car = Car("yellow", "Beetle", "1969") print(f"It was built in {my_car.year}") print(f"It has {my_car.__cupholders} cupholders.") Out: It was built in 1969 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last)in 1 my_car = Car("yellow", "Beetle", "1969") 2 print(f"It was built in {my_car.year}") ----> 3 print(f"It has {my_car.__cupholders} cupholders.") AttributeError: "Car" object has no attribute "__cupholders"
這個錯誤很有意思,為什么會說cupholders這個變量不存在呢 ? 因為當Python看到__ 時,會自動在cupholders前面補上一個下劃線_和所屬類名,也就是說,這里我們嘗試用my_car.__cupholders 來調用時,Python默認的正確寫法是
my_car._Car__cupholders,現在再試一下:
print(f"It has {my_car._Car__cupholders} cupholders") Out: It has 6 cupholders
看見沒,依然沒攔住。。。。
不過我個人認為這種規定公有私有變量的方式也是好處多多,這里就仁者見仁,智者見智了~
就像剛剛提到的,Python所有的東西都是公有的,我們可以隨意的新增,修改,甚至刪除變量:
my_car = Car("yellow", "beetle", 1969) print(f"My car was built in {my_car.year}") my_car.year = 2003 print(f"It was built in {my_car.year}") del my_car.year print(f"It was built in {my_car.year}") Out: My car was built in 1969 It was built in 2003 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last)in 6 7 del my_car.year ----> 8 print(f"It was built in {my_car.year}") AttributeError: "Car" object has no attribute "year"
那我們如何才能控制屬性的訪問權限呢?Python給出的答案是裝飾器 @property,這個類似于Java中的setter和getter,現在我們試試:
class Car: def __init__(self, color, model, year): self.color = color self.model = model self.year = year self._voltage = 12 @property def voltage(self): return self._voltage @voltage.setter def voltage(self, volts): print("Warning: this can cause problems!") self._voltage = volts @voltage.deleter def voltage(self): print("Warning: the radio will stop working!") del self._voltage
我們新增了voltage(電壓)這個屬性,并用property來控制外部的訪問權限,這里我們定義了三個方法,利用setter方法可以改變voltage的值,利用getter方法來訪問,利用deleter方法實現刪除,接下來讓我們新建實例來看看propert是如何工作的:
my_car = Car("yellow", "beetle", 1969) print(f"My car uses {my_car.voltage} volts") my_car.voltage = 6 print(f"My car now uses {my_car.voltage} volts") del my_car.voltage Out: My car uses 12 volts Warning: this can cause problems! My car now uses 6 volts Warning: the radio will stop working!
可以發現,我們這里直接使用.voltage 而不是._voltage,這樣就告訴python去使用property裝飾的方法,我們可以通過使用@.setter and @.deleter 使屬性變為read-only(只讀),從而保護voltage不會被隨意修改和刪除
總結今天主要總結了OOP編程中的類,對象,屬性,公有私有屬性,訪問權限這些基礎概念,下一篇文章會進一步深入,如果本文有哪些語言使用不當,希望大家可以指出,讓我們一起進步!
我之前的一些文章已經放到了Github上,如果感興趣的朋友可以去看看,鏈接如下:
Python 精品練習題100道
Python 實用技巧匯總
Python Pandas教程
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/45174.html
摘要:面向對象編程,簡稱,是一種程序設計思想。面向過程與面向對象面向過程的程序設計把函數作為程序的基本單元。以上是在計算機世界里認識面向對象和面向過程,接下來給大家舉個生活中的例子就拿你早上想吃雞蛋灌餅為例。 面向對象編程——Object Oriented Programming,簡稱OOP,是一種程序設計思想。OOP把對象作為程序的基本單元,一個對象包含了數據和操作數據的函數。 面向過程 ...
摘要:時代,如果需要手動繼承,如多態多態是指,不同的子類對象調用相同的父類方法,會產生多態多樣結果的編程特性。 參考:黑馬程序員教程 - Python基礎 面向對象 OOP三大特性,且三個特性是有順序的: 封裝 繼承 多態 封裝 指的就是把現實世界的事務,封裝、抽象成編程里的對象,包括各種屬性和方法。這個一般都很簡單,不需要多講。 唯一要注意的就是:推薦從小往大開始封裝、開發類。比如手槍...
摘要:一面向對象編程。是一門面向對象的編程語言,通過對象實現對方法的調用。面向過程的程序設計把計算機程序視為一系列的命令集合,即一組函數的順序執行。對于面向對象語言,重要的概念是類和實例。 一、preface 面向對象編程OOP:object oriented programming。OOP把對象作為程序的基本單元,一個對象包含了數據和操作數據的函數。Python是一門面向對象的編程語言,...
摘要:反對者在某些領域對此予以否認。下面再引用一段來自維基百科中關于的歷史。類的更嚴格的定義是由某種特定的元數據所組成的內聚的包。類還可以有運行時表示形式元對象,它為操作與類相關的元數據提供了運行時支持。 在開始部分,請看官非常非常耐心地閱讀下面幾個枯燥的術語解釋,本來這不符合本教程的風格,但是,請看官諒解,因為列位將來一定要閱讀枯燥的東西的。這些枯燥的屬于解釋,均來自維基百科。 1、問題...
摘要:新的稱為子類,而被繼承的稱為基類父類或超類。繼承最大的好處是子類獲得了父類的全部功能。在繼承關系中,如果一個實例的數據類型是某個子類,那它的數據類型也可以被看做是父類。 在上一篇中我們介紹了模塊和數據結構,這一篇將介紹面向對象編程。 面向對象編程 面向對象編程——Object Oriented Programming,簡稱 OOP,是一種程序設計思想。OOP 把對象作為程序的基本單元...
閱讀 2860·2019-08-30 15:44
閱讀 1887·2019-08-29 13:59
閱讀 2845·2019-08-29 12:29
閱讀 1090·2019-08-26 13:57
閱讀 3202·2019-08-26 13:45
閱讀 3330·2019-08-26 10:28
閱讀 825·2019-08-26 10:18
閱讀 1695·2019-08-23 16:52