- YT物件導向教學: - https://www.youtube.com/watch?v=WBrX9n0SWG8 - https://www.youtube.com/watch?v=fELYoevwnag&t=273s - [IThome文章](https://ithelp.ithome.com.tw/articles/10265795) - 物件導向程式設計(Object-Oriented Programming, OOP)是一種程式設計範式,它將程式組織成物件,這些物件包含資料(屬性)和操作資料的行為(方法)。OOP 使得程式更具結構性、可讀性和可維護性。 ```python= class Robot: # 初始化class(self, 其他自己接) def __init__(self, name, age): self.name = name self.age = age # 使用class自己的參數 def walk(self): print(f"{self.name} is walking.") # 除了class裡面的參數,還有額外參數 def sleep(self, hours): print(f"{self.name} is going to sleep for {hours} hours.") # 訪問屬性和方法 my_robot = Robot("助教",23) print(type(my_robot)) # <class '__main__.Robot'> print(my_robot.name) # 助教 print(my_robot.age) # 23 my_robot.walk() # 助教 is walking. my_robot.sleep(15) # 助教 is going to sleep for 15 hours. ``` ## oop class attribute(屬性) - 屬性就想成,是HP、MP這種自身的參數 - 這邊要介紹另一部動漫<<[怪獸8號](https://www.youtube.com/watch?v=CarsLstLs2s)>>,對他很好看ww ![upgit_20240813_1723542553.png](https://raw.githubusercontent.com/kcwc1029/obsidian-upgit-image/main/2024/08/upgit_20240813_1723542553.png) - 那它裡面要的平凡人,如果要打怪獸,就要穿上解放衣,並且激發解放力 ![upgit_20240813_1723542605.png](https://raw.githubusercontent.com/kcwc1029/obsidian-upgit-image/main/2024/08/upgit_20240813_1723542605.png) ### 第一種寫法:每個對象都有自己的屬性 - 在這種寫法中,每個對象都有自己的 `name`、`age` 和 `ingredient` 屬性。 ```python class Robot1: def __init__(self, name, age): self.name = name self.age = age self.ingredient = "metal" ``` ### 第二種寫法:使用類屬性 - 在這種寫法中,屬性 `ingredient` 被定義為類屬性,這意味著所有對象共享同一份 `ingredient` 屬性,而不是每個對象都有自己的副本。 - 這種寫法節省了空間,但如果需要為不同的對象設置不同的屬性值,就不適用。 ```python class Robot: ingredient = "metal" def __init__(self, name, age): self.name = name self.age = age def greet(self): print(f"hi, my name is {self.name}. and i am made of {Robot.ingredient}.") # 創建class robot1 = Robot("weiwei", 25) robot2 = Robot("robot2", 30) robot1.greet() # 訪問class print("Robot1 ingredient:", robot1.ingredient) # 输出 "metal" print("Robot2 ingredient:", robot2.ingredient) # 输出 "metal" # 也可以通过class本身来訪問屬性 print("Class attribute ingredient:", Robot.ingredient) # 输出 "metal" ``` ### 第三種寫法:使用 `self.__class__.attribute` - 這種寫法類似於第二種寫法,但是在方法中使用了 `self.__class__.ingredient` 來訪問類屬性。這樣做的好處是,如果後續需要修改類屬性的值,只需在類定義中修改一次即可,所有對象都會自動更新,而無需修改每個對象的屬性值。 ```python class Robot: ingredient = "metal" def __init__(self, name, age): self.name = name self.age = age def greet(self): print(f"hi, my name is {self.name}. and i am made of {self.__class__.ingredient}.") # 創建class robot1 = Robot("weiwei", 25) robot2 = Robot("robot2", 30) robot1.greet() # 访问class print("Robot1 ingredient:", robot1.ingredient) # 输出 "metal" print("Robot2 ingredient:", robot2.ingredient) # 输出 "metal" ``` ## 建構子與解構子 ```python class Person: # 建構子 def __init__(self, name, age): self.name = name self.age = age def introduce(self): print(f"Hi, my name is {self.name} and I am {self.age} years old") person = Person("助教", 23) person.introduce() # Hi, my name is 助教 and I am 23 years old ``` - 解構子是 `__del__` 方法,用於在物件被銷毀前執行清理操作。 ```python # 解構子 class Person: def __init__(self, name, age): self.name = name self.age = age def __del__(self): print(f"{self.name} is being deleted") person = Person("助教", 23) del person # 助教 is being deleted ``` ## static method & class method ### Instance Method - 第一個參數為 self。 - 實例化後,可以訪問物件屬性和實例方法。 ```python class MyClass: def instance_method(self): print("This is an instance method.") obj = MyClass() obj.instance_method() # This is an instance method. ``` ### Class Method 類別方法 - 使用 @classmethod 裝飾器定義的方法,第一個參數為 cls。 - 整個類別相關的操作,可以訪問類別的屬性和其他類別方法。 ```python class MyClass: class_variable = "Class Variable" @classmethod def class_method(cls): print(f"Class Method. Class Variable: {cls.class_variable}") # 使用類別方法 MyClass.class_method() # Class Method. Class Variable: Class Variable ``` ### Static Method 靜態方法 - 使用 @staticmethod 裝飾器定義的方法,不需要特定的第一個參數。 - 與類別和實例無關的操作,不訪問實例和類別的屬性。 ```python class MyClass: class_variable = "Class Variable" @staticmethod def static_method(): print("Static Method.") # 使用靜態方法 MyClass.static_method() # Static Method. ``` ### 綜合示範 ```python class Circle: pi = 3.14159 all_circles = [] # 建構子 def __init__(self,radius): self.radius = radius self.all_circles.append(self) # Instance Method(最一般的) def area(self): return self.pi * (self.radius**2) # Class Method 類別方法 @classmethod def total_area2(cls): total = 0 for i in cls.all_circles: total += i.area() return total # Static Method 靜態方法 @staticmethod def total_area(): total = 0 for i in Circle.all_circles: total += i.area() return total c1 = Circle(10) print(c1.all_circles) # [<__main__.Circle object at 0x00000102F199B490>] c2 = Circle(15) print(c1.all_circles) # [<__main__.Circle object at 0x00000102F19797D0>, <__main__.Circle object at 0x00000102F0B6E490>] print(c1.area()) # 314.159 print(c1.total_area2()) # 1021.01675 print(c1.total_area()) # 1021.01675 ``` ## 繼承(inheritance) - 繼承允許一個類(子類)繼承另一個類(父類)的屬性和方法。 ```python class People: def __init__(self, name, age) -> None: self.name = name self.age = age def sleep(self): print(f"{self.name} is sleeping...") def eat(self): print(f"{self.name} is eating...") class Student(People): def __init__(self, name, age, student_id) -> None: super().__init__(name, age) # 繼承 self.student_id = student_id def eat(self,food): # 方法可以被覆寫 print(f"{self.name} is eating now {food}...") student1 = Student("助教", 23, 10911221) print(student1.age, student1.student_id) # 23 10911221 student1.sleep() # 助教 is sleeping... student1.eat("怪獸8號蟲蟲") # 助教 is eating now 怪獸8號蟲蟲... ``` ## 多型(Polymorphism) - 多型允許同一方法在不同物件中有不同的實現。 - 繼承時會覆寫方法 ```python class People: def speak(self): return "say something" class 卡夫卡(People): def speak(self): return "我還可以以你的身邊為目標前進嗎?" class 米娜(People): def speak(self): return "恩,我會一直等你的" people1 = 卡夫卡() people2 = 米娜() print(people1.speak()) # '我還可以以你的身邊為目標前進嗎?' print(people2.speak()) # '恩,我會一直等你的' ``` ```python class 亞白米娜(): # 防衛隊第3部隊的隊長 def __init__(self): self.power = 96 self.years = 27 class 四之宮琪歌露(亞白米娜): def __init__(self): super().__init__() # 使用 super() 繼承 亞白米娜 __init__ 裡所有屬性 self.power = 55 # 如果屬性相同,則覆寫屬性 self.years = 16 self.sex = "female" class 日比野卡夫卡(亞白米娜): def __init__(self): super().__init__() # 使用 super() 繼承 亞白米娜 __init__ 裡所有屬性 self.power = 1 # 如果屬性相同,則覆寫屬性 self.years = 32 self.sex = "male" person = 四之宮琪歌露() print(person.power) # 55 ``` ## 多重繼承 - 繼承不僅能進行單一繼承,也可以進行多重繼承,例如可以從爸爸身上繼承基因,同時也可以從媽媽身上繼承基因一般 ```python class father(): def __init__(self): self.eye = 2 self.ear = 2 self.nose = 1 self.mouth = 1 class mother(): # mother 类 def language(self): # mother 的方法 print('english') def skill(self): print('painting') class son(father, mother): # 继承 father 和 mother def __init__(self): super().__init__() # 繼承爸爸媽媽 def play(self): print('play phone') person = son() print(person.eye) # 输出 2 person.skill() # 输出 painting person.play() # 输出 ball ``` ## 多層繼承 ```python class grandpa(): def __init__(self): self.eye = 2 self.ear = 2 self.nose = 1 self.mouth = 1 class father(grandpa): def __init__(self): super().__init__() # 调用父类的构造函数 def language(self): print('english') def skill(self): print('painting') class son(father): def __init__(self): super().__init__() # 调用父类的构造函数 def play(self): print('ball') person = son() print(person.eye) # 输出 2 person.skill() # 输出 painting person.play() # 输出 ball ``` ## 抽象(Abstraction) - 抽象是指僅顯示物件的必要屬性和行為,隱藏內部的實現細節。 - python要借助套件實現 ```python from abc import ABC, abstractmethod class Moster(ABC): @abstractmethod def say(self): return "我會一直等你的" class 卡夫卡(Moster): def say(self): return "我還可以以你的身邊為目標前進嗎?" class 米娜(Moster): def say(self): return "恩,我會一直等你的" person1 = 卡夫卡() person2 = 米娜() print(person1.say())# 我還可以以你的身邊為目標前進嗎? print(person2.say())# 恩,我會一直等你的 # error thief = Moster() thief.say() # Can't instantiate abstract class Moster with abstract method say ``` ## 封裝(Encapsulation)與私有化 - 封裝是將資料和方法綁定在一起,並隱藏物件的內部細節。可以透過在屬性或方法前加上雙下劃線(__)將其設為私有。 ### getter & setter ```python class Robot: def __init__(self,name, age) -> None: self.name = name self.age = age self.sex = "male" # public my_robot = Robot("TA", 23) my_robot.sex = "female" # 數值被隨意篡改了,也正因此有了private的概念 print(my_robot.sex) # female ``` ```python # 增加getter跟setter的概念 class Robot: def __init__(self,name, age) -> None: self.name = name self.age = age self.__sex = "male" # getter def getter(self): return self.__sex # setter def setter(self, new_sex): # 更改要透過函數 self.__sex = new_sex my_robot = Robot("TA", 23) my_robot.getter() # male my_robot.setter("female") my_robot.getter() # female ``` ## 裝飾器@property decorator(只讀) - 如果在類別裡有些屬性不希望被外部更動,就能夠使用 @property 的裝飾器,將該屬性設為唯讀屬性 - 要使用的話,要用屬性的方式歐 ```python class 卡夫卡(): def __init__(self): self.sentence = "我還可以以你的身邊為目標前進嗎?" def say(self): return self.sentence person1 = 卡夫卡() person1.say() # '我還可以以你的身邊為目標前進嗎?' person1.sentence = "我是金句破壞王" # 屬性被更改掉了 person1.say() # '我是金句破壞王' ``` ```python # 將sentence設為only read class 米娜(): def __init__(self): self.sentence = "恩,我會一直等你的" @property def say(self): return self.sentence person1 = 米娜() person1.say # '恩,我會一直等你的' # person1.say = "4546" # error ``` ## Lab08/作業題目 - 繳交方式 : 請到[https://140.116.179.59:8080](https://140.116.179.59:8080)完成作業題目,並將程式碼加上註解(你的理解),很重要,否則助教有權利扣你分數。 - 禁止抄襲,否則助教會來查水表。