面向過程 面向對象:
面向過程:—側重于怎么做?
1.把完成某一個需求的 所有步驟 從頭到尾 逐步實現
2.根據開發要求,將某些功能獨立的代碼封裝成一個又一個函數
3.最后完成的代碼,就是順序的調用不同的函數
特點:
1.注重步驟和過程,不注重職責分工
2.如果需求復雜,代碼變得非常復雜
3.開發復雜的項目的時候,沒有固定的套路,開發難度很大
面向對象:----側重于誰來做?
相比較函數,面向對象是更大的封裝,根據職責在一個對象中封裝多個方法
1.在完成某一個需求前,首先確定職責–要做的事(方法)
2.根據職責確定不同的對象,在對象內部封裝不同的方法(多個)
3.最后完成代碼,就是順序的讓不同的對象調用不同的方法
特點:
1.注重對象和職責,不同的對象承擔不同的職責
2.更加適合對復雜的需求變化,是專門應對復雜項目的開發,提供固定的套路
3.需要在面向過程的基礎上,再學習一些面向對象的語法
面向過程—>側重于怎么做?
面向對象—>測中于誰來做?
區別與應用場景:
面向過程:復雜的問題流程化,簡單化,側重于怎么做
應用場景:不再需要擴展了,監測腳本,自動部署腳本,軟件解壓安裝
面向對象:特征與技能的結合體 一切皆對象,側重于誰來做
應用場景:用戶需求經常變化,互聯網應用,游戲,企業內部應用
面向對象有兩個核心的概念
類:是一類具有相同特征或行為的事物的一個統稱
對象:由類創建出來的一個具體的存在
類和對象的關系:先有類再有對象
類是模板 對象是根據這個模板創建出來的
類只需要有一個 對象可以有多個
類:屬性(這一類事務的共同信息) 和 方法(你能完成的動作)
1.類名:這類事物的名字(大駝峰命名法)
大駝峰命名法:
1.每個單詞的首字母大寫
2.單詞與單詞之間沒有下劃線
2.屬性:這個類創建出來的對象有什么特征
3.方法:這個類創建出來的對象有什么行為
類名的確定
名詞提煉法分析整個業務流程,出現的名詞,通常就是找到的類
屬性和方法的確定
對 對象的特征描述,通常可以定義成屬性
對象具有的行為(動詞),通常可以定義為方法
提示:需求中沒有涉及的屬性或方法在設計類時,不需要考慮
類的屬性和對象的屬性的區別:
類的屬性:數據屬性和函數屬性,數據屬性是所有對象共有的,函數屬性是綁定對象使用的
對象的屬性:對象是類的實例化
類和對象在內存中是如何保存的
類是在定義階段便生成命名空間,以字典形式保存。通過__dict__查看
對象以字典形式保存。
self:
哪一個對象調用的方法,self就是哪一個對象的引用;
在封裝的方法內部,self就表示當前調用方法對象自己;
self.name :接受外部傳遞的參數。
# 定義一個貓類
class Cat:def eat(self):print('%s 愛吃魚' %(self.name))def drink(self):print('小貓要喝水')# 創建貓對象
# print(Cat())
tom = Cat()
tom.name = 'Tom'
print(tom.name)
print(tom)
tom.drink()
tom.eat()
初始化方法:
類名() 就可以創建一個對象
類名() 創建對象的時候,python解釋器會自動執行以下操作
1.為對象在內存中分配空間–創建對象
2.調用初始化方法為對象的屬性設置初始值
這個初始化方法是內置方法,是專門用來定義一個類據有哪些屬性和方法的
class Cat:def __init__(self, new_name):# print('這是一個初始化方法')self.name = new_namedef eat(self):print('%s愛吃魚' % (self.name))def drink(self):print('%s要喝水' % (self.name))
hello_kitty = Cat('hello_kitty')
print(hello_kitty)
hello_kitty.eat()
hello_kitty.drink()
tom = Cat('藍貓')
tom.drink()
tom.eat()
如果希望在創建對象的同時,就設置對象的屬性,可以對__init__方法進行改造
1.把希望設置的屬性值,定義成__init__方法的參數
2.在方法內部使用self.屬性名 = 形參 接收外部傳遞的參數
3.在創建對象的時候,使用類名(屬性)調用
str:在python中 使用print輸出對象變量時候,默認情況下
會輸出這個變量引用的對象是由哪一個類創建的對象以及在內存中的地址
如果在開發中,希望使用print輸出變量的時候,能夠打印自定義內容
就可以利用__str__這個內置的方法了
class Cat:def __init__(self,name):self.name = name# def __str__(self):# # 返回必須是一個字符串# return '我是 %s' %(self.name)
tom = Cat('tom')
print(tom)
addr = id(tom)
print(addr)
print('%x' %(addr))
print('%d' %(addr))
fentiao = Cat('粉條')
print(fentiao)
del:如果希望在對象被銷毀之前,再做一些事情,可以考慮一下__del__
當一個對象被從內存中銷毀前(把這個對象從內存中刪除掉),
會自動調用 __del__方法
class Cat:def __init__(self,name):self.name = nameprint('%s 來了' %(self.name))def __del__(self):print('%s 走了' %(self.name))tom = Cat('tom')
print(tom.name)
del tom
print('*' * 50)
print(tom.name)
棧:先進后出 入棧(push) 出棧(pop) 取棧頂元素 判斷棧是否為空 ,顯示棧元素、列表
隊列:先進先出
class Stack:def __init__(self):self.stack = []def push(self,value):""":param value:入棧元素:return:"""self.stack.append(value)return Truedef pop(self):# 判斷棧是否為空if self.stack:# 獲取出棧元素 并返回item = self.stack.pop()return itemelse:return Falsedef top(self):if self.stack:return self.stack[-1]else:return Falsedef length(self):return len(self.stack)def view(self):return ','.join(self.stack)s = Stack()
s.push('1')
s.push('2')
s.push('3')
item = s.pop()
print(s.view())
面向對象的三大特點:
1 . 封裝:
1.封裝是面向對象編程的一大特點
2.面向對象編程的第一步 將屬性和方法封裝到一個抽象的類中
3.外界使用類創建對象,然后讓對象調用方法
4.對象方法的細節都被封裝在類的內部
需求
1.小明體重75.0公斤
2.小明每次跑步都會減肥0.5公斤
3.小明每次吃東西體重都會增加1公斤
需求
1.小明和小美都愛跑步
2.小美體重45.0公斤
2.每次跑步都會減肥0.5公斤
3.每次吃東西體重都會增加1公斤
class Person:def __init__(self,name,weight):self.name = nameself.weight = weightdef __str__(self):return '我的名字叫 %s 體重是 %.2f' %(self.name,self.weight)
# 在對象的方法內部,是可以直接訪問對象的屬性的def run(self):print('%s 去跑步~~~~' %(self.name))self.weight -= 0.5def eat(self):print('%s 去吃東西~~~' %(self.name))self.weight += 1
xiaoming = Person('小名',75.0)
xiaoming.run()
xiaoming.eat()
print(xiaoming)
xiaomei = Person('小美',45.0)
xiaomei.eat()
print(xiaomei)
查看學生的分數的及等級
class Student:def __init__(self,name,score):"""初始化方法 當創建實例的時候會調用這個方法"""self.name = nameself.score = scoredef get_grade(self):"""對數據進行封裝"""print('my name is %s' %(self.name))if self.score > 90:print('Your grade is A')elif self.score > 75:print('Your grade is B')else:print('Your grade is C')
tom = Student('tome',80)
tom.get_grade()
一個對象的屬性 可以是另一個對象創建的類
需求:
1.房子有戶型,總面積和家具名稱列表
新房子是沒有家具的
2.家具有名字和占地面積,其中
eg:占地 6平方米
3.將以上三件家具添加到房子中
4.打印房子的時候,要求輸出:戶型 總面積 剩余面積 家具名稱列表
class HouseItem:# 初始化方法def __init__(self,name,area):self.name = nameself.area = areadef __str__(self):return '[%s] 占地 %.2f' %(self.name,self.area)class House:def __init__(self,house_type,area):self.house_type = house_typeself.area = area# 剩余面積self.free_area = areaself.item_list = []def __str__(self):return ('戶型:%s\n總面積:%.2f[剩余:%.2f]\n家具:%s'%(self.house_type,self.area,self.free_area,self.item_list))def add_item(self,item):# 判斷家具的面積if item.area > self.free_area:print('%s 的面積太大了,無法添加' %(item.name))return# 要將家具的名稱添加到列表中去self.item_list.append(item.name)# 計算剩余面積self.free_area -= item.area
# 創建家具
bed = HouseItem('床',4)
print(bed)
chest = HouseItem('chest',600)
print(chest)
table = HouseItem('table',1.9)
print(table)
# 創建房子對象
my_home = House('兩室一廳',90)
# 將家具添加到房子里面去
my_home.add_item(bed)
my_home.add_item(chest)
my_home.add_item(table)
print(my_home)
# 一個對象的屬性 可以是另一個對象創建的類
1.士兵瑞恩有一把AK47
2.士兵可以開火(士兵開火扣動的是扳機)
3.槍 能夠 發射子彈(把子彈發射出去)
4.槍 能夠 裝填子彈 --增加子彈的數量
class Gun:def __init__(self,model):self.model = modelself.bullet_count = 0def add_bllet(self,count):self.bullet_count += countdef shoot(self):if self.bullet_count <= 0:print('%s 沒有子彈了...' %(self.model))returnself.bullet_count -= 1print('%s ~~~~%s' %(self.model,self.bullet_count))class Soldier:def __init__(self,name):self.name =nameself.gun = Nonedef fire(self):if self.gun == None:print('%s 還沒有槍...' %(self.name))returnself.gun.add_bllet(50)self.gun.shoot()ak47 = Gun('ak47')
# ak47.add_bllet(50)
# ak47.shoot()
ryan = Soldier('Ryan')
ryan.gun = ak47
ryan.fire()
ryan.fire()
2 . 繼承:
實現代碼的重用,相同的代碼不需要重復的寫
class Animal:def eat(self):print('吃~~~')def drink(self):print('喝~~~')def run(self):print('跑~~~')def sleep(self):print('睡~~~')
class Cat(Animal):def call(self):print('瞄喵~~')
class Dog(Animal):def bark(self):print('汪汪~~')fentiao = Cat()
fentiao.run()
fentiao.eat()
fentiao.sleep()
fentiao.drink()
fentiao.call()dahuang = Dog()
dahuang.eat()
dahuang.drink()
dahuang.run()
dahuang.sleep()
dahuang.bark()
繼承具有傳遞性
當父類方法的實現不能滿虛子類的需求的時候
可以對方法進行重寫
1.覆蓋父類方法
2.對父類方法進行擴展
lass Animal:def eat(self):print('吃~~~')def drink(self):print('喝~~~')def run(self):print('跑~~~')def sleep(self):print('睡~~~')class Cat(Animal):def call(self):print('瞄喵')class HelloKitty(Cat):def speak(self):print('我可以說日語')def call(self):# 調用原本在父類中封裝的方法super().call()# Cat.call(self) python2.x# 針對子類特有的需求,編寫代碼print('##@!#@!#')
kt = HelloKitty()
kt.call()
kt.speak()
kt.eat()
kt.drink()
kt.run()
kt.sleep()
擴展父類方法示例:
class Bird:def __init__(self):self.hungry = True
# 鳥吃過了以后,它就不再饑餓def eat(self):if self.hungry:print('Akkkk~')self.hungry = Falseelse:print('No Thanks')# 在鳥類的基礎上 增加唱歌的功能
class SongBird(Bird):def __init__(self):self.sound = 'dsadsda'super().__init__()def sing(self):print(self.sound)bird = Bird()
bird.eat()
littlebird = SongBird()
littlebird.eat()
littlebird.sing()
子類同時繼承兩類示例:
class A:def test(self):print('A----test方法')def demo(self):print('A-----demo方法')
class B:def test(self):print('B----test方法')def demo(self):print('B----test方法')class C(B,A):passc = C()
c.test()
c.demo()
新式類和舊式(經典)類:
object是Python為所有對象提供的基類,提供有一些內置的屬性和方法,可以使用dir函數查看
新式類:以object為基類的類
經典類 不以object為基類的類
在python3.X中定義的類時,如果沒有指定父類,會默認使用object作為基類–python3.x中定義的類都是新式類
在python2.x中定義類時,如果沒有指定父類,則不會以object作為基類
為保證編寫的代碼能夠同時在python2.x和python3.x運行
今后在定義類時,如果沒有父類,建議統一繼承自object
>>> class A:
... pass
...
>>>
>>> dir(A)
['__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__']
>>> class B(object):
... pass
...
>>> dir(B)
['__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__']"""
class A(object):pass
3 . 多態:
多態(以封裝和繼承為前提)
不同的子類對象調用相同的方法,產生不同的執行結果
class Dog(object):def __init__(self,name):self.name = namedef game(self):print('%s 開心的玩~' %(self.name))
class Gaofei(Dog):# 父類方法不能滿足子類的需求,重寫game方法def game(self):print('%s和米老鼠一起玩~~~' %(self.name))
class Person(object):def __init__(self,name):self.name = namedef game_with_dog(self,dog):print('%s和%s玩' %(self.name,dog.name))
# 創建一個狗對象
#wangcai = Gaofei('高飛')
wangcai = Dog('大黃')
# 創建一個人對象
xiaoming = Person('小明')
# 讓小明和狗玩
xiaoming.game_with_dog(wangcai)
類屬性:針對類對象定義的屬性 使用賦值語句在class關鍵字下可以定
義類屬性
類方法:針對類對象定義的方法 在類方法內部可以直接訪問類屬性或者調用
其他的類方法
class Toy(object):# 使用賦值語句定義類屬性,記錄所有的玩具的數量count = 0def __init__(self,name):self.name = name# 讓類屬性 +1Toy.count += 1@classmethoddef show_toy_count(cls):print('玩具對象的數量 %d' %(cls.count))
# 創建玩具對象
# toy1 = Toy('樂高')
# toy2 = Toy('泰迪熊')
# 調用類方法
Toy.show_toy_count()
靜態方法:非綁定方法,類和對象都可以調用
class Cat(object):@staticmethoddef call():print('喵')
# 通過 類名. 調用靜態方法
Cat.call()
# 不需要創建對象 直接就可以調用
私有屬性和私有方法:
class Student(object):def __init__(self,name,score):# 前面帶兩個下劃線表示對變量進行私有化,# 外部不能隨便的訪問和更改self.__name = nameself.__score = scoredef get_grand(self):print('my name is %s,my ''grade is %d' %(self.__name,self.__score))def get_name(self):return self.__namedef get_score(self):return self.__scoredef set_name(self,name):if isinstance(name,str):self.__name = nameelse:raise ValueError('請輸入正確的名字')def set_score(self,score):if isinstance(score,int):self.__score = scoreelse:raise ValueError('請輸入正確的成績')tom = Student('Tom',89)
# print(tom.name)
# print(tom.score)
tom.get_grand()
# print(tom._Student__name)
#tom.__name = 'new name' # 這樣做只是給實例添加了__name的屬性,并不是
# 修改私有屬性變量
tom.set_name(321321)
tom.set_score(90)
print(tom.get_name())
print(tom.get_score())
設計模式——單例
單例設計模式
設計模式
設計模式是前人工作的總結和提煉,通常,被人們廣泛流傳的設計模式都
是針對某一特定問題的成熟解決方案
使用設計模式是為了可重用代碼,讓代碼更容易被他人理解,
保證代碼可靠性
單例設計模式
目的:讓類創建對象,在系統中只有唯一的一個實例
每一次執行類名()返回的對象
內存地址是相同的
使用__new__(cls)方法實現單例設計模式:
我們用 類名. 的方式創建對象的時候,python解釋器會幫我們做兩件事情
1.為對象分配空間
2.對象初始化
__new__是一個由object基類提供的內置的靜態方法,主要有兩個作用:
在內存中為對象分配空間
返回對象的引用
python的解釋器獲得對象的引用后,將引用作為第一個參數,傳遞給__init__方法
#new:負責給對象分配空間 init(初始化方法)負責給對象初始化
class MusicPlayer(object):instance = Nonedef __new__(cls, *args, **kwargs):print('創建對象 分配空間')# 1.創建對象的時候,new方法會被自動調用#instance = object.__new__(cls)#return instance #返回的是對象的引用# 判斷類屬性是否是空對象if cls.instance is None:# 調用父類方法 為第一個對象分配空間cls.instance = object.__new__(cls)return cls.instanceplayer1 = MusicPlayer()
player2 = MusicPlayer()
player3 = MusicPlayer()print(player1)
print(player2)
print(player3)