今日內容概要
- 組合
- 面向對象的內置函數(魔術方法、魔法)
- 反射
- 異常
內容詳細

組合
# 什么是組合
就是一個對象擁有一個屬性
但是該屬性的值 是另外一個對象
# 繼承
其實就可以描述為:
滿足什么是什么的關系 is-a的關系
'''
is-a 從字面上看就表示"是一個"的意思 根據繼承的特性
一個派生類對象(子類) 可以看成是一個基類(父類)對象
也就是說一個派生類對象"是一個"基類對象,所以這種名稱符合對這種特性的概括。
'''
# 繼承是一把雙刃劍 並不是繼承的越多越好 多繼承盡量少一些
# 例1
class Foo:
def __init__(self, m):
self.m = m
class Bar():
def __init__(self, n):
self.n = n
obj = Foo(10) # m = 10
obj1 = Bar(20) # n = 20
obj.x = obj1 # obj.x就是一個組合 就是一個對象擁有一個屬性obj.x 但是該屬性的值 是另外一個對象obj1
print(obj.__dict__) # {'m': 10, 'x': <__main__.Bar object at 0x000001F73E14B470>}
# obj 就是一個超級對象 不僅可以拿自己對象中的屬性 還可以拿到其他對象中的屬性
print(obj.x.n) # 20 obj.x就相當於obj1
print(obj1.n) # 20
# 例2
# 父類
class People():
school = 'SH'
def __init__(self, name, age, gender, ):
self.name = name
self.age = age
self.gender = gender
class Admin(People):
pass
# 父類
class Course():
def __init__(self, name, period, price, ):
self.name = name
self.period = period
self.price = price
python = Course('python', '6mon', 10000) # 實例化對象 課程就出來了
linux = Course('linux', '5mon', 20000) # 實例化對象 課程就出來了
# 子類
class Student(People, Course):
def __init__(self, name, age, gender, course=None):
if course is None:
course = []
self.courses = course
super().__init__(name, age, gender, )
def choose_course(self, stu_obj, course):
stu_obj.courses.append(course)
stu = Student('ly', 19, 'male', 'python')
print(stu.name) # ly
stu = Student('ly', 20, 'male')
# 課程已經有過了
# python = Course('python', '6mon', 10000) # 實例化對象 課程就出來了
# linux = Course('linux', '5mon', 20000) # 實例化對象 課程就出來了
stu.courses.append(python)
stu.courses.append(linux)
print(stu.courses) # 內存地址 [<__main__.Course object at 0x00000186D04BB390>, <__main__.Course object at 0x00000186D04BB3C8>]
# 實例化后結果 [python, linux] 列表里面是兩個內存地址
for course in stu.courses: # 通過內存地址空間中找屬性
print(course.price)
# 10000
# 20000
# 子類
class Teacher(People, Course):
def __init__(self, name, age, gender, level):
self.level = level
super().__init__(name, age, gender, )
def score(self, stu_obj, score):
stu_obj.score = score
tea = Teacher('ly', 19, 'male', 10)
tea.course = linux
print(tea.course.name) # 課程名 linux
print(tea.course.price) # 課程價格 20000
print(tea.course.period) # 課程周期 5mon

面向對象的內置函數
# 1. __init__()
調用類的時候自動觸發的方法
# 2. __str__()
只要打印對象的時候 就會自動觸發的方法
# 3. __del__()
# 4. __enter__()
# 5. __exit__()
# 6. __call__()
# 1. __init__() 2. __str__()
class Student():
school = 'SH'
# 調用類的時候觸發
def __init__(self, name, age):
self.name = name
self.age = age
def tell(self):
print('name: %s, age: %s' % (self.name, self.age))
# 只要打印對象的時候,就會自動觸發的函數
# 但是返回值只能是字符串
def __str__(self):
return 'name:%s' % self.name
# return 123 報錯 返回值只能是字符串
stu = Student('ly', 20)
print(stu) # name:ly 就相當於打印 print(stu.__str__())
f = open('a.txt', mode='w')
print(f) # 結果是經過底層處理的數據 <_io.TextIOWrapper name='a.txt' mode='w' encoding='cp936'>
# 3. __del__()
class Student():
school = 'SH'
# 調用類的時候觸發
def __init__(self, name, age):
self.name = name
self.age = age
self.f = open('a.txt', 'r')
# 1. 手動執行del
# 2. 程序執行完畢觸發
def __del__(self):
print('from __del__')
self.f.close()
stu = Student('ly', 19)
del stu.school # 報錯 因為stu對象默認是空
del Student.school # from __del__ 后走
print('end=>>>>>>>>>>>>') # 先走
del stu.name # from __del__
print(stu.school)
print('end=>>>>>>>>>>>>')
# 4. __enter__() 5. __exit__()
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出現with語句,對象的__enter__被觸發,有返回值則賦值給as聲明的變量') # 1
return self
# return 123
# __enter__執行之后 繼續執行with代碼體
def __exit__(self, exc_type, exc_val, exc_tb): # with代碼體 執行完之后 執行__exit__
print('with中代碼塊執行完畢時執行我啊') # 4
with Open('a.txt') as f:
print('=====>執行代碼塊') # 2
print(f) # <__main__.Open object at 0x00000246D7B793C8> # 3
print(f, f.name) # 5
# 6. __call__()
class Foo:
def __init__(self):
pass
# 對象加括號自動觸發
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 執行 __init__
# 一切皆對象 對象就可以加括號
obj() # __call__
'''
a = list([1, 2, 3])
# a.append(4) # 就相當於 list.append(a, 4)
list.append(a, 5)
print(a) # [1, 2, 3, 5]
'''

反射
# 反射是指:對象通過字符串來操作屬性
class Student():
school = 'sh'
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
print('from func')
stu = Student('ly', 18)
print(stu.name) # ly
print(stu."name") # 報錯 不能直接用字符串
print(stu.__dict__['name']) # ly 存在則正常獲取屬性
print(stu.__dict__['name11']) # 不存在的情況直接報錯
# 1. getattr
print(getattr(stu, 'name1', None)) # None 相當於 stu.name 第一個參數傳對象 第二個傳屬性 第三個傳找不到的返回結果
stu.func() # from func 直接調用
print(getattr(stu, 'func')) # 通過字符串調用 <bound method Student.func of <__main__.Student object at 0x0000020BB6FBBD30>>
getattr(stu, 'func')() # from func 必須掌握
# 2. setattr
setattr(stu, 'x', 123) # 第一個傳對象 第二個傳屬性名 第三個傳屬性值
print(stu.__dict__) # {'name': 'ly', 'age': 18, 'x': 123}
# 3. hasattr
print(hasattr(stu, 'name')) # True 確認對象中是否有屬性 第一個傳對象 第二個傳屬性
print(hasattr(stu, 'name1')) # False
# 4. delattr
delattr(stu, 'name') # 刪除 第一個傳對象 第二個傳屬性
print(stu.__dict__) # {'age': 18}
# 類也可以使用
print(getattr(Student, 'school'))
# 模塊也可以使用
import time
time.sleep(1)
getattr(time, 'sleep')(2)
# 導模塊底層寫法 __import__('time') 就相當於 import time
time = __import__('time') # 就相當於 import time 導入模塊
time.sleep(3) # 用法一樣

異常
1.什么是異常
異常就是錯誤發生的信號
'''如果不對該信號做處理 那么異常之后的代碼不會執行'''
# 異常種類
語法錯誤
不被允許的 print(12
邏輯錯誤
被允許 但盡量不要出現
a = [1, 2, 3]
print(a[5])
2.為什么要用異常
增強代碼的健壯性
3.怎么用異常
try:
被監測代碼
except 異常的類型:
pass # 異常處理流程
except 異常的類型:
pass # 異常處理流程
except 異常的類型:
pass # 異常處理流程
except Exception as e: # 萬能異常 不管什么類型錯誤 都可以接收
pass
else:
# 當被監測代碼沒有發生異常的時候,觸發的
pass
finally:
不管被監測的代碼有沒有出錯,都執行
pass
