Python——創建類和對象
####創建類和對象###
1.類的相關知識
類有兩種作用:屬性應用和示例化
(1)屬性的引用(類名.屬性)
定義一個類 --> 裏面定義一個屬性(但是這個屬性是寫死在程序裏的) --> 每一個引用這個屬性的都是一樣的內容
(2)實例化:類名加括號就是實例化,會自動觸發__init__函數的運行,可以用它來為每個實例定制自己的特有的屬性
關於類裏的方法括號中的self:
self 在實例化時自動將對象/實例本身傳給__init__的第一個參數
self 也可以說是:哪一個對象調用這個方法,self就是哪一個對象的引用
在類封裝的方法內部,self就表示當前調用方法的對象自己
--調用方法時,程序員不需要傳遞self參數(但是定義的時候,第一個參數必須是self)
--在方法內部:可以通過self.訪問對象的屬性
--在方法內部:可以通過self.調用其他的對象方法
示例:
class Cat:
"""這是class Cat的信息"""
def eat(self):
print ‘%s愛吃魚‘ %self.name
def drink(self):
print ‘%s要喝水‘%self.name
# 創建貓對象
tom = Cat()
# 可以使用 .屬性名 利用賦值語句就可以了
#tom.name = ‘Tom‘
tom.eat()
tom.name = ‘Tom‘
tom.drink()
print tom
# lazy_cat = Cat()
# lazy_cat.name = ‘miaomiao‘
# lazy_cat.eat()
# lazy_cat.drink()
2.內置方法
初始化方法:__init__是python對象的內置方法,在使用類名創建對象的時候自動被調用
__init__方法是專門用來定義一個類具有那些屬性和方法的
##如果不用初始化方法,像一些基本屬性可能在創建對象以後,還需要對象.屬性,這樣填寫屬性,還需要print手動去輸出它,添加這個初始化方法,在創建方法之後會主動調用這個方法,將填寫的信息添加並且輸出
##當初始化方法沒有形參變量的時候,方法內部所定義的屬性,在利用該類創建對象的時候,創建的所有對象都會擁有該屬性
##當初始化方法含有形參變量的時候,在利用該類創建對象的時候,創建的所有對象都會自動調用初始化方法,並且會要求添加相應的對象的屬性,如果不添加就執行的話,編譯器會報錯
__del__方法:對象被從內存中銷毀前,會自動調用
__str__方法:返回對象的描述信息 print 對象
__del__方法:在python中,當一個對象被從內存中銷毀前(把這個對象從內存中刪除掉),會自動調用__del__方法
應用場景:
__del__如果希望在對象被銷毀前,再做一些事情,可以考慮一下__del__方法
__str__方法:在python中,使用python輸出對象變量,默認情況下,會輸出這個變量引用的對象是由哪>一個類創建的對象,以及在內存中的地址(十六進制表示).如果在開發中,希望使用print輸出對象變量時,能夠打印自定義的內容,就可以利用__str__這個內置方法了
示例:
(1)
class Dog:
def __init__(self,name,weight):
self.name = ‘rourou‘
self.weight = weight
print ‘%s是一個%d斤的狗狗!‘%(self.name,self.weight)
def eat(self):
print ‘%s愛吃肉‘%self.name
def drink(self):
print ‘%s愛喝牛奶‘%self.name
rourou = Dog(‘rourou‘,10)
rourou.eat()
rourou.drink()
print rourou
(2)
class Dog:
def __init__(self,name,weight):
self.name = name
self.weight = weight
print ‘%s是一個%d斤重的狗狗!‘%(self.name,self.weight)
def __del__(self):
print ‘內存信息被刪除之前的調用!‘
def __str__(self):
return ‘我是肉肉!‘
dog = Dog(‘rourou‘,10)
print ‘=========‘
print dog
# tom是一個全局變量
# 所以當我們的代碼全部執行完之後,系統才會把tom這個對象進行回收
tom = Cat(‘Tom‘)
print tom
# print tom.name
# # del關鍵字,可以從內存中刪除一個對象,del關鍵字自己調用了__del__方法
# del tom
# print ‘*‘ * 50
生命周期
一個對象從調用類名()創建,聲明周期開始
一個對象的__del__方法一旦被調用,生命周期就結束
在對象的生命周期內,可以訪問對象的屬性,調用對象的方法
3.私有屬性和私有方法
(1)私有屬性和私有方法:在屬性或方法前加兩個下劃線 ‘__‘,聲明該方法是私有方法或者屬性,不能在類的外部調用。在類的內部可以調用
私有屬性 就是 對象 不希望公開的 屬性
私有方法 就是 方法 不希望公開的 方法
(2)應用場景及定義方式:
應用場景:
在實際開發中,對象的某些屬性或方法可能只希望在對象的內部使用,而不希望在外部被訪問到
定義方法:
在定義屬性或方法時,在屬性名或者方法名前增加兩個下劃線,定義的就是私有屬性或方法
示例:
class Women:
def __init__(self,name):
self.name = name ##這是一個公有屬性
self.__age = 18 ##這是一個私有屬性
def __secret(self): ##這是一個私有方法
print ‘%s 的年齡是 %d‘ %(self.name,self.__age)
lily = Women(‘lily‘)
print lily.name
# 私有屬性,外界不能直接訪問
print lily.age
# 私有方法,外界不能直接調用
lily.__secret()
結果:
會出現報錯,顯示沒有這個屬性,所以說,私有屬性和方法,在類的外部不能被調用
lily
Traceback (most recent call last):
File "/home/kiosk/PycharmProjects/王芳/day06/私有屬性和私有方法.py", line 27, in <module>
print lily.age
AttributeError: Women instance has no attribute ‘age‘
(3)類的私有屬性和私有方法
--子類對象不能在自己的方法內部,直接訪問父類的私有屬性和私有方法
--子類對象可以通過父類的公有方法間接訪問到私有屬性或私有方法
私有屬性,私有方法是對象的隱私,不對外公開,外界以及子類都不能直接訪問
私有屬性,私有方法常用做一些內部的事情
示例:
class A:
def __init__(self):
# 在初始化方法中定義兩個屬性,一個公有屬性一個私有屬性
self.num1 = 100 #公有屬性
self.__num2 = 200 #私有屬性
def __test(self):
print ‘私有方法 %d %d‘ % (self.num1, self.__num2)
##如果要查看私有的屬性和方法,可以在類A中定義一個公有方法,然後在公有方法中調用私有的方法和屬性,再print就可以輸出私有的屬性和方法。再在子類直接調用這個公有方法就可以了
def test(self):
print ‘父類的共有方法 %d‘ % self.__num2
self.__test()
class B(A):
def demo(self):
# # 在子類的對象方法中,不能訪問父類的私有屬性
# print ‘訪問父親的私有屬性 %d‘ % self.__num2
# # 在子類對象的方法中,不能調用父類的私有方法
# self.__test()
#調用父類的共有方法
self.test()
# 創建一個子類對象
b = B()
b.demo()
# b.test()
# 在外界不能直接訪問對象有屬性/調用私有方法
# print b.__num2的私
# b.__test()
4.面向對象的三大特征
(1)封裝:根據職責將屬性和方法封裝到一個抽象的類中
(2)繼承:實現代碼的重用,相同的代碼不需要重復的寫
(3)多態
5.單繼承
繼承的概念:子類擁有父類的所有屬性和方法
繼承的語法
class 類名(父類):
def 子類特有的方法
"""
Cat類是Animal類的子類,Animal類是Cat類的父類,Cat從Animal類繼承
Cat類是Animal類的派生類,Animal類是Cat類的基類,Cat類從Animal類派生
"""
class Animal(object):
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 ‘旺旺‘
class Hellokitty(Cat):
def speak(self):
print ‘我可以說日語‘
# 創建一個貓對象
fentiao = Cat()
fentiao.eat()
fentiao.drink()
fentiao.run()
fentiao.sleep()
fentiao.call()
# 創建一個hellokitty對象
# kt = Hellokitty()
# kt.speak()
# kt.call()
# 繼承的傳遞性,子類擁有父類的父類的屬性和方法
"""
繼承的傳遞性:(爺爺 父親 兒子)
1.C類從B類繼承,B類又從A類繼承
2.那麽C類就具有B類和A類的所有屬性和方法
子類擁有父類以及父類的父類中封裝的所有屬性和方法
"""
kt.eat()
kt.drink()
kt.run()
kt.sleep()
# 子類繼承自父類,可以直接享受父類中已經封裝好的方法
# 子類中應該根據自己的職責,封裝子類特有的屬性和方法
6.多繼承
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-------demo方法‘
class C(B,A):
"""多繼承可以讓子類對象,同時具有多個父類的屬性和方法"""
"""多繼承(A,B)這個,如果兩個父類的方法重名的話,哪個放在前面就繼承哪個"""
pass
# 創建子類對象
c = C()
c.test()
c.demo()
7.封裝
(1)封裝是面向對象編程的一大特點
(2)面向對象編程的第一步 將屬性和方法封裝到一個抽象的類中(為什麽說是抽象的,因為類不能直接使用)
(3)外界使用類創建對象,然後讓對象調用方法
(4)對象方法的細節都被封裝在類的內部
示例:
小明愛跑步
1.小明體重75.0公斤
2.每次跑步會減肥0.5公斤
3每次吃東西體重會增加1公斤
4.小美的體重是45.0公斤
class Person:
def __init__(self,name,weight):
self.name = name
self.weight = weight
def __str__(self):
return ‘我的名字叫 %s 體重是 %.2f‘ %(self.name,self.weight)
def run(self):
print ‘%s 愛跑步‘ %self.name
# 在對象方法的內部,是可以直接訪問對象的屬性
self.weight -= 0.5
def eat(self):
print ‘%s 吃東西‘ %self.name
self.weight += 1
xx = Person(‘小明‘,75.0)
xx.run()
xx.eat()
print xx
# 同一個類創建出來的多個對象之間,屬性互不幹擾
xm = Person(‘小美‘,45.0)
xm.run()
xm.eat()
print xm
封裝練習:
(1)需求
--房子有戶型,總面積和家具名稱列表
新房子沒有任何家具
--家具有名字和占地面積,其中
床:占4平米
衣櫃:占2平米
餐桌:占1.5平米
--將以上三件家具添加到房子中
--打印房子時,要求輸出:戶型,總面積,剩余面積,家具名稱列表
被使用的類應該先開發
就比如:先要將家具定義出來,然後才能往房子裏面加
# 創建家具類
class HouseItem:
def __init__(self, name, area):
self.name = name
self.area = area
def __str__(self):
return ‘[%s]占地為 %.2f‘ % (self.name, self.area)
# 創建家具
bed = HouseItem(‘bed‘, 4)
print bed
chest = HouseItem(‘chest‘, 2)
print chest
table = HouseItem(‘table‘, 1.5)
print table
# 創建房子類
class House:
def __init__(self, house_type, area):
# 下面為從外界傳遞進來的參數
self.house_type = house_type
self.area = area
# 剩余面積不需要從外面傳遞,內部計算
# 剩余面積 = 總面積 - 家具面積
# 新房子內沒有任何家具,剩余面積=總面積
self.free = area
self.item_list = []
def __str__(self):
return ‘戶型:%s\n總面積:%.2f[剩余面積:%.2f]\n家具:%s‘ \
% (self.house_type, self.area, self.free, self.item_list)
def add_item(self, item):
if item.area >= self.area:
print ‘請重新訂購家具‘
else:
print ‘添加成功‘
self.item_list.append(item.name)
self.free -= item.area
# 創建房子
house = House(‘兩室一廳‘, 100)
house.add_item(bed)
house.add_item(chest)
house.add_item(table)
print house
(2)需求:
--士兵瑞恩有一把AK47
--士兵可以開火(士兵開火扣動的是扳機)
--槍 能夠 發射子彈(把子彈發射出去)
--槍 能夠 裝填子彈 --增加子彈數量
class Gun:
def __init__(self, name):
# 自己輸入槍的型號
self.name = name
# 假設默認的子彈數是10個
self.count = 10
self.free = self.count
def add_zidan(self, num):
if num + self.free > 10:
print ‘子彈數超過10顆!裝子彈失敗‘
else:
self.free += num
print ‘子彈添加成功!‘
def shoot(self):
if self.free <= 0:
print ‘沒有子彈了!‘
else:
self.free -= 1
print ‘開火ing...‘
class Person:
def __init__(self,name):
self.name = name
self.gun = None
def fire(self):
if self.gun == None:
print ‘還沒有槍‘
return
print ‘go!‘
self.gun.shoot()
self.gun.add_zidan(1)
ak47 = Gun(‘AK47‘)
ren = Person(‘ryan‘)
#人使用槍
ren.gun = ak47
ren.fire()
print ren
8.重寫父類方法
(1).覆蓋父類的方法
(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 Hellokitty(Cat):
def speak(self):
print ‘我可以說話‘
def call(self):
# 重寫父類的方法
print ‘話~~‘
# 調用原本在父類中封裝的代碼
Cat.call(self)
# 增加其他的子類代碼
print ‘#!@$@!#!#‘
kt = Hellokitty()
# 如果子類中,重寫了父類的方法
# 在運行中,只會調用在子類中重寫的父類的方法而不會調用父類的方法
kt.call()
重寫的練習:
--在寫好的代碼Bird類的上面,加入一個唱歌的屬性(要增加到默認屬性當中)
class Bird:
def __init__(self):
self.hungry = True
def eat(self):
# 如果吃過了就不餓了
if self.hungry:
print ‘吃東西ing。。。‘
self.hungry = False
else:
print ‘No,thanks!‘
錯誤代碼:
class songBird(Bird):
def __init__(self):
self.sound = ‘squawk!‘
def sing(self):
print self.sound
lb = songBird()
lb.eat()
lb.sing()
print lb
##這就相當於是songBird的初始化方法將原本的代碼的初始化方法覆蓋了,因此就沒有了 self.hungry = True 這行代碼,因此下面的判斷就不能夠執行下去
##正確的代碼應該是,繼承了父類,重寫並且調用父類的被重寫的方法,這樣就相當於是在不更改源代碼的同時,增加了默認的屬性
正確代碼:
class songBird(Bird):
def __init__(self):
self.sound = ‘squawk!‘
Bird.__init__(self) ##這條語句就是調用父類的方法
def sing(self):
print self.sound
lb = songBird()
lb.eat()
lb.sing()
print lb
9.新式類和舊式(經典)類
object是Python為所有對象提供的基類,提供有一些內置的屬性和方法,可以使用dir函數查看
新式類:以object為基類的類,推薦使用
經典類:不以object為基類的類,不推薦使用
在python3.X中定義的類時,如果沒有指定父類,會默認使用object作為基類--python3.x中定義的類都是新式類
在python2.x中定義類時,如果沒有指定父類,則不會以object作為基類
####推薦使用新式類#############
新式類和舊式類在多繼承時---會影響到方法的搜索順序
為保證編寫的代碼能夠同時在python2.x和python3.x運行
今後在定義類時,如果沒有父類,建議統一繼承自object
10.綜合練習
圖書管理系統
圖書管理系統
1.查詢
2.增加
3.借閱
4.歸還
5.退出
Python——創建類和對象