1. 程式人生 > >初識面向對象三(經典類/多態/鴨子類型/初識封裝)

初識面向對象三(經典類/多態/鴨子類型/初識封裝)

面向對象 能夠 object 一件事 主動 object類 深度優先算法 == 參數


py2中的經典類
coding:utf-8

class D:
pass
# def func(self):
# print(‘d‘)
class B(D):
pass
# def func(self):
# print(‘b‘)
class C(D):
pass
def func(self):
print(‘c‘)
class A(B,C):
pass
# def func(self):
# print(‘a‘)
a = A()
a.func()
python2.x中的經典類
多繼承中深度優先
沒有mro提示你順序

沒有super

python2中的新式類 基本和python3中的新式類相似
class D(object):
pass
def func(self):
# print(‘d‘)
class B(D):
pass
def func(self):
print(‘b‘)
class C(D):
pass
def func(self):
super(C,self).func()
print(‘c‘)
class A(B,C):
pass
# def func(self):
# print(‘a‘)

a = A()
a.func()
print(A.mro()) # 方法
print(A.__mro__) # 屬性

python2.x版本中存在兩種類
經典類
不主動繼承object類的所有類都是經典類
繼承關系遵循深度優先算法
沒有mro,沒有super
新式類
所有繼承object類的都是新式類
和py3一樣繼承遵循mro順序和c3算法
有mro方法,但是super的使用必須傳參數super(子類名,對象名).方法名

python3.x中的類和py2.x中的新式類有什麽區別???
不需要主動繼承object
py3中super()可以直接用,py2中使用必須傳參數super(子類名,對象名).方法名


所有繼承了object類的都是新式類 <==> 所有的新式類都繼承object類
PEP8規範 : 跨環境 無論在py2還是py3中定義一個新式類,都需要加上object這個繼承
class 類名(object):
pass
class 子類(類名):
pass

python中處處是多態
python是一門自帶多態的語言

java
強數據類型的語言
def pay(float money): # float 2.35 - 類 對象
print(money)
pay()

class Payment(object):pass
class Alipay(Payment):
def pay(self,money):
pass
class Wechatpay(Payment):
def pay(self,money):
pass
def pay(Payment person_obj,float money):
person_obj.pay(money)
alex = Alipay()
pay(alex,24.5)
yuan = Wechatpay()
print(yuan,23.5)
一個類表現出來的多種狀態
支付Payment是一個類,多種狀態: 使用阿裏支付Alipay,使用微信支付Wechatpay
支付表現出來的多種狀態 :
第一種狀態 支付寶支付
第二種狀態 微信支付
class Animal(object):pass
class Cat(Animal):
def eat(self):pass
class Dog(Animal):
def eat(self):pass
def eat(Animal obj):
obj.eat()
小花 = Cat() # 小花就是貓類的對象 類==類型==數據類型,小花的類型就是Cat
小黑 = Dog()
eat(小花)
eat(小黑)
int str list tuple dict set 內置的數據類型
Cat Dog Animal 自定義的類/數據類型
動物吃表現出來的多種狀態:
貓吃
狗吃

python
class Cat(object):
def eat(self):pass
class Dog(object):
def eat(self):pass
def eat(obj):
obj.eat()
小花 = Cat() # 小花就是貓類的對象 類==類型==數據類型,小花的類型就是Cat
小黑 = Dog()
eat(小花)
eat(小黑)
動物吃表現出來的多種狀態:
貓吃
狗吃

class Alipay(object):
def pay(self,money):
pass
class Wechatpay(object):
def pay(self,money):
pass
def pay(person_obj,money):
person_obj.pay(money)
alex = Alipay()
pay(alex,24.5)
yuan = Wechatpay()
print(yuan,23.5)
pay(‘abc‘,23.5)

總結
在python中體現的多態:
幾個類擁有同名的方法,可以寫一個函數,來統一進行調用 - 歸一化設計
java要要求傳遞數據的數據類型? (通過繼承來實現的)
是為了代碼不出錯,只要你能夠順利的調用這個函數,那麽內部的執行就大大降低出錯的概率
python卻不要求?
更多的不是硬性的規定,但是可能會因為傳遞的參數不符合規則而使得代碼報錯,但是大大降低了代碼繁瑣程度


python特有的  鴨子類型是相對論
len()這個函數來說: str list dict set tuple 都是鴨子類型
鴨子 == 數據集合
對於len來說,它不關心給我的是一個具體的什麽數據類型
只關心 能夠計算長度的就是我接受的參數

在java中 用多態實現的
def len(object obj):
print(‘*‘*20)
return obj.__len__()

print(len(‘abcd‘))
print(len([1,2,3]))

在python中 用鴨子類型
不關心這個對象的數據類型,只要這個對象含有一個__len__就可以了
 對於len函數來說,含有__len__的所有的類都是鴨子類型
def len(obj):
print(‘*‘*20)
return obj.__len__()

print(len(‘abcd‘))
print(len([1,2,3]))


class Cat():
def eat(self):pass
def sleep(self):pass
def drink(self):pass
def play(self):pass
class Dog():
def eat(self):pass
def sleep(self):pass
def drink(self):pass
def play(self):pass
Cat和Dog就認為是鴨子類型
絕對的像 : 狗有的貓都有


class Cat():
def eat(self):pass
def sleep(self):pass
def drink(self):pass
def climb(self):pass
class Dog():
def eat(self):pass
def sleep(self):pass
def drink(self):pass
def ball(self):pass
eat
sleep

class Cat():
def eat(self):pass
def climb(self):pass
class Dog():
def eat(self):pass
def ball(self):pass
eat cat和dog還是鴨子類型


鴨子類型
是python語言中特有的,不依賴於繼承和規範來進行的一種約定(依賴繼承和規範特指:java中的多態和接口)
如果兩個類都需要做某一件事情,那麽應該起相同的名字,這個時候,對於做的這件事情來說,這兩個類就變成了鴨子類(歸一化設計的表現)


中心思想 : 不同類之間的相同的方法都應該用同一個名字

抽象類 規範 : 不同類之間的相同的方法都應該用同一個名字
接口類 規範: 不同類之間的相同的方法都應該用同一個名字
class Cat():
def eat(self):pass
class Dog():
def eat(self):pass
def eat(obj):
obj.eat()
歸一化設計 :為了使用不同類中的方法,而要求 不同類之間的相同的方法都應該用同一個名字

class Animal:pass
class Cat(Animal):
def eat(self):pass
class Dog(Animal):
def eat(self):pass
def eat(Animal obj):
obj.eat()
多態 : 已經實現了"不同類之間的相同的方法都用同一個名字",解決不同類的對象的傳參問題

class Cat:
def eat(self):pass
class Dog:
def eat(self):pass
def eat(obj):
obj.eat()
鴨子類型 : 不需要解決類的對象的傳參問題,就可以直接利用已經實現的"不同類之間的相同的方法都用同一個名字"


初識封裝
什麽是封裝?
廣義上(大家認為的) :
把一類事務的相同的行為和屬性歸到一個類中
class Dog:
def bite(self):pass
狹義上(學術上的定論) :
把一些特殊的屬性和方法藏在類中
外部無法調用,只有內部可以調用
class Dog:
def bite(self):pass
dog = Dog()
dog.bite() # 從一個類的外部調用了bite方法

class Dog:
dog_sum = 0
def __init__(self):
self.count() # 從一個類的內部調用了count方法
def count(self):
Dog.dog_sum += 1

alex = Dog()
print(Dog.dog_sum)

alex.count() # # 從一個類的外部調用了count方法
alex.count()
alex.count()
print(Dog.dog_sum)

隱藏靜態屬性
class Dog:
# dog_sum = 0 # 不安全,因為這個屬性可以在類的外部被隨便修改
__dog_sum = 0 # 安全,通過dog_sum方法和__變量名讓屬性變成只能看不能改的值
def __init__(self):
self.count()
def count(self):
Dog.__dog_sum += 1 # 可以從一個類的內部使用__dog_sum的屬性
def dog_sum(self):
return Dog.__dog_sum

print(Dog.__dict__)
alex = Dog()
print(Dog.__dict__)
# print(Dog.__dog_sum) # 不可以從外部直接使用這個變量
print(alex.dog_sum())

class Dog:
__dog_sum = 0 # 私有的靜態屬性 _Dog__dog_sum
def __init__(self):
self.count()
def dog_sum(self):
return Dog.__dog_sum # 只要是在類的內部使用__名字,默認就被改成 _類名__名字

print(Dog.__dict__)
print(Dog._Dog__dog_sum) # 絕不能在後續我們的代碼中出現這種情況
只要是在類的內部的名字前面加上雙下劃線
那麽這個名字 就變成 私有的 (只能在類的內部使用,不能在類的外部使用)
在定義的時候,存儲的名字就會發生變化 _類名__名字
因此 在類的外部就不會被調用到了
在類的內部 使用__名字,默認就被改成 _類名__名字

class Dog:
# dog_sum = 0 # 不安全,因為這個屬性可以在類的外部被隨便修改
__dog_sum = 0 # 安全,通過dog_sum方法和__變量名讓屬性變成只能看不能改的值
def __init__(self):
self.__count()
def __count(self):
Dog.__dog_sum += 1 # 可以從一個類的內部使用__dog_sum的屬性
def dog_sum(self):
return Dog.__dog_sum

alex = Dog()
print(alex.dog_sum())
yuan = Dog()
print(yuan.dog_sum())

class Dog:
def __init__(self,name,password):
self.__name = name # 不希望某個值被隨便修改
self.__password = password # 不希望某個值被從類的外部看到
def login(self,usr,pwd):
if usr == self.name and pwd == self.__password:
return True
def name(self):
return self.__name
def set_name(self,new_name):
if type(new_name) is str:
self.__name = new_name

alex = Dog(‘alex‘,‘sb123‘)
print(alex.login(‘alex‘,‘sb222‘))
print(alex.login(‘alex‘,‘sb123‘))

print(alex.name())
alex.set_name(‘alex_sb‘)
print(alex.name())

只能在類的內部被調用,保證了類內部數據的安全,不會被別人隨意修改
私有靜態屬性 : 為了不隨意被外部修改
私有方法 : 不希望被外部隨意調用
私有的對象屬性 :
不希望某個值被隨便修改
不希望某個值被從類的外部看到






初識面向對象三(經典類/多態/鴨子類型/初識封裝)