对象的组合、魔术、反射、异常

发布于 2022年 01月 12日 09:43

今日内容概要

  • 组合
  • 面向对象的内置函数(魔术方法、魔法)
  • 反射
  • 异常

内容详细

组合

# 什么是组合
	就是一个对象拥有一个属性
    但是该属性的值 是另外一个对象
    
# 继承
	其实就可以描述为:
        满足什么是什么的关系 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
         

推荐文章