Python中的“黑科技”:内省(Introspection)与反射(Reflection)


内省与反射对于编程语言来说,是非常重要的特性,对Python同样如此。如果灵活运营,可以大大提高我们对代码的掌控能力。今天,小编就来带大家看一看Python中的这两项“黑科技”。

Python中的“黑科技”:内省(Introspection)与反射(Reflection)

内省

内省,有时也叫类型内省,是在运行时进行的一种对象检测机制。我们可以通过内省来获取一个对象的所有信息,比如这个对象的类型,其中包含哪些属性等等。让我们来看两个例子:

例子1:dir()

dir()是内省机制中的一个重要内置函数。这个函数可以将一个对象的所有属性以字符串列表的形式返回。

Python中的“黑科技”:内省(Introspection)与反射(Reflection)

这段代码的输出为:

>>> ['__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__', 'foo', 'get_foo']

在这些属性当中,除了我们自己定义的“foo”和“get_foo”以外,其它的都是Python对象自带的属性。

例子2:类型检查

类型检查的方法有很多种,比如:

Python中的“黑科技”:内省(Introspection)与反射(Reflection)

注意,在使用isinstance()时有一个坑,那就是对于有继承关系的两个类,它的结果始终是True。

比如下面这两个类, logging.FileHandler 继承自 logging.StreamHandler 。尽管这两个类并不相同,但是isinstance()的结果是True。

Python中的“黑科技”:内省(Introspection)与反射(Reflection)

除了上面举的例子,Python中利用内省还能做很多事情。下面,我们用inspect模块来实现一个很二的功能:用一个装饰器来检测一个对象是类还是函数。

Python中的“黑科技”:内省(Introspection)与反射(Reflection)

反射

与内省相比,反射的功能要显得更为强大。反射使得程序具有在运行时动态修改自己的结构和行为的能力。继续来看几个例子:

例子1:动态设置属性

假设有一个空模块,现在我们想把所有的环境变量作为属性添加到这个模块中。这个文件env.py可以这样实现:

Python中的“黑科技”:内省(Introspection)与反射(Reflection)

import_module(__name__) 把当前模块作为一个对象返回, setattr() 将环境变量的key,value值作为属性添加到模块中去。

事实上, import_module(__name__) 也是利用里Python的反射能力。它根据输入的字符串参数生成了一个模块对象。

例子2:用getattr()动态获取属性值

在另一个文件output.py中,我们导入env.py,然后实现一个函数,获取其中的所有环境变量参数并以字典的形式返回:

Python中的“黑科技”:内省(Introspection)与反射(Reflection)

内置函数getattr()允许我们根据属性名来获取属性的值。

例子3:动态方法

下面小编要放大招了。我们要实现一个动态方法,当这个方法被调用时,它甚至都还没有被定义,但是仍然能够被成功调用。这是如何实现的呢?我们来看代码:

Python中的“黑科技”:内省(Introspection)与反射(Reflection)

这段代码看起来可能有点烧脑。总的来说,我们创建了一个GreetMe对象,并且依次调用其hello(),bye()和nice_to_meet_you()方法。然而,这三个方法在GreetMe类中均没有定义。

这里面的关键在于 __getattr__() 方法。在Python中,当一个没有被定义的方法被访问时, __getattr__() 就会被调用。后面的事情就靠大家自己去理解了。

好了,今天的“黑科技”就先讲到这里。感兴趣的小伙伴可以留言交流。

感谢大家的阅读!