繼承
單繼承
有兩個類,A類和B類,當我們說A類繼承至B類的時候,那麼A類就擁有了B類中的所有的屬性和方法。
注意:繼承者稱爲子類,被繼承者稱爲父類。
繼承的作用:
- 簡化了代碼,減少冗餘。
- 提高了代碼的健壯性。
- 提高了代碼的安全性。
- 是多態的前提。
缺點:
耦合和內聚是描述類與類之間的關係的。耦合性越低,內聚性越高,代碼越好。
class Person(object):
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.__weight = weight
# 通過內部的方法,去修改私有屬性
def setWeight(self, weight):
# 數據的過濾,這個其實可以更完善一些
if weight < 0:
weight = 0
self.__weight = weight
def getWeight(self):
return self.__weight
# 我們在這裏定義一個子類,學生類,學生類繼承自Person類
class Student(Person):
def __init__(self, name, age, weight):
# 調用父類中的__init__
super().__init__(name, age, weight)
student = Student("tom", 18, 180)
print(student.getWeight())
運行結果:
180
可以看出,Student類繼承類Person類之後,就擁有了Person類的所有屬性和方法
以前的版本的super
的寫法是
super(Student, self).__init__(name, age, weight)
這也是最標準的寫法,但是現在的python更爲先進了
super().__init__(name, age, weight)
括號裏面不寫也可以了,解釋器會自動幫我們識別
多繼承
class Father(object):
def __init__(self, money):
self.money = money
def play(self):
print('play')
class Mother(object):
def __init__(self, eat):
self.eat = eat
def eatt(self):
print('eatt')
class Child(Father, Mother):
def __init__(self, money, eat):
Father.__init__(self, money)
Mother.__init__(self, eat)
c = Child(110, 'food')
c.play()
運行結果:
play
如果兩個父類的方法的方法名重複了,會從左到右按照順序調用父類的方法
按照我們的方法名來看的話,會調用Father的方法
對象屬性與類屬性
類屬性:
class Person(object):
# 這裏的屬性實際上屬於類屬性(用類名來調用)
name = 'person'
print(Person.name)
運行結果:
person
對象屬性:
class Person(object):
# 這裏的屬性實際上屬於類屬性(用類名來調用)
name = 'person'
def __init__(self, name):
pass
# 對象屬性
self.name = name
print(Person.name)
a = Person('tom')
# 對象屬性的優先級高於類屬性
print(a.name)
print(Person.name)
運行結果:
person
tom
person
也可以動態的給對象添加對象屬性:
a.age = 18
只針對於當前對象生效,對於類創建的其他對象沒有作用。
刪除對象中的類name屬性在調用會使用到同名的類屬性:
del a.name
print(a.name)
運行結果:
person
注意:以後千萬不要將對象屬性與類屬性重名,因爲對象屬性會屏蔽掉類屬性,但是當刪除對象屬性後,在使用又能使用到類屬性了。
動態給實例添加屬性和方法並使用__slots__
# 創建一個空類
class Person(object):
pass
a = Person()
# 動態添加屬性,這體現了動態語言的特點(靈活)
a.name = 'jack'
print(a.name)
# 動態添加方法
def say(self):
print('my name is ' + self.name)
a.speak = say
a.speak(a)
# 這樣添加不太好,因爲哪有自己傳自己的
運行結果:
jack
my name is jack
通過調用其他的一些方法
from types import MethodType
# 動態添加方法
def say(self):
print('my name is ' + self.name)
a.speak = MethodType(say, a)
a.speak()
# 這樣就不需要給自己傳參了
運行結果:
my name is jack
__ slots __
用於限制實例的屬性的添加
打個比方,只允許給對象添加name, height, weight屬性
在我們定義類的時候,定義一個特殊的屬性 __slots__
,可以限制動態的添加屬性。
class Person(object):
__slots__ = ("name", "age")
a = Person()
# 動態添加屬性,這體現了動態語言的特點(靈活)
a.name = 'jack'
print(a.name)
a.height = 18
print(a.height)
運行結果:
jack
AttributeError: 'Person' object has no attribute 'height'
顯而易見,除了我們指定的一些屬性名之外,其他的屬性都添加不進來
@property
怎麼說呢?私有屬性,我們用方法去訪問很麻煩。肯定是沒有通過直接用屬性來取值玩的爽,所以就有了這個裝飾器
屬性直接對外暴露,不安全,沒有數據的過濾
class Person(object):
def __init__(self, age):
self.__age = age
# 方法名爲受限制的變量,去掉雙下劃線
@property
def age(self):
return self.__age
# 去掉下劃線.setter
@age.setter
def age(self, age):
if age < 0:
age = 0
self.__age = age
p = Person(18)
p.age = 100 # 相當於調用setAge
print(p.age) # 相當於調用getAge
簡單來講,這個@property裝飾器,就是把一個方法變爲屬性,我們不再需要通過方法來改變屬性了,我們只需要直接通過屬性就可以修改,可以讓我們對受限制訪問的屬性使用語法。簡單方便
運算符重載
讓自定義的類生成的對象(實例)能夠使用運算符進行操作
先看看簡單的列子吧
class Person(object):
def __init__(self, age):
self.age = age
# 返回一個對象的描述信息
def __str__(self):
return "age = " + str(self.age)
# 制定加法的規則
def __add__(self, other):
return Person(self.age + other.age)
P1 = Person(18)
P2 = Person(20)
print(P1 + P2)
print(P1.__add__(P2))
運行結果:
age = 38
age = 38
是不是很神奇
算數運算符:
方法名 | 運算符和表達式 | 說明 |
---|---|---|
__ add __(self,other) | self + other | 加法 |
__ sub__(self,other) | self - other | 減法 |
__ mul__(self,other) | self * other | 乘法 |
__ truediv__(self,other) | self / other | 除法 |
__ mod__(self,other) | self % other | 取餘 |
__ floordiv__(self,other) | self // other | 地板除 |
__ pow__(self,other) | self ** other | 求冪 |