U6物件導向設計

zhlzn發表於2024-10-31

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 深複製與淺複製

  1. 淺複製(Shallow Copy)

    • 淺複製建立一個新物件,其欄位值與原始物件相同。如果欄位是基本資料型別,那麼複製的是基本資料型別的值;如果欄位是物件的引用,則複製的是引用,而不是引用的物件本身。
    • 對於欄位是物件引用的情況,淺複製後的新物件和原始物件會共享這些物件引用。這意味著如果透過新物件改變了引用指向的物件,原始物件中相應的物件也會被改變。
    • 淺複製可以透過多種方式實現,例如在Python中可以使用copy模組的copy()函式。
  2. 深複製(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)

相關文章