Python学习 面向对象编程进阶(反射、内置方法)

41 阅读4分钟

一、面向对象编程之反射

python是动态语言,而反射机制被视为动态语言的关键。

(一)基本概念

反射机制:

反射是一种“能力”,指的是在程序的运行状态中,对于任意一个类,都可以知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意方法和属性。即在程序运行过程中,可以"动态"获取对象的信息,调用属性或方法。

那么反射有什么作用呢?

当我们想要查看对象拥有的属性时,使用的是__dict__方法,不过对象使用这个方法取不到类的属性,只能取到对象专属于自己的属性。而通过dir()方法,就可以获取到对象的所有属性,其中也包括类的属性和一系列内置属性。

class test:
    x = 1
    y = 2

    def z(self):
        return self.x + self.y


obj = test()
print(obj.__dict__)
# {}
print(dir(obj))
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'x', 'y', 'z']

这样的话,我们得到的就是一系列字符串格式的属性和方法,但并不能使用(在某些情况下,我们是要让用户使用到其中的某些方法的,即程序自动获取,自动调用或者用户触发调用),所以python给我们提供了反射

(二)实现反射

反射是通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

反射四大函数(通过字符串来操作属性值)

class test:
    x = 1
    y = 2

    def __init__(self, m, n):
        self.m = m
        self.n = n

    def z(self):
        return self.x + self.y


obj = test(3, 4)
  1. hasattr():判断某个属性是否存在
    print(hasattr(obj, 'x'))  # True
    print(hasattr(obj, 'z'))  # True
    print(hasattr(obj, 'n'))  # True
    print(hasattr(obj, '混入其中'))  # False
    
  2. getattr():获取某个属性的值
    print(getattr(obj, 'x'))  # 1
    print(getattr(obj, 'z'))  # <bound method test.z of <__main__.test object at 0x0000014B51775640>>
    print(getattr(obj, 'n'))  # 4
    
    print(getattr(obj, '混入其中'))  # 报错,找不到就报错
    
    # 我们可以添加第三个参数来设置找不到时的返回值
    print(getattr(obj, '混入其中', None))  # None
    
  3. setattr():设置某个属性(有则更改,无则创建)
    setattr(obj, 'x', 100)  # obj.x = 100
    print(obj.x)  # 100
    setattr(obj, 'name', '山炮')
    print(obj.name)  # 山炮
    
  4. delattr():删除某个属性
    print(obj.m)  # 3
    delattr(obj, 'm')
    print(obj.m)  # 报错,找不到
    
注意:在python中一切皆对象,所以反射四大方法也适用于一切对象。

在这里插入图片描述

当不确定对象有没有某些方法时,可以先进行判断,再进行操作,这样子会避免报错。

x = 10
# print(x.__dict__)  # 报错:'int' object has no attribute '__dict__'
print(getattr(x, '__dict__', None))  # None
obj = 10
if hasattr(obj, '__dict__'):
    print(getattr(obj, '__dict__'))
else:
    pass

# 无事发生

还有些类型是不被允许再添加属性进去的:

x = 10
setattr(x, '混入其中', 'niub')  # 'int' object has no attribute '混入其中'

反射应用小案例

class QQ:
    def put(self):
        print('正在发消息')

    def get(self):
        print('正在收消息')

    def interactive(self):
        method = input(">>>: ").strip()  # method接收的是一个字符串类型

        if hasattr(self, method):
            getattr(self, method)()
        else:
            print('输入的指令不存在')


obj = QQ()
obj.interactive()

二、面向对象编程之内置方法

(一)基本概念

  1. 什么是内置方法?

    定义在类内部,以__开头并以__结尾的方法。

    特点: 会在某种情况下自动触发执行

  2. 为何要用内置方法?

    为了来帮助使用者高度定制自己的类或对象。

(二)如何使用内置方法

__str____del__为例

__str__:在打印对象时自动触发,然后将返回值(==必须是字符串类型==)当做本次打印的结果输出,print功能打印的就是它的返回值。
# 未使用__str__
class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age


obj = People('山炮', 18)
print(obj)  # <__main__.People object at 0x0000020ADA933310>
# 使用__str__
class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return "<姓名:%s | 年龄:%s>" % (self.name, self.age)


obj = People('山炮', 18)
print(obj)  # <姓名:山炮 | 年龄:18>
__del__会在对象被删除时自动触发,先执行该方法,再清理对象。
class test:
    def __del__(self):
        print('清理中...')


obj = test()
# 结果:清理中...

# 当程序只有上面这么多时,程序运行结束后,自动输出了“清理中...”是因为在python程序空间释放时(清理对象),该方法先于清理对象执行。

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

举个例子:

class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.x = open('a.txt', mode='w')
        # self.x =》 占据的是操作系统资源

    def __del__(self):
        # 发起系统调用,告诉操作系统回收相关的系统资源
        self.x.close()


obj = People('山炮', 18)