魔术方法(内置方法)- 反射(4个方法) - 异常部分内容

一、魔术方法(内置方法)

'''
魔术方法(内置方法):
    类里面内置的双下划线开头的一些方法,它们具有特殊的功能,称之为魔术方法,简称魔法
    比如:__init__

    魔术方法的学习需要掌握每个方法什么时候触发或者执行
    __str__,__repr__方法
    __del__方法
    isinstance(obj,cls)和issubclass(sub,super)
        isinstance(obj,cls)检查是否obj是否是类 cls 的对象
        issubclass(sub, super)检查sub类是否是 super 类的派生类
    __doc__
    __enter__和__exit__
    __setattr__,__delattr__,__getattr__
    __setitem__,__getitem,__delitem__
    __call__

'''

1. __str__和__repr__方法

'''
"""
	1. 打印对象的时候会自动触发这两个方法
	2. 如果有返回值,类型必须是字符串形式的
	3. 如果有返回值,那么,打印的结果就是它的返回值
	4. 如果这两个方法同时存在,优先使用__str__方法,__str__的优先级高
	5. print打印会执行这两个任意一个,str()会执行__str__, repr()会执行__repr__
"""
    __str__方法会在对象被打印时自动触发,print功能打印的就是它的返回值,
    我们通常基于方法来定制对象的打印信息,该方法必须返回字符串类型
'''


class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return '<Name:%s Age:%s>' % (self.name, self.age)  # 返回类型必须是字符串


p = People('lili', 18)
print(p)  # 触发p.__str__(),拿到返回值后进行  <Name:lili Age:18>


class School:
    def __init__(self, name, addr, type):
        self.name = name
        self.addr = addr
        self.type = type

    def __repr__(self):
        return 'School(%s,%s)' % (self.name, self.addr)

    def __str__(self):
        return '(%s,%s)' % (self.name, self.addr)


s1 = School('oldboy1', '北京', '私立')
print('from repr: ', repr(s1))  # from repr:  School(oldboy1,北京)
print('from str: ', str(s1))  # from str:  (oldboy1,北京)
print(s1)  # (oldboy1,北京)

'''
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常
'''

2. __del__方法

'''

"""
	1. 当删除对象的时候,会自动触发
	2. 当程序执行结束的时候也会触发方法的执行
	3. 它的作用一般用来清理数据
"""
    __del__会在对象被删除时自动触发。由于Python自带的垃圾回收机制会自动清理Python程序的资源,
    所以当一个对象只占用应用程序级资源时,完全没必要为对象定制__del__方法,
    但在产生一个对象的同时涉及到申请系统资源(比如系统打开的文件、网络连接等)的情况下,
    关于系统资源的回收,Python的垃圾回收机制便派不上用场了,需要我们为对象定制该方法,
    用来在对象被删除时自动触发回收系统资源的操作
'''
from sqlite3 import connect


class MySQL:
    def __init__(self, ip, port):
        self.conn = connect(ip, port)  # 伪代码,发起网络连接,需要占用系统资源

    def __del__(self):
        self.conn.close()  # 关闭网络连接,回收系统资源


obj = MySQL('127.0.0.1', 3306)  # 在对象obj被删除时,自动触发obj.__del__()


3. isinstance(obj,cls)和issubclass(sub,super)

'''
    isinstance(obj,cls)检查是否obj是否是类 cls 的对象
'''


class Foo(object):
    pass


obj = Foo()

print(isinstance(obj, Foo))  # True


'''
issubclass(sub, super)检查sub类是否是 super 类的派生类
'''


class Foo(object):
    pass


class Bar(Foo):
    pass


print(issubclass(Bar, Foo))  # True

4. doc

它是查看类内部的详细信息,类内部的注释内容
class Foo:
    '我是描述信息'
    pass


print(Foo.__doc__)  # 我是描述信息

---------------------继承-----------------------------
class Foo:
    '我是描述信息'
    pass


class Bar(Foo):
    pass


print(Bar.__doc__)  # 该属性无法继承给子类  故输出结果:None

5. enter__和__exit

"""
	1. 当出现with语句的时候,会触发__enter__方法
	2. 如果__enter__方法中有返回值,则就赋值给as后面的变量名
	3. 开始执行with代码块,当with代码块执行完毕之后,在执行__exit__方法
	4. with代码块中出现了异常,则在__exit__方法中会拿到异常的信息(异常类型、异常值、追溯信息)
	5. 如果在__exit__方法中return True,忽略异常,相当于什么都没发生
	举例: with打开文件
"""

'''在操作文件对象的时候可以这么写'''

with open('a.txt') as f:
    '代码块'

'''
    上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,
    必须在这个对象的类中声明__enter__和__exit__方法
'''


class Open:
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
        # return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')


with Open('a.txt') as f:
    print('=====>执行代码块')
    # print(f, f.name)


'''
    __exit__()中的三个参数分别代表异常类型,异常值和追溯信息,
    with语句中代码块出现异常,则with后的代码都无法执行
'''


class Open:
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')
        print(exc_type)
        print(exc_val)
        print(exc_tb)


with Open('a.txt') as f:
    print('=====>执行代码块')
    raise AttributeError('***着火啦,救火啊***')
print('0' * 100)  # ------->不会执行


'''
    如果__exit()返回值为True,那么异常会被清空,
    就好像啥都没发生一样,with后的语句正常执行
'''


class Open:
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('with中代码块执行完毕时执行我啊')
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        return True


with Open('a.txt') as f:
    print('=====>执行代码块')
    raise AttributeError('***着火啦,救火啊***')
print('0' * 100)  # -------->会执行


6. setattr,delattr,getattr

"""
	前提:必须是使用点语法(.) obj.x
	__getattr__: 获取一个不存在的属性名的时候,会自动触发__getattr__的执行,并且有个参数:属性名
	__setattr__:设置一个不存在的属性的时候,会自动触发__setattr__的执行,并且有两个参数:key,value, self.__dict__[key] = value =====> self.key = value=====> 无限递归
	__delattr__:删除一个属性的时候,触发的函数
"""

class Foo:
    x = 1

    def __init__(self, y):
        self.y = y

    def __getattr__(self, item):
        print('----> from getattr:你找的属性不存在')

    def __setattr__(self, key, value):
        print('----> from setattr')
        # self.key=value #这就无限递归了,好好想想
        # self.__dict__[key]=value #应该使用它

    def __delattr__(self, item):
        print('----> from delattr')
        # del self.item #无限递归了
        self.__dict__.pop(item)


''' __setattr__添加/修改属性会触发它的执行'''
f1 = Foo(10)
print(f1.__dict__)  
'''这句打印是因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,
就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值'''

f1.z = 3
print(f1.__dict__)
'''__delattr__删除属性的时候会触发'''

f1.__dict__['a'] = 3   
'''这句赋值是因为我们可以直接修改属性字典,来完成添加/修改属性的操作'''

del f1.a
print(f1.__dict__)

'''__getattr__只有在使用点调用属性且属性不存在的时候才会触发'''
f1.xxxxxx

7. setitemgetitemdelitem

"""
	前提:必须是使用中括号([]) obj['x']
	__getitem__: 获取一个不存在的属性名的时候,会自动触发__getitem__的执行,并且有个参数:属性名
	__setitem__:设置一个不存在的属性的时候,会自动触发__setitem__的执行,并且有两个参数:key,value, self.__dict__[key] = value =====> self.key = value=====> 无限递归
	__delitem__:删除一个属性的时候,触发的函数
"""

给你一个字典,字典通过key取值,中括号的形式,不支持句点符,所以,现在想让字典支持点取值
d = {"a":1}
d['a']
d.a


class C(dict):
    def __getattr__(self, item):
        return self.__dict__[item]
    
obj = C()
obj.a


class Foo:
    def __init__(self, name):
        self.name = name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __delitem__(self, key):
        print('del obj[key]时,我执行')
        self.__dict__.pop(key)

    def __delattr__(self, item):
        print('del obj.key时,我执行')
        self.__dict__.pop(item)


f1 = Foo('sb')
f1['age'] = 18
f1['age1'] = 19
del f1.age1  # del obj.key时,我执行
del f1['age']  # del obj[key]时,我执行
f1['name'] = 'alex'
print(f1.__dict__)  # {'name': 'alex'}

8.call

"""
	对象加括号会自动触发__call__的执行,如果有返回值,就给到了对象加括号的位置
"""

class Foo:

    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):
        print('__call__')


obj = Foo()  # 执行 __init__
obj()  # 执行 __call__ 输出:__call__

Foo()()  # __call__


二、反射

'''
    反射其实就是通过字符串的形式来操作对象的属性
'''


class Student:
    school = 'SH'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def index(self):
        print('Student.index')


stu = Student('jason', 20)
# print(stu.name)  # jason
# stu.z = 1
# print(stu.z)  # 1

"""getattr()  setattr()  delattr()  hasattr()"""
1.getattr()
res = getattr(stu, 'name')
# print(res)  # jason

# 可设置默认值,若没有这个属性,则打印默认值
res1 = getattr(stu, 'age1', '没有age1')
# print(res1)  # 没有age1

res2 = getattr(stu, 'index')  # index函数的内存地址
# print(res2)


2.setattr()
setattr(stu, 'x', 1)
setattr(stu, 'name', '666')  # 如果属性名存在就是修改,不存在就是增加
print(stu.__dict__)  # {'name': '666', 'age': 20, 'x': 1}

3.delattr()
delattr(stu, 'name')
# print(stu.__dict__)  # {'age': 20}

4.hasattr()
print(hasattr(stu, 'index'))  # True 返回布尔值,只是一个判断是否存在

案例

#  基于反射可以十分灵活地操作对象的属性,比如将用户交互的结果反射到具体的功能执行
class FtpServer:
    def serve_forever(self):
        while True:
            inp = input('input your cmd>>: ').strip()
            cmd, file = inp.split()
            if hasattr(self, cmd):  # 根据用户输入的cmd,判断对象self有无对应的方法属性
                func = getattr(self, cmd)  # 根据字符串cmd,获取对象self对应的方法属性
                func(file)

    def get(self, file):
        print('Downloading %s...' % file)

    def put(self, file):
        print('Uploading %s...' % file)


server = FtpServer()
server.serve_forever()

三、异常补充

'''
1.异常就是错误发生的信息,必须要做处理,否则,后续代码无法正常运行

2.如何捕获异常
try:
    # 被监测代码
    pass
except 异常类型:
    pass
else:
    pass
finally:
    pass

3.如何抛出异常
import abc


class Animal:
    @abc.abstractmethod
    def speak(self):
        raise Exception('请先实现Animal中的speak方法')


class People(Animal):
    def speak(self):
        pass

"""主动抛出异常"""
stu = People()
stu.speak()


4.自定义异常
class MyException(BaseException):
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return self.msg


raise MyException('这是异常信息')
'''

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值