浅谈 Java 和 Python 的反射

反射这个词我一直没搞懂,也不知道为什么需要反射,也不知道反射到底做了什么。所见所闻逐渐丰富之后,开始有点儿懂了。

先不管反射这个词是什么意思。Java 里面有反射,Python 里面也有反射,但是不太有人强调 Python 里面的反射,可能是因为 Python 是解释的语言,天然的容易获得运行时的类型信息。

C 语言是最贴近硬件的编程语言。C 语言编译到汇编以后,汇编只有指令,寄存器。根本不管什么 int, float, struct date。从汇编我们只知道用哪个寄存器,往哪个地址写东西,从哪个地址读东西,一次读也就最多读一个寄存器的大小,具体一点大概是64位或者32位。C 语言的程序里面的变量在运行的时候不知道他是什么类型,只在编译的时候知道一个变量占多少个字节。

Java 和 Python 都是有一个 VM 用来运行从源码编译到的字节码。Python 的 OOP 世界一切都是对象,变量,字面量是对象,类型也是对象。我们可以通过obj.attr的方式访问对象的属性,对于这种动态解释的语言来说,方法也是属性。在 Python 可以轻松获得一个对象的有关信息,包括它的类型。使用type()函数可以知道一个对象的类型。

>>> str
<class 'str'>
>>> type(str)
<class 'type'>
>>> type
<class 'type'>

一切皆对象,类也是对象,类是<class 'type'>的对象。str 这个类是 <class 'str'>,而 str 这个类的类是 type。好吧,很绕了。声明一个类就是声明了一种新的类型,类型也是对象,类型是 type 的对象。那么如果还要追究 type 是谁的对象,那目前我只能说就像盘古开天辟地,混沌初始一样,自这个世界开始,混沌就是这个世界开始的起点(如果你相信的话)。type 由 VM 建立,而 VM 就是我们造的混沌,我们也是盘古直接将 VM 需要的东西都建立了起来。

实际上,Python 的类的机制完全可以用 Python 的函数来实现1。用 class MyClass 这种语法声明一个类,完全可以当做是一个函数,加载/构造这个类的时候这个函数体被执行,然后函数体的本地变量都变成了这个新类方法和类的属性。这个类是通过type()构造的。而所有的类型的属性都可以从对象获得。

>>> str
<class 'str'>
>>> str.__name__
'str'
>>> 'Hello'.__class__
<class 'str'>
>>>

Python 的每个模块只会被 evaluate 一次。import 一个模块的时候模块内的代码被执行,模块内的 class 里的语句也被执行,每个 class 都是被 type 实例化出来的类型。

在 Python 的世界获取对象的类型特别简单,都在对象的属性里面了。不知不觉就已经用到了反射了,从一个对象获得它的类型,这就是反射做的事情。Python 的类的加载是执行类的定义,所有的类都是 type 的实例。而 Java 也有类似之处。

Java 所有的类都是 Class 这个类的实例,而所有的对象都有一个 class 属性,可以获取对象的类。而 Java 是加载完必要的类之后,用到类的时候才去装载类。Python 是 import 一个类,或者类被 type 制造出来的时候完成类的装载。装载或者加载一个类,制造出来类型的时候,类的代码被执行。

通过反射可以在运行时刻知道对象的类型信息。Java 可通过Class.forName()去加载一个类,Python 可以通过 import 类来加载类,加载类的时候类的代码被执行。加载完了,就有了新的类型。所以 MySQL 的 JDBC,可以用 Class.forName("com.mysql.cj.jdbc.Driver")加载类,执行类的代码。

posted @ 2022-11-06 17:41  wngtk  阅读(226)  评论(0编辑  收藏  举报