CC00020.python——|HadoopPython.v20|——|Arithmetic.v20|语法:进阶面向对象.V2|
生活随笔
收集整理的這篇文章主要介紹了
CC00020.python——|HadoopPython.v20|——|Arithmetic.v20|语法:进阶面向对象.V2|
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、面向對象 ### --- 面向對象基本概念~~~ # 面向過程:
~~~ 根據業務邏輯從上到下寫代碼。
~~~ # 面向對象:
~~~ 將變量與函數、屬性綁定到一起,分類進行封裝,每個程序只要負責分配給自己的功能,
~~~ 這樣能夠更快速的開發程序,減少了重復代碼。
~~~ 我們在前面寫的代碼都是面向過程的,這對初學者比較容易接受,
~~~ 而且,對于比較簡單的需求,用面向過程實現起來確實更簡單。 ### --- 那什么是對象呢 ?~~~ 我們可以理解為實際存在的實物,比如一個用戶、一臺ATM機、一幢建筑,
~~~ 亦或者是軟件業務流程中產生的虛擬概念,比如訂單、購物車、用戶賬戶。
~~~ 我們發現,不管是實體還是虛擬產物,它們都是有一些共同點,都是名詞,有自己的行為,
~~~ 有自己的屬性。比如說用戶對象,用戶都有相同的幾個屬性,名字、年齡、性別、注冊時間、
~~~ 上一次登錄的時間等等。但不同用戶這個幾屬性的值卻都不一樣。下面我們來看幾個例子。
~~~ 如果你想向另一個人描述一只狗, ### --- 那你會說出這只狗的哪幾個特點?
~~~ 品種
~~~ 顏色
~~~ 體型大小~~~ # 狗會有哪些行為呢?
~~~ 吃東西
~~~ 奔跑
~~~ 吠叫
~~~ 這些都是我們基于常識總結出來的狗的特點和行為,
~~~ 對象的屬性就是可以精確描述事物的特點,對象的函數就是事物的行為。 二、類和實例 ~~~ # 現在我們用代碼來實現一下“狗”對象先介紹Python里的一個重要概念:類它也是面試對象編程的基礎。
class Dog:
pass~~~ # 這樣我們就定義了一個類,使用class關鍵字,加上一個類名,這樣我們就定義了一個空的類。
~~~ 類名一般使用名詞,且使用駝峰式命名法。 ~~~ # 類是創建對象的模板,對象是類的實例。類就像生產線,有了類,就可以生產出許許多多的相同對象。
~~~ # 使用上面的Dog類來創建一個Dog對象:
dog = Dog()
type(dog)~~~ # 這里dog就是Dog的實例,通過內置的type函數,可以查看任何對象的類。
type(1)
type('abc')
type([]) ~~~ # 這些都是我們學習過的數據類型,我們看到它們分別是整數、字符串和列表。那dog的類型就是Dog。
~~~ # 如果我們不知道一個對象是不是某種類型,就可以用type判斷。
type('abc') == str # True
type(dog) == Dog # True
type(1) == int # True~~~ # 也可以使用內置函數isinstance來判斷對象與類的關系
isinstance('abd', str) # True
isinstance(1, int) # True
isinstance(dog, Dog) # True 三、對象的屬性與方法 ### --- 現在我們來完整的實現一下Dog類:class Dog:
def __init__(self):
self.breed = None
self.color = None
self.size = None
def eat(self):
print("I like bones")
def run(self):
print("I'll catch you.")
def bark(self):
print('Wang! Wang!') ~~~ # 大家應該注意到,類的每一個方法的第一個參數是self ,但在調用的時候卻不需要傳參數給它。它是類方法和普通函數的區別,這個self代表的是實例自身,意思是“我的”,現在我們來創建Dog的實例dog = Dog()
dog.eat()
dog.run()
dog.bark()
print('一只%s型%s色的%s' % (dog.size, dog.color, dog.breed)) ~~~ # 調用不同的方法能打印出不同的內容,體現了不同的行為。但是最后一句話打印出來的內容卻是None,因為我們還沒有設置相應的屬性。dog.breed = '哈士奇'
dog.color = '黑白'
dog.size = '大'
print('一只%s型%s色的%s' % (dog.size, dog.color, dog.breed))~~~ # 一只大型黑白色的哈士奇 ~~~ # 如果每個創建完每個對象之后還要一個個的設置屬性,會很麻煩。我們可以使用__init__ 函數來接收初始化參數,這樣就可以把屬性的值作為參數在初始化對象的時候就傳給它。大家應該也注意到了,__init__ 函數看起來與眾不同的樣子,它是Python的類用來初始化對象的構造函數,它的名字是固定的,必須這樣寫,創建對象時會首先調用它。改完后構造函數后代碼如下:class Dog:
def __init__(self, size, color, breed='土狗'):
self.breed = breed
self.color = color
self.size = size
def eat(self):
print("I like bones")
def run(self):
print("I'll catch you.")
def bark(self):
print('Wang! Wang!') ~~~ # 現在再來創建對象:dog = Dog('中', '黃')
print('一只%s型%s色的%s' % (dog.size, dog.color, dog.breed)) ~~~ # 第三個參數breed因為給了它默認值,所以可以不用傳。
~~~ # 我們在之前學習的字符串、列表的所有函數,實際是調用字符串對象、列表對象的方法。
~~~ # 對象自身的屬性是直接可以方法里使用的,比如我們改造一下bark方法,讓狗可以開口自我介紹class Dog:
def __init__(self, size, color, breed='土狗'):
self.breed = breed
self.color = color
self.size = size
def eat(self):
print("I like bones")
def run(self):
print("I'll catch you.")
def bark(self):
print('我是一只%s型%s色的%s' % (self.size, self.color, self.breed)) ~~~ # 這里在bark方法里使用的self和構造函數里的self一樣,都是指向對象自身。dog = Dog('中', '黃')
print('一只%s型%s色的%s' % (dog.size, dog.color, dog.breed)) 四、類屬性與方法 ~~~ # 對象是從類創造的,對象的屬性和方法雖然是在類中定義的,但它們的值是各個對象獨有的,互相不能共享。而類也有屬性和方法,且它們可以和類創建的所有對象共享。我們先來定義一個類class Goods:
def __init__(self):
self.name = ''
self.price = 0
self.discount = 1 ~~~ # Goods類有三個對象屬性,每個商品有自己的名稱、價格、折扣。我可以隨意的創建商品g1 = Goods()
g2 = Goods() ~~~ # 但如何知道一共創建了多少個商品呢?我們可以給Goods類加一個計數器。class Goods:
count = 0
def __init__(self):
Goods.count += 1
self.name = ''
self.price = 0
self.discount = 1 ~~~ # 我們給Goods類加了一個屬性count,每當調用__init__ 函數時將它加1,這樣我們就可以知道一共創建了多少商品對象了。這個count就是類屬性,它可以通過對象訪問,也可以通過類訪問。g1 = Goods()
g1.count # 1
g2 = Goods()
Goods.count # 2 ~~~ # 即使沒有定義對象,也可以直接訪問count屬性,這就是類屬性,同樣,類方法也不需要創建對象,通過類名就可以訪問。我們改造一下Goods類,給它增加一個屬性id,表示商品唯一的序列號,為了保證id不重復,我們使用計數器,每創建一個商品給它加1。class Goods:
id_count = 0
@classmethod
def generate_id(cls):
cls.id_count += 1
return cls.id_count
def __init__(self): ~~~ # zfill函數表示用“0”將數字補足5位self.id = str(self.generate_id()).zfill(5)
self.name = ''
self.price = 0
self.discount = 1 ~~~ # 這里的generate_id 方法就是一個類方法,它的上面一行有一個@classmethod ,聲明了它是類方法,它的參數不再是self,而是cls,指向類本身,用來在類方法內部訪問類成員屬性和方法。這個方法每次將id_count屬性加1,并返回。~~~ 這種@ 符號的寫法叫做裝飾器,裝飾器是用來裝飾函數的,不同的裝飾器賦予函數不同的特殊功
~~~ 能。對于classmethod裝飾器,大家只要知道它是用來定義類方法的就行了。 ~~~ # 現在我們再來試試:g1 = Goods()
g2 = Goods()
g1.id # 00001
g2.id # 00002
Goods.id_count # 2 五、一切皆對象 ~~~ # 在Python中一切都是對象,我們使用的數字、字符串、函數甚至類本身,都是對象。所有的對象都可以用type函數來判斷它的類型,同時可以用dir函數來查看它的屬性和方法。dir(dog) ~~~ # 會顯示出dog對象的所有屬性和方法,包括剛剛定義的那幾個方法和屬性。對于對象,也可以使用help函數查看它的幫助文檔。help(sum)
help(print) ~~~ # 這些幫助信息可以在定義的時候寫入到代碼里:def bark(self):
"""一只狗的自我介紹"""
print('我是一只%s型%s色的%s' % (self.size, self.color, self.breed)) ~~~ # 加上這句文檔后,我們就可以使用help函數查看bark方法的幫助信息了,這有助于其他人使用我們的方法。help(dog.bark)
help(Dog.bark) ~~~ # 一切皆對象是一句簡單的話,但它的精神卻很深邃,試試下面的代碼,你還能看得懂嗎?lst = []
lst.append(Dog)
dog = lst[0]('中', '黃')
lst.append(dog)
lst[1].bark()
lst[1].sleep = lambda: print('Good night.')
lst.pop().sleep() ~~~ # 有時候兩個對象的值完全相同,我們可以說這兩個對象是相等的,但不能說它們是同一個對象。l1 = [1, 2, 3]
l2 = [1, 2,]
l1 == l2 # False
l2.append(3)
l1 == l2 # True
l1 is l2 # False ~~~ # 最后一行操作,使用is 關鍵字來判斷這兩個對象是否是同一個對象,結果是False。它表明l1和l2是不同的對象,這一點可以使用id函數看出來:
~~~ # 分別返回兩串不同的數字,這個一長串的數字代表了對象所指向的內存空間地址。id(l1)
id(l2) 六、綜合案例-電商購物車商品統計分析 ### --- 項目需求~~~ 可以設置每個商品的名稱、價格、折扣率,用戶將商品加入到購物車以后,
~~~ 能夠立即顯示所有商品、總價、折扣情況和實際需要支付的金額,也就是折扣后的金額。
~~~ 商品的名稱、價格、折扣率都可以隨意修改,且修改完成后,
~~~ 購物車中的相關信息和金額也會發生改變。
~~~ 需求分析:在這個需求里面,提到了兩個虛擬產物,商品與購物車,也就是說需要定義兩個類。 ### --- 編程實現class Goods:"""商品類"""id_count = 0\@classmethoddef generate_id(cls):cls.id_count += 1return cls.id_countdef __init__(self, name, price, discount=1):self.id = str(self.generate_id()).zfill(5)self.name = nameself.price = priceself.discount = discountdef calc_price(self):"""計算商品打折后的實際價格"""return self.price * self.discount ### --- 這是商品類,它有四個屬性:ID、商品名稱、價格、折扣,另外它還有一個函數,計算出商品打完折后的價格。接下來我們來創建幾個商品對象:g1 = Goods('iPhone 11', 6000, 0.9)
g2 = Goods('U盤32G', 100, 0.8)
g3 = Goods('華為P40', 5000) ### --- 這樣我們就創建了三個商品對象,并設置好了它們的名稱、價格、折扣。接下來我們來編寫購物車類:class Cart:"""購物車"""def __init__(self):self.cart = {}self.goods_list = []def add(self, goods, num=1):"""向購物車中添加商品"""if goods in self.goods_list:self.cart[goods.id] = self.cart[goods.id] + numelse:self.goods_list.append(goods)self.cart[goods.id] = numdef remove(self, goods, num):"""從購物車減少或刪除商品"""if goods not in self.goods_list:return self.cart[goods.id] -= numif self.cart[goods.id] <= 0:del self.cart[goods.id] self.goods_list.remove(goods)def get_goods_by_id(self, id):"""根據商品名稱查找商品"""for g in self.goods_list:if g.id == id:return gdef get_total_amount(self):"""獲取當前購物車中的總價"""amount = 0for name, num in self.cart.items():goods = self.get_goods_by_id(name)amount += goods.price * numreturn amountdef get_pay_amount(self):"""獲取實際需要支付的總價"""amount = 0for name, num in self.cart.items():goods = self.get_goods_by_id(name)amount += goods.calc_price() * numreturn amountdef show(self):"""顯示當前購物車中所有商品的數量、價格,以及總價"""title = ('商品', '單價', '數量', '價格(元)')def show_row(row):"""內部函數,顯示購物車中的一行"""for col in row:print(str(col).ljust(12), end='\t')print()print("-" * 70)show_row(title)for id, num in self.cart.items():goods = self.get_goods_by_id(id)price = '%.2f' % goods.priceif goods.discount < 1:price = '%.2f (%d折)' % (goods.price, goods.discount * 10)show_row((goods.name, price, num, '%.2f' % (goods.calc_price() * num))) total_amount = self.get_total_amount()pay_amount = self.get_pay_amount() discount_amount = total_amount - pay_amountshow_row(('', '', '', '總金額: %.2f' % total_amount))if discount_amount > 0:show_row(('', '', '', '優惠: %.2f' % discount_amount))show_row(('', '', '', '實付金額: %.2f' % pay_amount)) ### --- 這是購物車類,看起來它的代碼很長。共有兩個屬性,6個方法。其實這個類主要就是提供了三個功能:
~~~ 增加商品 add
~~~ 減少商品 remove
~~~ 顯示商品 show
~~~ 其他的函數都是輔助實現這三個主要功能。cart是一個字典,用來保存商品和數量的對應關系,它的鍵名是商品ID(字符串);goods_list是一個列表,保存了購物車所有商品的詳細信息(商品類實例),注意它們的數據結構。
~~~ 有了Goods和Cart,我們就可以隨意的增加刪除商品,并可以隨時查看購物車里的情況。cart = Cart()
cart.add(g1)
cart.add(g2, 3)
cart.show() ### --- 顯示如下:商品 單價 數量 價格(元)
iPhone 11 6000.00 (9折) 1 5400.00
U盤32G 100.00 (8折) 3 240.00
總金額: 6300.00
優惠: 660.00
實付金額: 5640.00 ### --- 我們可以繼續增加或者刪除,并隨時可以查看購物車的商品、計算總金額。如果商品的數量為零,則會從購物車中被刪除cart.remove(g2, 2)
cart.show()
cart.remove(g2, 1)
cart.show() ### --- 如果商品的名稱、價格或者折扣發生了變化,我們只需要修改商品對象就可以了,其他的代碼都不用修改,購物車中的信息會實時的跟隨調整。
~~~ # 可以看到,在修改了g3對象的商品名稱之后,再次顯示購物車時發生了變化 ,而我們的Cart類不用修改任何代碼,這樣做到了不同實體之間的操作隔離,是不是有點感受到面向面向對象的便捷了呢?cart.add(g3)
cart.show()
g3.name = '華為P40 pro'
cart.show() 七、自定義屬性-property ### --- Cart類中的這兩個函數get_total_amount 和get_pay_amount ,每次調用它們的時候都是直接調用,沒有傳遞任何參數,最后返回一個值。對于這種方法,其實可以把它們變成property(屬性):@property
def total_amount(self):"""獲取當前購物車中的總價"""amount = 0for name, num in self.cart.items():goods = self.get_goods_by_id(name)amount += goods.price * numreturn amount
@property
def pay_amount(self):"""獲取實際需要支付的總價"""amount = 0for name, num in self.cart.items():goods = self.get_goods_by_id(name)amount += goods.calc_price() * numreturn amount ### --- 我們在函數名前面加了一個property裝飾器,修改方法名,去掉了get_ ,其實方法名也可以不改,在這里修改是為了代碼的可讀性更通順。改造后,使用這兩個方法時,就可以像使用普通屬性一樣:
~~~ 這樣使用起來是不是更簡潔優雅了呢?
~~~ 繼承*
~~~ 魔術方法*cart.total_amount
cart.pay_amount
總結
以上是生活随笔為你收集整理的CC00020.python——|HadoopPython.v20|——|Arithmetic.v20|语法:进阶面向对象.V2|的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 协调计算机硬件和软件的中间层次,计算机的
- 下一篇: Python 的xlrd库读取日期和数字