類定義格式以下:java
class A: pass class B(A): pass
在java和C++中,分別提供了this引用和this指針,表示當前的調用對象或指針,在Python中,則提供了相似的self參數,在對方法進行調用時,會自動提供self參數,可是必須在參數列表中包含該參數,所以,方法的定義格式以下:python
class A: def func(self): print("我是普通方法")
有了self參數,類的屬性就是經過self參數來存取,如:安全
class A: def func(self,name,age): self.name = name self.age = age print("我是普通方法")
完整的類定義以下:函數
class A: def __init__(self,name,age): self.name = name self.age = age def func(self): print(666) def __eq__(self, other): return self.name == other.name and self.age == other.age def __repr__(self): return "Animal('{0}',{1}".format(self.name,self.age) def __str__(self): return "Animal({0},{1}".format(self.name,self.age) a1 = A('alex',1000) print(a1.name) #'alex" print(a1.func()) # 666 None print(a1.__eq__(a1)) # True print(a1.__str__()) #Animal(alex,1000 print(a1.__repr__()) #Animal('alex',1000
其中以_開頭和結尾的方法都來自於基類object,當定義好類後,就能夠了導入人類所在模塊後使用了,this
如:spa
import Module_A dog = Module_A dog.eat()
若是想要定義一個私有的屬性,則在屬性前面加上__就變成私有的了設計
如:指針
class A: def __init__(self,name='alex',age=1000): self.__name=name self.age=age if __name__ == "__main__": dog = A() print(dog.__name) #AttributeError: 'A' object has no attribute '__name'
__new()__
和__init()__
方法:
和其餘語言不一樣,Python中要建立一個對象,當調用dog = Module_Animal.Animal("Dog")
時,執行了兩個步驟:code
__new__()
方法建立該對象;__init__()
方法對其進行初始化;在建立類時,應該重寫__init__()
方法進行初始化,__new__()
沒必要須進行重寫。在建立對象時若是發現沒有提供,則自動調用object.__new__()
。
若是重寫了__init__()
方法而且想要調用基類該方法,則能夠經過super()方法:orm
def __init__(self): super().__init__()
__eq__(self, other)
和__ne__(self, other)
方法:
這兩個方法用於兩個對象之間進行比較,對於__eq__()
,若是self和other相等,則返回True;對於__ne__()
,若是self和other不等,則返回True,如:
dog = Animal("Dog") dog.eat() cat = Animal("cat") cat.eat() print(dog == cat) # return False isEqual = dog.__eq__(cat) isNotEqual = dog.__ne__(cat) print(isEqual) # return False print(isNotEqual) # return True
==
進行比較,但老是返回False(除非dog == dog),所以能夠經過__eq__()
來實現比較操做。__eq__()
方法但沒有提供__ne__()
方法,Python會自動提供__ne__()
和!=
操做符;若是沒有提供__eq__()
,調用結果爲NotImplemented。__hash__()
方法,也能夠做爲字典的鍵,可是若是重寫了__eq__()
方法,則該類的實例就不是可哈希運算的了。def __eq__(self, other): if not isinstance(other,Animal): return NotImplementedError return self.name == other.name and self.age == other.age
__le__(self,other)
:self <= other,返回Ture__lt__(self,other)
:self < other,返回Ture__ge__(self,other)
:self >= other,返回Ture__gt__(self,other)
:self > other,返回Ture__ne__(self,other)
:self != other,返回Ture__eq__(self,other)
:self == other,返回Ture__repr__()
和__str__()
方法:
調用內置repr()函數時,會調用給定對象的__repr__()
方法,該方法用於返回一個特殊的字符串,該字符串可經過內置eval()
函數生成一個Python對象,如:
def __repr__(self): return "Animal('{0}',{1})".format(self.name,self.age) if __name__ == "__main__": cat = Animal("Cat") ani = eval(repr(cat)) # return Animal('Cat',0) print(ani) # Animal(Cat,0)
調用內置函數str()
時,會調用給定對象的__str__()
方法,該方法也會返回一個字符串,和__repr__()
的區別主要是該方法產生的字符串主要是便於理解,而不是爲了傳遞給eval()
函數。
如:
def __str__(self): return "Animal({0},{1})".format(self.name, self.age) print(str(ani)) # Animal(Cat,0)
__repr__()
而沒有實現__str__()
時,則在調用str()、print(obj)時也會執行__repr__()
方法。 __hash__()
方法: __eq__()
方法,那麼則不可進行哈希運算,經過提供該方法能夠使類能狗進行哈希運算,實現以下:def __hash__(self): return hash(id(self))
內置hash()
方法根據獨一無二的ID來計算哈希值,內置id()
方法返回一個獨一無二的整數。
Python中定義一個類繼承另外一個類格式以下:
class Subclass(A): pass
子類能夠對父類的方法進行重寫,若是子類想調用父類的方法,能夠使用super()
進行調用,如:
class Animal: def __init__(self,name="Animal",age=0): self.__name = name self.age = age def eat(self): print('Animal is eating') def shout(self): print("Animal is shouting") class Dog(Animal): def __init__(self,name="Dog",age=0): # 調用Animal的__init__()方法 super().__init__() self.name = name self.age = age def shout(self): print("Dog is Shouting") def eat(self): print("Dog is eating") class Cat(Animal): def __init__(self,name="Cat"): self.name = name def shout(self): print("Cat is shouting") def eat(self): print("Cat is eating")
在java等面嚮對象語言中,多態是指子類的引用指向父類的實例,可是在Python中,可能不能用這種方式來理解,由於Python中定義一個變量或對象並不須要聲明數據類型,所以對於Python而言,其多態的表現形式就是:若是子類對父類方法進行了覆蓋,則子類對象調用該方法時,會調用子類對方法的實現。如:
if __name__ == "__main__": ani = Animal() dog = Dog() cat = Cat() ani.eat() # Animal is eating dog.eat() # Dog is eating cat.eat() # Cat is eating
python提供了isinstance(o,Obj)
方法,能夠判斷對象o是不是Obj類型,所以,在使用多態時,能夠這樣使用:
# 定義一個函數 def animal_eat(animal): animal.eat() if isinstance(dog,Animal): animal_eat(dog) # Dog is eating if isinstance(cat,Animal): animal_eat(cat) # Cat is eating
在面向對象的設計中,經常要將屬性進行封裝,提供setter/getter方法對屬性進行操做,Python中也能夠提供setter/getter進行對屬性的封裝,從而保證數據的安全性,可是並不推薦使用,由於有更優的方式能夠屬性的安全性,下面逐步進行分析。
如今定義一個類:
import math class Circle: def __init__(self, radius, x=0, y=0): self.radius = radius def area(self): return math.pi * (self.radius ** 2) if __name__ == "__main__": c1 = Circle(2) c1.radius = -3 print(c1.area()) print(c1.radius) # -3
能夠看到,屬性radius有可能被設置爲不合理的值,所以,能夠將radius設置爲私有屬性,同時提供setter/getter方法對其進行設置,修改該類實現以下:
class Circle: def __init__(self, radius, x=0, y=0): if radius <= 0: self.__radius = 1 self.__radius = radius def set_radius(self, radius): assert radius >= 0, "radius can't be zero" self.__radius = radius def get_radius(self): return self.__radius if __name__ == "__main__": c1 = Circle(2) c1.set_radius(-3) # AssertionError: radius can't be zero print(c1.area()) print(c1.get_radius()) # 2
經過setter/getter能夠將屬性封裝起來,能夠保證屬性的安全性,可是這種方式比較繁瑣,在Python中,更傾向於使用Property裝飾器,使用方式以下:
# class A: # def __init__(self,name,age): # self.name = name # self.age = age # def func(self): # print(666) # def __eq__(self, other): # return self.name == other.name and self.age == other.age # def __repr__(self): # return "Animal('{0}',{1}".format(self.name,self.age) # def __str__(self): # return "Animal({0},{1}".format(self.name,self.age) # # a1 = A('alex',1000) # print(a1.name) #'alex" # print(a1.func()) # 666 None # print(a1.__eq__(a1)) # True # print(a1.__str__()) #Animal(alex,1000 # print(a1.__repr__()) #Animal('alex',1000 class A: def __init__(self,name='alex',age=1000): self.__name=name self.age=age if __name__ == "__main__": dog = A() print(dog.__name) #AttributeError: 'A' object has no attribute '__name'
Property裝飾器是一個函數,該函數以一個方法做爲參數,並返回修飾後的版本。可是一般並不使用該方法,而是經過@
符號來標記,如上例所示。property()是一個內置函數,至多能夠接受四個參數:get參數、set參數、delete參數、docstring參數。@property
至關於property(get)。
在上例中,建立了一個__radius私有屬性,而後經過property裝飾器進行其getter、setter的設置。須要注意:
當建立radius裝飾器後,就能夠經過radius.setter和radius.getter獲取和設置__radius屬性了,同時保證了私有屬性的安全性,如:
c1.radius = 0 # AssertionError: radius can't be zero c1.radius = 3 # 調用radius(self,radius),至關於radius.setter print(c1.radius) # 2 調用radius.setter