面向对象之魔术方法(内置方法),反射,异常之自定义异常

发布时间 2023-06-28 21:02:40作者: 毓见

魔术方法(内置方法)(面试题)

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

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


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

    def __str__(self):
        print("我执行了")
        # return None
        """__str__方法返回值必须是字符串类型"""
        # return "123"
        return "name:%s" % self.name
        # return 123

    def __repr__(self):
        return "name1:%s" % self.name
stu = Student("kevin", 19, 'male')

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

# 我们一般用的是__Str__方法

2. __del__方法

class Student():
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
        self.f = open("a.txt", "w", encoding="utf8")

    # 我执行了:
    # 1. 当删除对象的时候,会自动触发函数的执行
    # 2. 当程序结束的时候,也会自动触发执行
    def __del__(self):
        print("我执行了")
        """可以做一些清理垃圾的操作"""
        self.f.close()
        #  # close() 方法用于关闭一个已打开的文件
        # 关闭后的文件不能再进行读写操作,否则会触发 ValueError 错误。
        # close() 方法允许调用多次。
stu = Student("kevin", 19, 'male')

# del stu

print("123")

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

class People():
    pass

class Student(People):
    pass


# stu = Student()
# print(isinstance(stu, Student))  # True
# print(isinstance("hellowrold", str))


# res = 'helloworld'  # <class 'str'>
# # res1 = int
#
# print(type(res))
#
# # res = str('helloworld')

print(issubclass(Student, People))

4. __doc__方法


class Foo:
    """
    author:kevin
    date:2023-01-01
    email:liyangqit@163.com
    这是注释"""
    pass


class Bar(Foo):
    """这是Bar"""
    pass
# document:可以查看出类内部的详细信息,其实就是注释里面的内容
# print(Foo.__doc__)
print(Bar.__doc__)  # 这个特性不能够继承到父类

5. __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('=====>执行代码块')
    print('=====>执行代码块')
    print('=====>执行代码块')
    print('=====>执行代码块')
    print('=====>执行代码块')

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 Tr

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

print('0'*100) #------------------------------->不会执行

5. 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) #------------------------------->不会执行

面试题:探探你对with上下文管理协议的理解?

1.with可以自动打开文件和关闭文件

2.with创建上下文管理器,只要出现with语句,他就会自动的触发with后面的那个对象的类里面的enter和 exit ,那enter什么时候触发呢?那就是出现with语句的时候,会自动触发enter的函数,enter里面的返回值返回什么就会给with语句后面的as变量

3. 当触发enter语句之后,就会执行我with代码块,当with代码块执行完之后就会执行另外一个方法叫exit的方法,然后关闭文件的时候,可以在exit里面做一些关闭的操作

4.如果我们在with代码块里面出现了异常信息,那我们可以在里面可以查看到一下信息,比如:异常类型,异常值,和追溯信息等,如果在exit里面直接返回Tuer,
那在with代码块里面抛出异常的时候,相当于没有发生一样

5.setattr,delattr,__getattr__方法

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')
        # print(key, value)  # z 1
        # self.z = 1
        # 你使用点语法,设置一个不存在的属性值就会自动触发__setattr__

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

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

obj = Foo(10)
obj.z

# obj.z = 1  # ----> from setattr
# print(obj.z)  # None

del obj.z


__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()
# 123
print(obj())  # 对象加括号  # __call__

反射

# 反射其实就是通过字符串的形式来操作对象的属性
stu.z = 1
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')]
# stu.name

getattr() setattr() delattr() hasattr()

1. getattr()

# res=getattr(stu, 'name') # attribute 属性 attr  # jason
# res1=getattr(stu, 'age1', 666) # attribute 属性 attr  # jason
# res1=getattr(stu, 'age1', 666) # attribute 属性 attr  # jason
# print(res)
# print(res1)


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

2. setattr()

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

3. delattr()

 delattr(stu, 'name')
 print(stu.__dict__)

4. hasattr()

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

补充

# import time
# time.sleep(3)

# res=getattr(time, 'sleep') # built-in
# print(res)
# res(3)  # time.sleep(3)

# getattr(time, 'sleep')(3)


# import time
# time = __import__("time")  # 以字符串的形式导入模块
# time.sleep(3)


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

反射的案例

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. 如何捕捉异常

try:
    被检测的代码
except 异常类型:
    pass
else:
    print()
finally:
    print()
    
 """以上结构是我们为了捕捉代码中出现的异常"""

2. 我们自己如何抛出异常:raise

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

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

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

3. 自定义异常

class MyException(BaseException):
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return self.msg


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