这篇文章在类的继承基础上进一步分析Python和Scala是如何处理类和对象,实现一个纯的面向对象的语言。Python拥有很优秀的REPL,可以很方便的深入到Python的实现,体会Python在动态语言简单的表面下隐藏着的复杂性,而Scala作为一门静态语言,它的继承关系反倒会相对比较好分析。从相对简单的Scala的继承关系开始吧。 Scala:
下面分析参考《Programming In Scala》
Scala的每个类都继承自Any类,在Any中定义的方法在所有类都可以使用,例如toString方法。
Any类的方法有==,!=,equals,##,hashCode,toString,其中==和equals牵扯到对象相等性的概念,后面详述。
继承Any类的子类是AnyVal和AnyRef。AnyVal是Scala所有值类的父类,例如Int,Char,Float等值类,值类之间是没有子类关系的,不同的值类可以互相隐性转换,高精度数值不可以转换为低精度,例如Int可以隐性转换为Double。
scala> 1+1.0
res5: Double = 2.0不能通过new关键字来创建值类否则就会报错。Unit类前面提到过,用来作为不返回结果的方法的结果类型,有且仅有一个实例()。
scala> new Float
<console>:8: error: class Float is abstract; cannot be instantiated
new FloatAnyRef是所有引用类的父类,例如来自Java的类,List,String,自定义Scala类等类,是java.lang.object类的别名。
除了继承关系外,Scala的数值类型一般情况下都是直接映射在内存上,而需要的时候,会调用相应的类操作,例如Int在使用toString操作的是java.lang.Integer类(自动装箱)。这一点与Python使用名字空间的方式截然不同。
除了值类和引用类之外还存在一种特殊的类,被称为底类型。有两种底类型,分别是scala.Null和scala.Nothing。Null是每个引用类的子类,对应的是null值,而Nothing是每个其它类型的子类,主要是用于给出非正常终止的信号。
Python:
Python的继承关系可以用一句话说明:object是所有类的元类,所有对象都是type的实例。
注:__class__方法返回实例的对应类,__bases__方法返回继承的基类
先分析type和object的关系:
>>> object.__class__
<class 'type'>
>>> type.__class__
<class 'type'>object和type都是type类的实例
>>> type.__bases__
(<class 'object'>,)
>>> object.__bases__
()type的元类是object,object本身就是元类
>>> list.__bases__
(<class 'object'>,)
>>> list.__class__
<class 'type'>内置类型list的父类是object,是type类的实例。
>>> lst = [1,2,3]
>>> lst.__class__
<class 'list'>lst是list类的实例,当创建内置类型时,创建的是内置类型对应的类的实例
>>> class A:
... pass
...
>>> A.__class__
<class 'type'>
>>> A.__bases__
(<class 'object'>,)我们创建一个自定义类A,它是type类的实例,继承自object类
>>> A().__class__
<class '__main__.A'>A()是A的实例。
有了上面的分析,可以用这么一张图来说明Python的继承关系,虚线代表着实例,实线代表着子类。type和object类似于鸡和蛋的关系,但是要注意到Python是一门C写成的语言,抛开Python本身的语法,type和object在Python初始化的时候便作为结构体已经分配好存储空间,真正使用时只需要相互引用即可。
引用知乎https://www.zhihu.com/question/30301819/answer/47539