Unit6 物件導向設計
這是程式設計思想的差別,相比與C語言的物件導向設計,大概就是由各種功能的方法組成專案,比較具體,缺少抽象,對於類似的操作不能很好的複用。在語言語法上多了類Class,繼承,多型這些。
6.1 類
'''
Python 類/物件
Python 是一種物件導向的程式語言。
Python 中的幾乎所有東西都是物件,擁有屬性和方法。
類(Class)類似物件建構函式,或者是用於建立物件的“藍圖”。
'''
class MyClass:
x = 5
p1 = MyClass()
print(type(p1))
print(p1.x)
#_init_()函式
'''
所有類都有一個名為 __init__() 的函式,它始終在啟動類時執行。
使用 __init__() 函式將值賦給物件屬性,或者在建立物件時需要執行的其他操作
相當於 java裡的無參構造
'''
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
p2 = Person("zhl",21)
print(p2.name)
print(p2.age)
#物件方法
class Person1:
def __init__(self,name,age):
self.name = name
self.age = age
def myFunc(self):
print("hello my name is " + self.name)
p3 = Person1("zhl",21)
p3.myFunc()
#self引數
'''
self 引數是對類的當前例項的引用,用於訪問屬於該類的變數。
它不必被命名為 self,您可以隨意呼叫它,但它必須是類中任意函式的首個引數
'''
class Person3:
def __init__(mySillyObject, name, age):
mySillyObject.name = name
mySillyObject.age = age
def myfunc(abc):
print("hello my name is " + abc.name)
print(f"my age is {abc.age}")
p4 = Person3("zhl",21)
p4.myfunc()
#修改物件屬性
p4.age = 40
p4.myfunc()
#刪除物件屬性
del p4.age
#刪除物件
del p4
class Person5:
pass
6.2 繼承
'''
Python 繼承
繼承允許我們定義繼承另一個類的所有方法和屬性的類。
父類是繼承的類,也稱為基類。
子類是從另一個類繼承的類,也稱為派生類。
'''
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname
def printname(self):
print(self.firstname, self.lastname)
# 使用 Person 來建立物件,然後執行 printname 方法:
x = Person("Bill", "Gates")
x.printname()
#建立子類
class student(Person):
pass
EM = student("Elon","Musk")
EM.printname()
'''
#新增_init_()函式
#次使用類建立新物件時,都會自動呼叫 __init__() 函式。
#當新增 __init__() 函式時,子類將不再繼承父的 __init__() 函式。
子的 __init__() 函式會覆蓋對父的 __init__() 函式的繼承。
如需保持父的 __init__() 函式的繼承,請新增對父的 __init__() 函式的呼叫
'''
class Student(Person):
def __init__(self, fname, lname):
Person.__init__(self, fname, lname)
x = Student("Elon", "Musk")
x.printname()
'''
super()函式
'''
class Student(Person):
def __init__(self, fname, lname):
super().__init__(fname, lname)
x = Student("Elon", "Musk")
x.printname()
#和java一樣,可以新增屬性,新增方法
6.3 類屬性和例項屬性
class student:
school = "CSUFT"
#初始化方法
def __init__(self, studentName, age):
self.name = studentName
self.age = age
def show(self):
print(f"my name is {self.name}, today {self.age} years old.")
#靜態方法
@staticmethod
def sm():
#print(self.name)
#self.show()
print("這是一個靜態方法,不能去呼叫例項屬性,和使用方法")
#類方法
@classmethod
def cm(cls):#cls -->class的簡寫
#print(self.name)
#self.show()
print("這是一個類方法,不能呼叫例項屬性,也不能呼叫例項方法")
#例項化
p1 =student("zhl",12)
#例項方法
p1.show()
#類屬性直接呼叫
print(p1.name, p1.age)
print(p1.school)
#類方法
p1.cm()
#靜態方法
p1.sm()
6.4 建立類物件
class Student:
school = "CSUFT"
def __init__(self, sn, age):
self.name = sn
self.age = age
def show(self):
print(f"我叫{self.name},今年{self.age}歲了")
#建立物件
stu1 = Student("小明",18)
stu2 = Student("小明1",18)
stu3 = Student("小明2",18)
stu4 = Student("小明4",18)
print(type(stu1))
print(type(stu2))
print(type(stu3))
print(type(stu4))
Student.school = "NO.1 Scholl CSUFT"
lst = [stu1,stu2,stu3,stu4]
for i in lst:
i.show()
6.5 動態繫結屬性和方法
class Student:
school = "CSUFT"
def __init__(self, sn, age):
self.name = sn
self.age = age
def show(self):
print(f"我叫{self.name},今年{self.age}歲了")
stu = Student("zhl",21)
print(stu.name, stu.age)
stu.name = "good man"
print(stu.name, stu.age)
6.6 python的getter和setter
class Student():
#
def __init__(self,name,age,gender):
#self._name受保護,只能本類和子類去訪問
self._name = name
#self.__age 標識是由的,只能類本身去訪問
self.__age = age
self.gender = gender
def _fun1(self):#protected
print("子類以及本身可以訪問")
def __fun2(self):#private
print("本身可以訪問")
def fun3(self):#default
print("都可以訪問")
def show(self):
self._fun1()
self.__fun2()
print(self._name)
print(self.__age)
stu = Student("zhl", 21,"男")
#類的外部
print(stu._name)
#print(stu.__age)
stu._fun1()
#AttributeError: 'Student' object has no attribute '__fun2'. Did you mean: '_fun1'?
#stu.__fun2()
#私有的例項屬性和方法不能直接訪問
print(stu._Student__age)#可以訪問
stu._Student__fun2()#可以訪問
print(dir(stu))
'''
getter and setter
'''
class Student:
def __init__(self, name, gender):
self.__name = name
self.__gender = gender
# @property 修改方法,將方法轉成屬性使用
@property
def gender(self):
return self.__gender
@gender.setter
def gender(self,value):
if value != "男" and value != "女":
raise ValueError("性別只能是'男’或'女'")
self.__gender = value
def getName(self):
return self.__name
stu = Student("zhl","男")
print(stu.getName(),"的性別是",stu.gender)
print(type(stu.getName()))
print(type(stu.gender))
stu.gender = "女"
print(stu.getName(),"的性別是",stu.gender)
stu.gender = "1"
print(stu.getName(),"的性別是",stu.gender)
6.7繼承
class Person:#預設繼承了 Object
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(f"hello i'm {self.name}, my age is {self.age}")
class Student(Person):
#編寫初始化的方法
def __init__(self, name, age, stuNo):
#呼叫父類的初始化方法
super(Student, self).__init__(name, age)
self.stuNo = stuNo
#Doctor 繼承Person
class Doctor(Person):
#初始化
def __init__(self, name, age, department):
super(Doctor, self).__init__(name, age)
self.department = department
#例項化物件
stu1 = Student("張三",20,"1001")
stu2 = Student("李四",20,"1002")
stu1.show()
stu2.show()
doctor1 = Doctor("王五", 32,"外科")
doctor1.show()
6.8多繼承
class Father1():
def __init__(self,name):
self.name = name
def show1(self):
print("父類1中的方法")
class Father2():
def __init__(self,age):
self.age = age
def show2(self):
print("父類2中的方法")
#多繼承
class Son(Father1, Father2):
def __init__(self, name, age, gender):
#需要呼叫兩個父類的初始化方法
Father1.__init__(self, name)
Father2.__init__(self, age)
self.gender = gender
son1 = Son("張三",20,"男")
son1.show1()
son1.show2()
6.9重寫
#c重寫
class Person:#預設繼承了 Object
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(f"hello i'm {self.name}, my age is {self.age}")
class Student(Person):
#編寫初始化的方法
def __init__(self, name, age, stuNo):
#呼叫父類的初始化方法
super(Student, self).__init__(name, age)
self.stuNo = stuNo
def show(self):
super(Student, self).show()
print("我是學生")
#Doctor 繼承Person
class Doctor(Person):
#初始化
def __init__(self, name, age, department):
super(Doctor, self).__init__(name, age)
self.department = department
def show(self):
super(Doctor, self).show()
print("我是醫生")
#例項化物件
stu1 = Student("張三",20,"1001")
stu2 = Student("李四",20,"1002")
stu1.show()
stu2.show()
doctor1 = Doctor("王五", 32,"外科")
doctor1.show()
6.10多型
class Person():
def eat(self):
print("人吃飯")
class Cat():
def eat(self):
print("貓吃魚")
class Dog():
def eat(self):
print("狗吃骨頭")
def fun(obj):
obj.eat()
#建立三個類物件
per = Person()
cat = Cat()
dog = Dog()
#呼叫fun函式
fun(per)
fun(cat)
fun(dog)
6.11 Object
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(f"hello i'm{self.name}, age is {self.age}")
#例項化
per = Person("張三",20)
print(dir(per))
print(per) #自動呼叫了 __str__方法
6.12 __str__方法的重寫
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(f"hello i'm{self.name}, age is {self.age}")
#重寫
def __str__(self):
return "這是一個Person Class"
#例項化
per = Person("張三",20)
print(dir(per))
print(per) #自動呼叫了 __str__方法
6.12 深複製與淺複製
-
淺複製(Shallow Copy):
- 淺複製建立一個新物件,其欄位值與原始物件相同。如果欄位是基本資料型別,那麼複製的是基本資料型別的值;如果欄位是物件的引用,則複製的是引用,而不是引用的物件本身。
- 對於欄位是物件引用的情況,淺複製後的新物件和原始物件會共享這些物件引用。這意味著如果透過新物件改變了引用指向的物件,原始物件中相應的物件也會被改變。
- 淺複製可以透過多種方式實現,例如在Python中可以使用
copy
模組的copy()
函式。
-
深複製(Deep Copy):
- 深複製建立一個新物件,並且遞迴地複製所有物件的欄位值。這意味著如果欄位是物件的引用,那麼深複製會建立這些物件的副本,而不是僅僅複製引用。
- 深複製後的新物件與原始物件完全獨立,對新物件的任何修改都不會影響原始物件。
- 深複製通常需要更多的時間和記憶體,因為它需要建立更多的物件副本。
- 在Python中,可以使用
copy
模組的deepcopy()
函式來實現深複製。
class CPU():
pass
class Disk():
pass
class Computer():
def __init__(self, cpu, disk):
self.cpu = cpu
self.disk = disk
'''
輸出結果
<__main__.Computer object at 0x000002ADC80F9010> 子物件的記憶體地址 <__main__.CPU object at 0x000002ADC80F8F90> <__main__.Disk object at 0x000002ADC80F8FD0>
<__main__.Computer object at 0x000002ADC80F9010> 子物件的記憶體地址 <__main__.CPU object at 0x000002ADC80F8F90> <__main__.Disk object at 0x000002ADC80F8FD0>
'''
cpu= CPU()
disk = Disk()
com = Computer(cpu,disk)
com1 = com
print(com, "子物件的記憶體地址",com.cpu, com.disk)
print(com1, "子物件的記憶體地址",com1.cpu, com1.disk)
print("*"*50)
#淺複製
import copy
com2 = copy.copy(com)
print(com, "子物件的記憶體地址",com.cpu, com.disk)
print(com2, "子物件的記憶體地址",com2.cpu, com2.disk)
print("*"*50)
#深複製
com3 = copy.deepcopy(com)
print(com, "子物件的記憶體地址",com.cpu, com.disk)
print(com3, "子物件的記憶體地址",com3.cpu, com3.disk)