introspection有什么用处?

16

我主要使用PHP进行编程,现在正试图转向Python。我熟练掌握PHP,并且从未需要使用内省/反射等功能。那么代码内省有什么好处,在什么情况下会变得无可替代呢?

以下是我认为代码内省有用的唯一方式:

从我在“深入Python”的例子中看到的,内省基本上意味着您可以列出对象的所有函数和属性。对我来说,内省就像一个对象的“用户手册”。它允许您从python shell查看对象及其功能。

我只是不知道为什么或在什么情况下,您会对任意对象进行内省,并做出有用的事情。

4个回答

14

假设你有一个自定义对象,你想知道该对象是否具有某些属性或某个方法,那么可以使用内省函数(例如hasattr)来查找。

就像《Dive into Python》一书中已经说明的那样,如果您正在构建带有自动完成功能的GUI编辑器,您想要在运行时获取可调用的对象的公共方法,则可以使用内省方法,例如通过dir获得每个方法的getattr,并检查它是否是可调用的,然后将其显示在您的自动完成列表中。


嗨。谢谢你的回复。有一件事让我感到困惑,也许你期望(并已编写代码反映了这种期望),如果一个对象想要获取用户的ID,这将通过名为“getUserID()”的函数完成。在您的代码中,您会检查并寻找名为getUserID的函数。好吧,也许程序员更喜欢给他的函数起一个“不同”的名称,比如叫做“retrieve_the_user_identification_integer()”或者其他奇怪的名称。这就是我对即时内省感到困惑的原因。看起来你做了很多假设。 - Chris D.
其实,你的疑问很好。通常情况下,你不会对自己或类创建的对象进行内省,因为你已经知道某些东西存在!现在,考虑一下当对象被给定给你并且你不知道太多关于它们的信息时,内省就显得尤为重要。一个很好的例子是,你编写了一个带有自动完成功能的GUI编辑器,我使用该编辑器并创建了一个自定义模块和对象。当我尝试自动完成我编写的对象时,你的编辑器应该给我可能函数的列表。你的编辑器如何知道?通过内省我的对象。希望对你有所帮助。 - Senthil Kumaran
2
这里涉及到“鸭子类型”的概念。如果一个对象有一个write()方法,Python将很乐意让你在任何你想写文件的地方使用它——无论它是否派生自file类。(这与其他一些语言非常不同!)因此,如果你要写入一个文件,你可以先试试看是否会出现异常,或者你可以先使用hasattr()检查它是否有一个write()方法。通常的Python习惯用法实际上是先尝试并捕获异常,但有些情况下“三思而后行”也很有用。 - kindall
为了强调@kindall所说的:在Python中,"方法调用类型检查",又称为“尝试方法,而不是检查类型”的类型检查,经常用于代替内省。请注意,一些疯狂的人 :) 将其称为“鸭子类型”,在我看来这是一个相当荒谬和晦涩的术语。请参阅链接以阅读我对这是什么意思的描述。 - Gabriel Staples

4

我在实际项目中使用introspection的一个例子:

我们有一个名为TaskService的管理后台任务的服务。每个任务实际上都是实现了给定接口的Start()和Stop()方法的类。我们有一个配置文件,将每个任务与其类匹配。所以运行TaskService时,它只是浏览配置文件,并对于每个任务获取类的名称,并通过reflection(introspection是reflection的一个子部分)在运行时实例化。

另一个introspection可能有用的示例是在编程语言中使用注释。注释用于向其他第三方程序(如ORMs)提供关于您的类的元信息,例如您可以使用注释来告诉某个类是否为实体类(这在Java中是正确的,但Python不支持),或关于某些属性的关联类型等。

代码补全是introspection有用性的另一个例子。

顺便说一下,正如你提到的,introspection在程序文档工具方面非常有帮助。


2
我编写了一款文档验证器,可以对PDF文件运行测试以检查其中的各种问题。这些测试是特殊类的方法,这些类代表Subversion分支、产品、手册和各种类型的任意分组。验证器引擎使用内省来查找这些特殊类、实例化它们并运行它们的方法。
我本可以编写一个需要编写样板代码来实例化每个类、调用每个方法等的验证器。但这样做会重复自己,并且容易出现维护问题(在这种情况下添加/删除测试时未能同时更新两个位置)。通过利用您希望将同一操作应用于所有特殊类的事实,计算机可以为您执行样板工作,并且不会犯错误。这样,您只需在一个地方声明文档的结构。

1
有点晚了,但另一个内省的例子是使用Active Record(一种将对象映射到数据库表的Ruby库)。 Active Record使用内省来查看类的名称,确定关联的表,并定义方法以访问对象属性,从数据库模式中推断它们的名称。它在运行时读取模式(元编程和内省在此处发挥作用)。因此,例如,如果您有一个名为Person的类,则不必编写访问器方法,例如nameemail。只要与相同名称的列(在本例中为nameemail)存在于关联表中(在本例中为people),Active Record就会在运行时为这些同名属性定义访问器方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接