一,python中的方法沒有重載
如果定義多個同名方法,則只有最後一個有效。
在其他語言中,可以通過形參列表區分但是python中不可以
測試代碼如下:
class Tx:
def prints(self):
print('沒有參數')
def prints(self,a):
print('參數爲',a)
t=Tx()
t.prints(1)
結果如下:
參數爲 1
二,方法的動態性
python是動態語言,我們可以動態的爲類添加新的方法,也可以改變已有的方法
測試代碼如下:
class Tips:
def work(self):
print('好好學習')
def play(a):
print('{0}在玩遊戲'.format(a))
def work(a):
print('{0}在工作'.format(a))
Tips.play=play
Tips.work=work
p=Tips()
p.play() #Tips.play(p)
p.work()
結果如下:
<__main__.Tips object at 0x0000022931185B88>在玩遊戲
<__main__.Tips object at 0x0000022931185B88>在工作
該代碼的關鍵是將play與work看作對象,然後進行操作。相當於在Tips中創建一個類屬性,存放函數的地址。
三,私有屬性與私有方法
要點:(1)兩個下劃線開頭的屬性或方法爲私有的,其他的爲公共有的
(2)類內部可以直接訪問私有屬性和方法
(3)類外部不可以直接訪問私有屬性與方法
(4)在類外部可以通過_類名__私有屬性名來訪問私有屬性
方法在本質上也是屬性,只不過可以用()調用
測試代碼如下:
class Employee:
__company='yzu'
def __init__(self,name,age):
self.name=name
self.__age=age #私有屬性
def __fun(self): #私有方法
print('加油')
print(Employee.__company) #私有類屬性,注意在類內部引用時,不需要加_類名,但是前面也要加類名
e=Employee('lhy',18)
print(e.name)
#print(e.age)
print(e._Employee__age)
print(dir(e))
#print(e.__fun)
print(e._Employee__fun())
print(Employee._Employee__company)
結果如下:
lhy
18
['_Employee__age', '_Employee__company', '_Employee__fun', '__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__', 'name']
加油
yzu
None
yzu
四,@property修飾器
它可以將一個方法的調用變成屬性調用
測試代碼如下:
class Employee:
@property
def salary(self):
return 10000
e=Employee()
print(e.salary)
#e.salary()錯誤
#e.salary=20000該方法中不可修改
結果如下:
10000
上面代碼無法改變值,下面是改進代碼
class Employee:
def __init__(self,salary):
self.__salary=salary
def get_salary(self):
return self.__salary
def set_salary(self,salary):
if 1000<salary<50000:
self.__salary=salary
else:
print('輸入錯誤')
e=Employee(3000)
print(e.get_salary())
#e.set_salary(4000)
e.set_salary(-2000)
print(e.get_salary())
#改進
class Employee:
def __init__(self,salary):
self.__salary=salary
@property
def salary(self):
return self.__salary
@salary.setter
def salary(self,salary):
if 1000<salary<50000:
self.__salary=salary
else:
print('輸入錯誤')
e=Employee(3000)
print(e.salary)
e.salary=-2000
print(e.salary)
結果如下:
3000
輸入錯誤
3000
3000
輸入錯誤
3000
五,面向對象三大特徵
(1)封裝:隱藏對象的屬性和實現細節,只對外提供必要的方法
(2)繼承:繼承讓子類具有父類的特徵,提高代碼重用性
(3)多態:同一種方法調用由於對象不同會產生不同的行爲。
六,繼承
語言格式:class 子類名(父類1,【父類2】。。。)
如果在類體中沒有指定父類,則默認父類爲object類,
object是所有類的父類,裏面定義所有類默認實現的東西,如__new__()
一般來說,構造子類對象一般調用父類的構造函數。
對於父類的私有屬性與私有方法,子類繼承但不可以直接用。
測試代碼如下:
class Person:
def __init__(self,name,age):
self.name=name
self.__age=age
def say_age(self):
print('年齡是{0}'.format(self.__age))
class Student(Person): #注意縮進,unindent
def __init__(self,name,age,score):
Person.__init__(self,name,age)#注意要加self
self.score=score
s=Student('lhy',18,60)
s.say_age()
print(Student.mro())#打印所屬關係
#如果把age定爲私有屬性
print(s._Person__age)
結果如下:
年齡是18
[<class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>]
18
七,類成員的繼承與重寫
(1)繼承:子類繼承父類除構造函數外的所有成員
(2)重寫:子類中可以重新定義父類中的方法。
測試代碼如下:
class Person:
def __init__(self,name,age):
self.name=name
self.__age=age
def say_age(self):
print('年齡是{0}'.format(self.__age))
class Student(Person): #注意縮進,unindent
def __init__(self,name,age,score):
Person.__init__(self,name,age)#注意要加self
self.score=score
def say_age(self):
print("{0}的年齡是{1}".format(self.name,self._Person__age))
s=Student('lhy',18,60)
s.say_age() #覆蓋了父類的方法
結果爲:
lhy的年齡是18
八,object根類
測試代碼如下:
class Person:
def __init__(self,name,age):
self.name=name
self.__age=age
def say_age(self):
print('年齡是{0}'.format(self.__age))
print(dir(object))
s=Person('lhy',18)
print(dir(s))
s1=s.name
s2=s._Person__age
s3=s.say_age
print(type(s1))
print(type(s2))
print(type(s3))#方法也是屬性,只不過是method屬性,可以用()調用
結果如下:
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
['_Person__age', '__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__', 'name', 'say_age']
<class 'str'>
<class 'int'>
<class 'method'>
九,__str__方法
該方法用來返回一個對象的描述,用print()方法時,會使用該方法
測試代碼如下:
class Person:
def __init__(self,name):
self.name=name
s=Person('lhy')
print(s)
#若使用str
class Person1:
def __init__(self,name):
self.name=name
def __str__(self):
return '修改了' #不用return會報錯
s=Person1('lhy')
print(s)
結果如下:
<__main__.Person object at 0x0000027D6CD2AD08>
修改了
十,多重繼承與特殊屬性
多重繼承會將類的整體結構搞得複雜,應該避免使用
測試代碼如下:
class A:
def a(self):
print('a')
def say(self):
print('aaa')
class B:
def b(self):
print('b')
def say(self):
print('bbb')
class C(A,B):
pass
c=C()
c.a()
c.b()
c.say()#由於繼承時候A在前面
print(C.mro())#c不可以
print(c.__dict__)
print(c.__class__)
print(C.__bases__)
print(C.__base__)
print(C.__mro__)
print(A.__subclasses__())
結果如下:
a
b
aaa
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
{}
<class '__main__.C'>
(<class '__main__.A'>, <class '__main__.B'>)
<class '__main__.A'>
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
[<class '__main__.C'>]
十一,super()獲取父類定義
在子類中,如果想獲得父類方法時,可以通過super()來實現
super()代表父類的定義,不是父類的對象
測試代碼如下:
class A:
def a(self):
print(self)
class B(A):
def say(self):
#A.a(self)
super().a()#與上語句相似
print(self)
#b=B()
#b.say()
B().say()
結果爲:
<__main__.B object at 0x0000024E8A450548>
<__main__.B object at 0x0000024E8A450548>
十二,多態
多態是由於對象不同而產生不同行爲
要點:(1)只有方法有多態,屬性沒有多態
(2)多態必須存在兩個必要條件:繼承與方法重寫
測試代碼如下:
class Man:
def eat(self):
print('喫飯行爲')
class Chinese(Man):
def eat(self):
print('用筷子喫')
class English(Man):
def eat(self):
print('用刀叉喫')
class Indian(Man):
def eat(self):
print('用右手喫')
def maneat(m):
if isinstance(m,Man):
m.eat()
else:
print('不能喫飯')
maneat(Chinese())
maneat(English())
maneat(Indian)
maneat(Man())
結果爲:
用筷子喫
用刀叉喫
不能喫飯
喫飯行爲
十三,特殊方法與運算符重載
測試如下:
class Person:
def __init__(self,name):
self.name=name
def __add__(self, other):
if isinstance(other,Person):#檢測是不是Person類
return "{0}__{1}".format(self.name,other.name)#這裏的other其實是一個Person對象
else:
return "不能打印"
def __mul__(self, other):
if isinstance(other,int):
return self.name*3
else:
return "不能打印"
p1=Person('lhy')
p2=Person('zm')
c=p1+p2
print(c)
d=p1*3
print(d)
結果爲:
lhy__zm
lhylhylhy
十四,對象的淺拷貝與深拷貝
測試代碼如下:
import copy
class Phone:
def __init__(self,cpu,screen):
self.cpu=cpu
self.screen=screen
class Cpu:
pass
class Screen:
pass
#測試變量賦值
c=Cpu()
c2=c
print(c)
print(c2)
s=Screen()
print('測試淺拷貝')
p=Phone(c,s)#Phone(1,2)?
p1=copy.copy(p)
print(p,p.cpu,p.screen)
print(p1,p1.cpu,p1.screen)
print('測試深拷貝')
p2=copy.deepcopy(p)
print(p,p.cpu,p.screen)
print(p2,p2.cpu,p2.screen)
結果如下:
<__main__.Cpu object at 0x000001D7AFC3C748>
<__main__.Cpu object at 0x000001D7AFC3C748>
測試淺拷貝
<__main__.Phone object at 0x000001D7B0B99DC8> <__main__.Cpu object at 0x000001D7AFC3C748> <__main__.Screen object at 0x000001D7AFC40948>
<__main__.Phone object at 0x000001D7AFC48288> <__main__.Cpu object at 0x000001D7AFC3C748> <__main__.Screen object at 0x000001D7AFC40948>
測試深拷貝
<__main__.Phone object at 0x000001D7B0B99DC8> <__main__.Cpu object at 0x000001D7AFC3C748> <__main__.Screen object at 0x000001D7AFC40948>
<__main__.Phone object at 0x000001D7B0C23248> <__main__.Cpu object at 0x000001D7B0C23BC8> <__main__.Screen object at 0x000001D7B0C23C48>
十五,組合
is-a關係用繼承
has-a關係用組合
測試代碼如下:
class A1:
def a1(self):
print('aaa')
class B1(A1):
pass
B1().a1()
#組合
class A2:
def a2(self):
print('bbb')
class B2:
def __init__(self,a):
self.a=a
B2(A2()).a.a2()#這裏B2中包含A2,然後將A2()的對象,傳入B2中,用來創建a,所以a.a2()可以調用
結果如下:
aaa
bbb
十六,工廠模式實現
class CarFactory:
def create_car(self,brand):
if brand=='奔馳':
return BC()
elif brand=='比亞迪':
return BYD()
elif brand=='法拉利':
return FLL()
class BC:
pass
class BYD:
pass
class FLL:
pass
factory=CarFactory()
c1=factory.create_car('奔馳')
c2=factory.create_car(('比亞迪'))
十七,單例模式實現
class Dan:
__obj=None
init_flag=True
def __new__(cls, *args, **kwargs):
if cls.__obj==None:#忘加cls
cls.__obj=object.__new__(cls)
return cls.__obj
def __init__(self):
if Dan.init_flag==True:#忘加Dan
Dan.init_flag=False
print('執行了')
d1=Dan()
d2=Dan()
print(d1)
print(d2)
結果如下:
執行了
<__main__.Dan object at 0x0000021EB37C4B88>
<__main__.Dan object at 0x0000021EB37C4B88>