Python高阶基础之魔术方法、反射、异常

发布时间 2023-06-28 20:47:27作者: Way*yy

魔术方法(内置方法)

# 类里面内置的双下划线开头的一些方法,他们具有特殊的功能,我们称之为魔术方法:简称魔术

"""魔术方法的学习只需要掌握每个方法什么时候触发或者执行就行了"""
1、__str__,__repr__方法

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

    def __str__(self):
        print('这是__str__')
        # """__str__方法返回值必须是字符串类型"""
        return 'name'

    def __repr__(self):
        print('__repr__')
        return 'repr'


stu = Student('kevin', 18)
"""也就是说,__str__方法内部返回什么结果,打印的就是返回的结果,"""
print(stu)  # 当打印或者输出对象的时候,会自动触发__str__的执行
# 这是__str__
# name
print(str(stu))
# 这是__str__
# name
print(repr(stu))
# __repr__
# repr
"""__repr__:它的功能和__str__一样,只不过,只写了他们两个其中之一,都会执行,但是,如果两个都写了,__str__它的优先级高于_repr__"""

# 我们一般用的是__Str__方法

2、__del__方法:
class Student:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # 1. 当删除对象的时候,会自动触发函数的执行
    # 2. 当程序结束的时候,也会自动触发执行
    def __del__(self):
        print('这是__del__')


stu = Student('kevin', 18)
print(stu.name)  # kevin
print(stu.age)  # 18
# 这是__del__
# 执行删除对象操作
del stu
# 这时候在打印stu对象就会报错了,报错信息为,没有找到stu这个名字,说明这个对象已经被删除掉了
# print(stu) # NameError: name 'stu' is not defined

"""__del__函数会在代码都走完以后再走__del__函数体内的代码"""
isinstance(obj,cla) and issubclass(sub,suoer) 使用方法

isinstance(obj,cla):
    """判断object是不是由这了class产生的,是的话返回True,不是的话返回False"""
    class A:
      pass


    class B(A):
        pass


    a = A()
    b = B()
    print(isinstance(b, B))  # True
    print(isinstance(a, B))  # False
    """它还可以用来判断一些数据类型"""
    print(isinstance('hello', str))  # True
    print(isinstance('hello', list))  # False
    
issubclass(sub,super):
    """判断一个class是否继承了;另一个class"""
    class A:
    	pass
    class B(A):
        pass
    print(issubclass(B, A)) # True
    '判断B是否继承了A的类,返回的也是布尔值'
    
__doc__方法:
    """查看对这个class的一些解释说明信息,不能查看到注释信息"""
    class Foo:
    """
    author:kevin
    date:2023-01-01
    email:liyangqit@163.com
    这是注释"""

    def __init__(self):
        """这是初始化表对象"""
        pass


    class Bar(Foo):
        # """这是Bar"""
        pass


    print(Foo.__doc__)
    #  author:kevin
    #  date:2023-01-01
    #  mail:liyangqit@163.com
    #  这是注释

    print(Bar.__doc__)  # 这个特性不能够继承到父类
    """如果没有对这个class的解释说明就会返回None,如果有就会打印出来"""

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

    def __enter__(self):
        print('代码走到了__enter__这里')
        return '__enter__'

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('代码走到了__exit__这里')


with Open('a.txt') as f:
    print('代码走到了with open 这里')

print(f)
# 执行结果
# 代码走到了__enter__这里
# 代码走到了with open 这里
# 代码走到了__exit__这里
# __enter__
"""如果出现了with语句,就会立马触发__enter__的方法,如果有返回值就会把返回值赋给as后面的变量,
然后再执行with Open 的代码块,最后执行__exit__的代码块"""

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

        def __enter__(self):
            print('代码走到了__enter__这里')
            return '__enter__'

        def __exit__(self, exc_type, exc_val, exc_tb):
            print('代码走到了__exit__这里')
            print(exc_type)  # <class 'Exception'> 异常类型
            print(exc_val)  # 出现了错误 异常信息
            print(exc_tb)  # <traceback object at 0x000001DAB3D727C0> 追溯信息
            # 如果我在这个地方return一个True就算下面出现了报错,代码还是会继续往下走,会直接忽略掉这个错误信息
            return True


with Open('a.txt') as f:
    print('代码走到了with open 这里')
    raise Exception('出现了错误')

print('*' * 50)
# 未使用return
"""
    Traceback (most recent call last):
      File "D:\Program Files\Pycharm\pythonProject\import\exercise.py", line 2641, in <module>raise Exception('出现了错误')
    Exception: 出现了错误
    代码走到了__enter__这里
    代码走到了with open 这里
    代码走到了__exit__这里
    <class 'Exception'>
    出现了错误
    <traceback object at 0x000002448CDE2700>

"""
# return 后
"""
    代码走到了__enter__这里
    代码走到了with open 这里
    代码走到了__exit__这里
    <class 'Exception'>
    出现了错误
    <traceback object at 0x0000029D11AC77C0>
    **************************************************
"""
# return后代码就不会报错并且一直往下走

__setattr__,__delatter__,__getatter__

class Foo:
    x = 1

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

    def __getattr__(self, item):
        print('这是__getattr')

    def __setattr__(self, key, value):
        # print(key, value)  # z 1
        # self.z = 1
        # 你使用点语法,设置一个不存在的属性值就会自动触发__setattr__

        # 错误使用
        # self.key=value # 这就无限递归了,你好好想想
        # 正确使用
        self.__dict__[key] = value
        # self.__dict__[key]=value #应该使用它
        # super(Foo, self).__setattr__()
        print('这是__setattr__')

    def __delattr__(self, item):
        print('这是__delattr__')
        # 错误使用
        # # del self.item #无限递归了
        # 正确使用
        self.__dict__.pop(item)


foo = Foo(10)
print(foo.y)

foo.z = 1
print(foo.z)  # 1

del foo.z
print(foo.z)

# 如果不调用self.__dict__[key] = value方法,就看不到值
"""
    这是__setattr__
    这是__getattr
    None
    这是__setattr__
    这是__getattr
    None
"""

# 调用self.__dict__[key] = value方法后
"""
    这是__setattr__
    10
    这是__setattr__
    1

"""

# 使用删除方法后
"""
    这是__setattr__
    10
    这是__setattr__
    1
    这是__delattr__
    这是__getattr
    None
"""

__setitem__,__getitem,__delitem__
class Foo(object):
    def __init__(self, name):
        self.name = name

    def __getitem__(self, item):
        print(item)
        print("我执行了")
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        print("我也执行了")
        print(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)


obj = Foo('kevin')

# obj['name']

obj['age'] = 19
print(obj['age'])

del obj['age']
__call__
class Foo:
    def __init__(self):
        pass

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


obj = Foo()
print(obj.__call__())
# __call__
# 123
"""对象加括号时会调用__call__的函数体"""

反射

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

搭配的四种方法:
	"""getattr()  setattr()  delattr()  hasattr()"""
    
   	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')]
# print(stu.name)  # jason
"""这时候的name是str形式吗?很显然不是,那么我们要怎么做通过str形式来操作对象属性呢?"""
"""getattr()  setattr()  delattr()  hasattr()"""
# 1、getattr()
res = getattr(stu, 'name')
print(res)  # jason
'这时候的‘name’就是str形式了,可以看出来我们还是可以查看到对应的属性值'
res1 = getattr(stu, 'age', 666)
print(res1)
res2 = getattr(stu, 'age1', 666)
print(res2)
'如果查找的属性值存在就会得到对应的属性值,如果查找的属性值不存在就会新创建一个'
# jason
# 20
# 666

# 2、setattr()
setattr(stu, 'x', 66)
setattr(stu, 'name', 666)
print(stu.__dict__)  # {'name': 666, 'age': 20, 'x': 66}
"""如果值存在就修改,不存在就添加"""

# 3、delattr()
delattr(stu, 'x')
print(stu.__dict__)  # {'name': 666, 'age': 20}
"删除属性"

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

"补充"
import time

# time.sleep(3)

s = getattr(time, 'sleep')
print(s)  # <built-in function sleep>
# 形式一
s(3)  # 现在这个s具备了与sleep相同的功能了 time.sleep(3)
# 形式二
getattr(time, 'sleep')(3)  # 这几种写法功能相等

time = __import__('time')  # 以字符串的形式导入模块
# 这个地方的sleep遇到自己打出来pycharm不会再提示了
time.sleep(3)

random = __import__("random")
res = random.randint(0, 9)
print(res)  # 3

反射的案例

class FtpServer:
    def serve_forever(self):
        while True:
            inp = input('input your cmd>>: ').strip()  #  get a.txt  put a.txt
            cmd, file = inp.split()  # get a.txt  ['get', 'a.txt']

            #  hasattr(self, 'get')
            #  hasattr(self, 'put')
            if hasattr(self, cmd):  # 根据用户输入的cmd,判断对象self有无对应的方法属性

                # getattr(self, ’get‘) get或者put的内存地址
                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:
    被检测的代码
except 异常类型:
    pass
else:
    print()
finally:
    print()
    
 """以上结构是我们为了捕捉代码中出现的异常"""
3、自己抛出异常
class A:
    def speak(self):
        raise Exception('请先实现speak方法')


class B(A):
    pass


b = B()
b.speak()
# 报错信息
"""
    raise Exception('请先实现speak方法')
    Exception: 请先实现speak方法

"""
4、自定义异常
必传参数'BaseException'
class MyException(BaseException):
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return self.msg


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