Python 物件導向程式設計
目錄
1 程式導向程式設計
程式導向——Procedure Oriented,是一種以過程為中心的程式設計思想,它首先分析出解決問題所需要的步驟,然後用函式把這些步驟一步一步實現,在使用時依次呼叫,是一種基礎的順序的思維方式。程式導向開發方式是對計算機底層結構的一層抽象,它將程式分為資料和操縱資料的操作兩部分,其核心問題是資料結構和演算法的開發和優化。
最典型的就是流水線,上一道工序完成後,後面的流程才能進行。
-
面過程程式設計的特點:
功能模組化,程式碼流程化
-
優點:
效能高,適合資源緊張、實時性強的場合
-
缺點:
不易複用和不易擴充套件
2 物件導向程式設計
物件導向程式設計——Object Oriented Programming,簡稱OOP
,是一種程式設計思想。OOP
把物件作為程式的基本單元,一個物件包含了資料和運算元據的函式。
物件導向的程式設計把計算機程式視為一組物件的集合,而每個物件都可以接收其他物件發過來的訊息,並處理這些訊息,計算機程式的執行就是一系列訊息在各個物件之間傳遞。
在Python中,所有資料型別都可以視為物件,當然也可以自定義物件。自定義的物件資料型別就是物件導向中的類(Class)的概念。
3. 程式導向和麵向物件的優缺點
物件導向 | 程式導向 | |
---|---|---|
特性 | 抽象、繼承、封裝、多型 | 功能模組化,程式碼流程化 |
優點 | 易維護、易複用、易擴充套件、低耦合 | 效能高,適合資源緊張、實時性強的場合 |
缺點 | 效能比程式導向低 | 沒有物件導向易維護、易複用、易擴充套件 |
4. 由淺入深瞭解物件導向
4.1 學生選課為例
"""
1, 要定義學生的資訊: 姓名,性別,年齡,學校,所選課程
"""
# 學生的特徵:
student_name = 'Hans'
student_gender = 'M'
student_age = 20
shool = '社會大學'
student_course = []
# 學生的功能:選課
def course_selection_system(name, gender, age, shool, course):
student_course.append(course)
print("學生:%s 性別:%s 年齡:%s 在%s 期間所選課程:%s" % (name, gender, age, shool, student_course))
# 執行結果:
course_selection_system(student_name, student_gender, student_age, shool, "如何接受社會的毒打")
學生:Hans 性別:M 年齡:20 在社會大學 期間所選課程:['如何接受社會的毒打']
"""
2, 把學生的資訊定義成一個字典
"""
student1 = {
'student_name': 'Hans',
'student_gender': 'M',
'student_age': 20,
'shool':'社會大學',
'student_course':[]
}
def course_selection_system(student, course):
student1['student_course'].append(course)
print("學生:%s 性別:%s 年齡:%s 在%s 期間所選課程:%s" % (student['student_name'], student['student_gender'], \
student['student_age'], student['shool'], student['student_course']))
#執行結果:
course_selection_system(student1, "如何接受社會的毒打")
學生:Hans 性別:M 年齡:20 在社會大學 期間所選課程:['如何接受社會的毒打']
"""
3, 把選課的函式放到字典裡, 某個學生要選課成功,裡面要包括他的特徵和技能,
這樣一個學生他的特徵和功能都有了
"""
def course_selection_system(student, course):
student1['student_course'].append(course)
print("學生:%s 性別:%s 年齡:%s 在%s 期間所選課程:%s" % (student['student_name'], student['student_gender'], \
student['student_age'], student['shool'], student['student_course']))
student1 = {
'student_name': 'Hans',
'student_gender': 'M',
'student_age': 20,
'shool':'社會大學',
'student_course':[],
'course_select':course_selection_system
}
student2 = {
'student_name': 'Jack',
'student_gender': 'M',
'student_age': 20,
'shool':'社會大學',
'student_course':[],
'course_select':course_selection_system
}
student1['course_select'](student1, "五塊錢如何花一星期")
student2['course_select'](student2, "如何接受社會的毒打")
#執行結果:
學生:Hans 性別:M 年齡:20 在社會大學 期間所選課程:['五塊錢如何花一星期']
學生:Jack 性別:M 年齡:20 在社會大學 期間所選課程:['如何接受社會的毒打'
# 這是一兩個學生,如果是十個,百個或更多都要手寫一遍???
# 這時就需要物件導向了。
"""
物件是什麼
1. 程式中:
函式:盛放資料的容器
物件:盛放資料和函式的容器
2. 現實生活中:
一切皆物件
物件:特徵與技能的結合體
"""
4.2 類和物件
"""
物件: 特徵與技能的結合體
類:一系列物件相似的特徵與相似的技能的結合體
站在不同的分類,劃分的分類不一定一樣
在程式中先有類再有物件。現實中先有物件,再有類
"""
# 把上面的程式 相同的部分拿出來,
student1 = {
'student_name': 'Hans',
'student_gender': 'M',
'student_age': 20,
'shool':'社會大學',
'student_course':[],
'course_select':course_selection_system
}
student2 = {
'student_name': 'Jack',
'student_gender': 'M',
'student_age': 20,
'shool':'社會大學',
'student_course':[],
'course_select':course_selection_system
}
"""
這個程式中有哪些是相同的:
學校(shool)和選課功能(course_selection_system)
可以把這兩個功能提取出來
"""
student_public = {
'shool':'社會大學',
'course_select':course_selection_system
}
# 這個提取出來的公共的功能就是類,但在python中寫有專業的寫法:
class 類名():
pass
# class為關鍵字
# 類名一般首字母大寫
# 程式碼:
class student_public():
shool = '社會大學'
def course_selection_system(student, course):
student1['student_course'].append(course)
print("學生:%s 性別:%s 年齡:%s 在%s 期間所選課程:%s" % (student['student_name'], student['student_gender'], \
student['student_age'], student['shool'], student['student_course']))
# 類在定義的時候會執行,這是與函式不同的地方(函式在定義時不會執行,只有在呼叫時執行)
# 檢視類的名稱空間:
print(student_public.__dict__)
{'__module__': '__main__', 'shool': '社會大學', 'course_selection_system': <function student_public.course_selection_system at 0x000002ADBB6AA5F0>, '__dict__': <attribute '__dict__' of 'student_public' objects>, '__weakref__': <attribute '__weakref__' of 'student_public' objects>, '__doc__': None}
# 類的底層為字典
"""
類在定義時做了哪些:
1. 類在定義時會立即執行
2. 產生一個類的名稱空間,然後把類體裡執行的資料都放到名稱空間裡(__dict__返回的字典裡)
3. 把類的名稱空間繫結給__dict__
變數放到類裡面叫屬性
函式放到類裡面叫方法
"""
# 呼叫類
stu = student_public()
# 呼叫類從而產生物件。
# 呼叫類從而產生物件的過程,叫類的初始化
#檢視物件的名稱空間
print(stu.__dict__)
# 執行結果:
{} # 一個空字典
# 現在用Python的語法把類定義出來了。
# 但是學生自己獨有的特徵還沒有(自己的名字,自己的年齡等等),剛才看到了為空
# 給物件新增自己獨有的特徵
stu.__dict__['name'] = 'Hans'
stu.__dict__['gender'] = 'M'
stu.__dict__['age'] = 20
stu.__dict__['course'] = ['五塊錢如何花一星期','如何接受社會毒打']
print(stu.__dict__)
# 執行結果:
{'name': 'Hans', 'gender': 'M', 'age': 20, 'course': ['五塊錢如何花一星期', '如何接受社會毒打']}
# 物件的名稱空間為一個空字典,現在新增了一些key,所以也可以對它進行取值
print(stu.__dict__['name'])
Hans
#在Python中一般不使用這種方法賦值和取值,Python中的方法
# 新增
stu.name = 'Hans'
stu.gender = 'M'
stu.age = 20
stu.course = ['五塊錢如何花一星期','如何接受社會毒打']
# 取值
print(stu.__dict__)
print(stu.name)
# 執行結果:
{'name': 'Hans', 'gender': 'M', 'age': 20, 'course': ['五塊錢如何花一星期', '如何接受社會毒打']}
Hans
# 這種方法只能在物件種使用
# 上面的方法依然是很個學生物件都要寫一遍,所以這個方法也可以做成函式形式。
# 1. 定義一個類
class student_public():
shool = '社會大學'
def course_selection_system(student, course):
student['student_course'].append(course)
print("學生:%s 性別:%s 年齡:%s 在%s 期間所選課程:%s" % (student['student_name'], student['student_gender'], \
student['student_age'], student['shool'], student['student_course']))
#
# 例項化物件
stu1 = student_public()
# 定義函式
def init(name,gender,age,course):
stu1.name = name
stu1.gender = gender
stu1.age = age
stu1.course = course
init('hans', 'M',20,['五塊錢如何花一星期','如何接受社會毒打'])
print(stu1.__dict__)
# 執行結果:
{'name': 'hans', 'gender': 'M', 'age': 20, 'course': ['五塊錢如何花一星期', '如何接受社會毒打']}
# init()函式中stu1為固定值,如果初始化一個學生,這個函式就不滿足了,所以stu1的位置也要傳參獲得
def init(student,name,gender,age,course):
student.name = name
student.gender = gender
student.age = age
student.course = course
stu1 = student_public()
stu2 = student_public()
init(stu1,'hans', 'M',20,['五塊錢如何花一星期','如何接受社會毒打'])
init(stu2,'jack', 'M',18,['五塊錢如何花一星期','如何接受社會毒打'])
print(stu1.__dict__)
print(stu2.__dict__)
# 執行結果:
{'name': 'hans', 'gender': 'M', 'age': 20, 'course': ['五塊錢如何花一星期', '如何接受社會毒打']}
{'name': 'jack', 'gender': 'M', 'age': 18, 'course': ['五塊錢如何花一星期', '如何接受社會毒打']}
# 這樣比較相對比較完美了,但是每次都要手動呼叫init()這個方法,有沒有什麼方法可以自動執行init()
# 可以把它寫入到類裡面,不過要變形
class student_public():
def __init__(student, name, gender, age, course):
student.name = name
student.gender = gender
student.age = age
student.course = course
shool = '社會大學'
def course_selection_system(student, course):
student['student_course'].append(course)
print("學生:%s 性別:%s 年齡:%s 在%s 期間所選課程:%s" % (student['student_name'], student['student_gender'], \
student['student_age'], student['shool'], student['student_course']))
print(student_public.__dict__)
stu1 = student_public()
# 執行結果:
TypeError: student_public.__init__() missing 4 required positional arguments: 'name', 'gender', 'age', and 'course'
# 提示要四個引數,現在給它傳四個引數:
stu1 = student_public('hans', 'M',20,['五塊錢如何花一星期','如何接受社會毒打'])
print(stu1.__dict__)
# 現在執行不會報錯
{'name': 'hans', 'gender': 'M', 'age': 20, 'course': ['五塊錢如何花一星期', '如何接受社會毒打']}
# __init__()上面寫了五個引數,但是物件在呼叫的時候只讓寫四個,因為使用物件呼叫它會把自己當成第一個引數傳遞給函式。
# 在類中的方法,類和物件都可以呼叫,但是類在呼叫的時候,裡面寫了幾個引數就要傳幾個引數,但是使用物件時它把自己當成第一個引數傳過去,所以推薦使用物件呼叫
# Python中,因為方法中第一個引數為自己,所以把這個寫成self
class student_public():
def __init__(self, name, gender, age, course):
self.name = name
self.gender = gender
self.age = age
self.course = course
shool = '社會大學'
def course_selection_system(self, course):
self['student_course'].append(course)
print("學生:%s 性別:%s 年齡:%s 在%s 期間所選課程:%s" % (self['student_name'], self['student_gender'], \
self['student_age'], self['shool'], self['student_course']))
# 執行:
stu1 = student_public('hans', 'M', 20, '五塊錢如何花一星期') # 例項化物件
print(stu1.__dict__)
{'name': 'hans', 'gender': 'M', 'age': 20, 'course': '五塊錢如何花一星期'}
# 判斷一個
print(isinstance(stu1, student_public))
True
"""
呼叫類:
1. 呼叫類(stu1 = student_public())會得到一個空物件,把這個空物件傳給student_public.__dict__
2. 呼叫student_public.__dict__(空物件,'hans', 'M',20,'五塊錢如何花一星期')
3. 得到一個初始化結果
4. 在__init__裡不能使用return 返回值,如果真要使用也只能返回None
"""
4.3 屬性的查詢順序
類屬性(在類中定義的):
# 1, 檢視類屬性
class student_public():
def __init__(student, name, gender, age, course):
student.name = name
student.gender = gender
student.age = age
student.course = course
shool = '社會大學'
stu1 = student_public('hans', 'M',20,'五塊錢如何花一星期')
print(stu1.shool)
# 2, 增加一個類屬性
stu1.country = 'CN'
print(stu1.__dict__)
{'name': 'hans', 'gender': 'M', 'age': 20, 'course': '五塊錢如何花一星期', 'country': 'CN'}
# 3, 修改類屬性
stu1.shool = '清華大學'
print(stu1.shool)
清華大學
# 4, 修改類屬性
del stu1.shool
物件屬性
class student_public():
def __init__(student, name, gender, age, course):
student.name = name
student.gender = gender
student.age = age
student.course = course
shool = '社會大學'
stu1 = student_public('hans', 'M',20,'五塊錢如何花一星期')
# 1, 檢視
print(stu1.name)
print(stu1.gender)
print(stu1.age)
hans
M
20
# 2, 修改
stu1.age = 18
print(stu1.age)
18
# 3,增加
stu1.result = '優'
print(stu1.__dict__)
{'name': 'hans', 'gender': 'M', 'age': 18, 'course': '五塊錢如何花一星期', 'country': 'CN', 'result': '優'}
# 4, 刪除
del stu1.result
print(stu1.__dict__)
{'name': 'hans', 'gender': 'M', 'age': 18, 'course': '五塊錢如何花一星期', 'country': 'CN'}
屬性查詢順序
1. 先在物件中查詢,如果物件中沒有則去類中查詢
class student_public():
def __init__(self, name, gender, age, course):
self.name = name
self.gender = gender
self.age = age
self.course = course
shool = '社會大學'
print(stu1.shool) # 這個shool為類中定義的
社會大學
print(stu1.__dict__['shool']) # 這個會報錯,因為在物件stu1中根本沒有shool這個屬性,shool這個是類的屬性,直接這麼取是拿不到的,因為指定從物件stu1中的名稱空間中取,物件stu1中的名稱空間中根本沒有。
#所以使用點(.)的方式,如果物件中的名稱空間中沒有,它會去類的名稱空間中找。
class student_public():
def __init__(self, name, gender, age, course):
self.name = name
self.gender = gender
self.age = age
self.shool = "清華大學"
self.course = course
shool = '社會大學'
print(stu1.shool) # 這個shool為物件中定義的
清華大學
5. 物件導向繫結方法
5.1 小案例:計算一共產生了多少個物件
class Count():
count = 0
def __init__(self, name):
self.name = name
Count.count +=1 # 統計次數
s1 = Count('Hello')
s2 = Count('World')
print(Count.count)
# 執行結果:
2
# 類屬性修改,所有物件都改。
# 還有一種寫法:
class Count():
count = 0
def __init__(self, name):
self.name = name
self.__class__.count +=1 # 統計次數 和Count.count +=1 一樣
s1 = Count('Hello')
s2 = Count('World')
print(Count.count)
5.2 繫結方法
繫結方法有兩種:
-
繫結給物件
class Students(): def __init__(self,name, age, gender): self.name = name self.age = age self.gender = gender def printInfo(self): print("%s %s %s" % (self.name, self.age, self.gender)) stu = Students("Hans", 18, 'M') stu.printInfo() # 把printInfo方法繫結給物件stu
-
繫結給類
IP = '192.168.1.123' PORT = 3306 class Mysql(): def __init__(self, ip, port): self.ip = ip self.port = port mysql = Mysql(IP, PORT) print(mysql.ip,mysql.port) # 執行結果: 192.168.1.123 3306 # 如果有多個需要寫多次。能不能把Mysql(IP, PORT)這個只寫一次 # 可以把這個放到一個函式裡 IP = '192.168.1.123' PORT = 3306 class Mysql(): def __init__(self, ip, port): self.ip = ip self.port = port def tell(self): mysql = Mysql(IP, PORT) return mysql obj = Mysql(IP, PORT) obj1 = obj.tell() print(obj1.ip,obj1.port) # 寫到函式裡後,又有一個問題,mysql = Mysql(IP, PORT)現在是寫的MySQL的,如果換別的資料庫如redis,pg等是不是就不那麼靈活了。 class Database(): def __init__(self, ip, port): self.ip = ip self.port = port @classmethod def tell(cls): obj = cls(IP, PORT) return obj mysql = Database.tell() print(mysql.ip, mysql.port) # 換個IP和埠 IP = '192.168.1.111' PORT = 6379 redis = Database.tell() print(redis.ip, redis.port) # 執行結果: 192.168.1.123 3306 192.168.1.111 6379 # @classmethod 這個裝飾器繫結給了類,以後類來呼叫,會自動把類名當成第一個引數傳過來(cls) # 這時呼叫的時候,使用類名呼叫 # 如果即用到繫結物件,又用到繫結類,推薦使用繫結物件,因為在物件中可以使用__class__拿到類
5.3 靜態方法(非繫結方法)
import random
class Students():
def __init__(self,name,age):
self.name = name
self.age = age
def randnum(self):
print(random.randint(1, 10))
info = Students("Hans", 18)
info.randnum()
info.randnum()
# 執行結果:
1
4
# 在 def randnum(self) 中根本沒有用到self,是不是可以不傳?
# 現在在類中如果不傳就會報錯(TypeError: Students.randnum() takes 0 positional arguments but 1 was given),所以可以使用 @staticmethod
import random
class Students():
def __init__(self,name,age):
self.name = name
self.age = age
@staticmethod
def randnum():
print(random.randint(1, 10))
info = Students("Hans", 18)
info.randnum()
info.randnum()
# 執行結果:
4
9
6. 隱藏屬性
為什麼要隱藏屬性?
有些時間有些資料,只想讓內部看到,不想讓外部看到。
如何隱藏屬性
class Students():
shool = '社會大學'
def __init__(self,name,age):
self.name = name
self.age = age
stu1 = Students("Hans", 18)
print(stu1.shool)
#shool是可以拿到的,如何把shool屬性隱藏掉
class Students():
__shool = '社會大學' # 只需要在屬性前面加兩個下劃線(__),只在前面加
def __init__(self,name,age):
self.name = name
self.age = age
stu1 = Students("Hans", 18)
print(stu1.shool)
# 執行結果:
AttributeError: 'Students' object has no attribute 'shool'
print(stu1.__shool)
# 執行結果:
AttributeError: 'Students' object has no attribute '__shool'
# 就會發現shool這個不管用什麼方法都訪問不到了。
# 可以看一下它變成了什麼?
print(Students.__dict__)
{'__module__': '__main__', '_Students__shool': '社會大學', '__init__': <function Students.__init__ at 0x000001E5EC31A0E0>, '__dict__': <attribute '__dict__' of 'Students' objects>, '__weakref__': <attribute '__weakref__' of 'Students' objects>, '__doc__': None}
# 可以看到shool前面加了雙下劃線(__)後就變成: _Students__shool(_類名__屬性名)
# 現在在外面拿不到了,在內部是否可以拿到?
class Students():
__shool = '社會大學'
def __init__(self,name,age):
self.name = name
self.age = age
def get_shool(self):
return self.__shool
stu1 = Students("Hans", 18)
print(stu1.get_shool())
# 執行結果:
社會大學
# 可以看到在內部可以拿到
# 其實如果外部要拿也能拿到:
stu1 = Students("Hans", 18)
print(stu1._Students__shool) # 因為在類的名稱空間為_Students__shool,所以直接取這個就可以拿到
print(Students._Students__shool)
# 不但可以隱藏類中的屬性也可以隱藏方法和物件中的屬性,寫法都一樣,使用雙下劃線
# 物件屬性:
self.__name
#類中的方法:
def __get_shool(self):
#
# 在外部有方法拿到隱藏的屬性,是不是也可以修改? 正常的方法是改不了,可以在類中定義一個專門修改的函式
class Students():
__shool = '社會大學'
def __init__(self,name,age):
self.name = name
self.age = age
def get_shool(self):
return self.__shool
def set_shool(self):
self.__shool = "清華大學"
stu1 = Students("Hans", 18)
stu1.set_shool()
print(stu1.get_shool())
# 執行結果:
清華大學
# 更好的方法是給set_shool傳值
class Students():
__shool = '社會大學'
def __init__(self,name,age):
self.name = name
self.age = age
def get_shool(self):
return self.__shool
def set_shool(self,shoolname):
self.__shool = shoolname
stu1 = Students("Hans", 18)
stu1.set_shool("北京大學")
print(stu1.get_shool())
# 執行結果:
北京大學
# 還可以對修改的內容進行判斷,現在要修改的是學校名字,按目前寫的傳什麼值都可以,但有些型別不合適用在這個地方比如int型別,所以可以判斷一下。
class Students():
__shool = '社會大學'
def __init__(self,name,age):
self.name = name
self.age = age
def get_shool(self):
return self.__shool
def set_shool(self,shoolname):
# if type(shoolname) is not str: return
if not isinstance(shoolname, str): return
self.__shool = shoolname
stu1 = Students("Hans", 18)
stu1.set_shool(123) # 123 不是字串,直接return返回,所以shool的值還是原來的
print(stu1.get_shool())
# 執行結果:
社會大學
"""
隱藏屬性發生了什麼?
1, 在類定義階段發生了變化,如__shool變成了_Students__shool,也只有在定義階段發生變化,其他地方都不會發生變化
2, 隱藏對外不對內
"""
7. property裝飾器
property是python的一種裝飾器,是用來修飾方法的。
上面的例子我們把一些不想對外公開的屬性隱蔽起來,而只是提供方法給使用者操作(檢視get_shool和設定set_shool),在方法裡面,我們可以檢查引數的合理性等。
class Students():
__shool = '社會大學'
def __init__(self,name,age):
self.__name = name
self.age = age
def get_name(self):
return self.__name
def set_name(self):
self.__name="ABC"
stu = Students("Hans", 18)
print(stu.get_name())
stu.set_name()
print(stu.get_name())
# 執行結果:
Hans
ABC
# 我們要得到name必須要呼叫get_name方法,但正常我們取一個屬性直接使用.加屬性名就可以(stu.name),
# 但現在還要呼叫一個方法,如何實現即要隱藏屬性又要使用.屬性獲得值,就可以使用@property
class Students():
__shool = '社會大學'
def __init__(self,name,age):
self.__name = name
self.age = age
@property
def name(self): # 為了更像stu.name這種方法,把方法名直接改為name
return self.__name
stu = Students("Hans", 18)
print(stu.name)
# 執行結果:
Hans
# @property 裝飾器會將 name() 方法轉化為一個具有相同名稱的只讀屬性的 "getter"
# 在修改的時候也要像查詢一樣,直接使得.屬性的方式
class Students():
__shool = '社會大學'
def __init__(self,name,age):
self.__name = name
self.age = age
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
if not isinstance(name, str):
print("必須為字串")
return
self.__name= name
stu = Students("Hans", 18)
print(stu.name) # Hans
stu.name = 123 # 必須為字串,執行到了isinstance
print(stu.name) # Hans
# 修改為一個合法型別:
stu = Students("Hans", 18)
print(stu.name) # Hans
stu.name = "XYZ"
print(stu.name) # XYZ
# 可以看到已經修改
# 要使用這種方法,在定義時:
"""
@property
def name(self): 1
return self.__name
@name.setter 2
def name(self,xxx) 3
這三個地方的名字一定要一致。
"""
# 刪除一個屬性
class Students():
__shool = '社會大學'
def __init__(self,name,age):
self.__name = name
self.age = age
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
if not isinstance(name, str):
print("必須為字串")
return
self.__name= name
@name.deleter
def name(self):
del self.__name
print("正在刪除%s" % self.__name)
stu = Students("Hans", 18)
del stu.name
print(stu.name)
# 執行結果:
正在刪除Hans
# 還有一種寫法,現在已經不常用了,即定義一個託管屬性
class Students():
__shool = '社會大學'
def __init__(self,name,age):
self.__name = name
self.age = age
def get_name(self):
return self.__name
def set_name(self,name):
if not isinstance(name, str):
print("必須為字串")
return
self.__name= name
def del_name(self):
print("正在刪除%s" % self.__name)
# 定義一個託管屬性
name = property(get_name, set_name, del_name)
stu = Students("Hans", 18)
print(stu.name) # 呼叫get_name 方法
stu.name = "XYZ" # 呼叫set_name 方法
print(stu.name)
del stu.name # 呼叫del_name 方法
# 執行結果:
Hans
XYZ
正在刪除XYZ
property
就是把方法偽裝成屬性
property
詳細請看官網: