在Ruby或Python中,类的概念可以重写吗?
这是我第一次在Stack Overflow发帖。
我想了解一下Ruby或Python的一些元编程特性,但首先我需要知道这些特性能让我在多大程度上扩展语言。最重要的是,我想重新定义一下类的概念。这并不是说我想在运行时重写某个特定的类,而是我想创造出我自己对类的理解。更具体一点,我想做一些类似于人们通常称之为类的东西,但我想遵循一种“开放世界”的假设。在正常类的“封闭世界”中,如果我声明贵宾犬是狗的子类,而狗又是动物的子类,那么我就知道贵宾犬不会同时是毛皮外套的类型。然而,在开放世界的类中,我定义的贵宾犬对象可能是也可能不是毛皮外套的对象,直到我解释说我可以穿上贵宾犬为止。(可怜的贵宾犬。)这一切都与我正在进行的关于OWL本体的研究有关。
顺便说一下,我已经尝试在网上寻找信息,但由于术语太多,我没有找到任何有用的资料。
非常感谢,
约翰
更新:我刚想到一个我开放世界类概念的好用例。也许这能更好地帮助理解我真正想做的事情。我想能够“描述”一个类,而不是定义它。例如,我想说狗是任何a) 有四条腿 b) 会叫的东西。然后我想创建一个未指定类的对象,并描述这个对象有四条腿。此时,这个对象仍然是未指定类型。然后我想说这个对象会叫。此时,这个对象就会被认定为(可能还有其他类型)一只狗。
5 个回答
不,您不能在Ruby中这样做。在Ruby中,对象模型是语言本身的一部分,程序内部无法访问(当然也不能修改)。即使在Rubinius中,这个Ruby的实现大部分是用Ruby写的,并且有很强的元编程能力,超出了Ruby规范的范围,但一些基本原理是用C++硬编码的。
我对Python不太熟悉,但我相信它也是这样,即使在PyPy中也是如此。
您可能可以在Smalltalk中做到这一点,通过修改(或子类化)行为类(Behavior
),这个类是Class
的父类,定义了类和类元的行为。
在CLOS中,或者更准确地说,使用CLOS的MOP(元对象协议),您肯定可以做到这一点。毕竟,MOP的目的就是定义对象模型。
您描述的最接近的面向对象概念似乎是谓词类。谓词类是一个类,其实例不是静态定义的,而是由一组谓词定义:所有满足这组谓词的对象都是该类的实例,只要谓词成立。在一个状态可变的语言中,这显然意味着对象可以随着其状态的变化而“移动”进出谓词类。这也意味着在任何给定时刻,一个对象可以是多个或没有谓词类的实例。
我知道的唯一一个有谓词类的主流语言(对于“主流”的定义相对宽泛)是Factor。
不过,请注意,即使在这里,谓词是被定义的,一个对象要么满足它们,要么不满足。没有在运行时发现一个对象是否满足某个谓词的概念。
最后但同样重要的是,您可以看看Mikel Evins的对象系统,叫做类别。对类别的最佳描述是按时间顺序跟随博客文章:
未来,类别的大部分开发将会在Mikel的新语言Bard中进行,您可以通过关注类别标签和吟游诗人标签来跟踪他们的进展,访问Mikel的新博客。
不过,总的来说,我想说的是,知识管理和面向对象都使用“类”这个词,主要是历史原因。我认为将一个模型与另一个模型进行比较并不合适。
听起来像是鸭子类型。你只需要声明你想要的方法,记住,事后请求原谅比事先请求许可要简单:
try:
poodle.wear()
except (AttributeError, TypeError):
pass
我同意Samir的看法,这听起来像是鸭子类型。你不需要关心一个对象到底是什么“类型”,你只需要关注这个对象能“做”什么。这在Ruby和Python中都是这样。
不过,如果你确实需要检查类的类型,并且在运行时需要一个Poodle
对象也可以是FurCoat
,那么在Ruby中实现这个功能的方法是把FurCoat
模块混入到Poodle
对象中,具体如下:
class Poodle; end
module FurCoat; def wear; end; end
my_poodle = Poodle.new
my_poodle.is_a?(Poodle) #=> true
my_poodle.is_a?(FurCoat) #=> false
my_poodle.wear #=> NoMethodError
# now we mix in the FurCoat module
my_poodle.extend(FurCoat)
# my_poodle is now also a FurCoat
my_poodle.is_a?(Poodle) #=> true (still)
my_poodle.is_a?(FurCoat) #=> true
my_poodle.wear #=> the wear method now works
编辑(根据你更新的问题):
你仍然不需要重写Class
来实现你想要的功能,你只需要对Ruby的Kernel
模块中的kind_of?
和is_a?
(可能还有instance_of?
)方法进行猴子补丁。由于Ruby的类是开放的,这很简单:
class Module
def obj_implements_interface?(obj)
false
end
end
module Kernel
alias_method :orig_is_a?, :is_a?
def is_a?(klass)
orig_is_a?(klass) || klass.obj_implements_interface?(self)
end
end
然后为每个类(或模块)定义一个对象实现其接口的含义:
class Dog
def self.obj_implements_interface?(obj)
obj.respond_to?(:bark) && obj.respond_to?(:num_legs) && obj.num_legs == 4
end
end
module FurCoat
def self.obj_implements_interface?(obj)
obj.respond_to?(:wear)
end
end
现在测试一下:
my_poodle = Poodle.new
my_poodle.is_a?(FurCoat) #=> false
# now define a wear method on my_poodle
def my_poodle.wear; end
my_poodle.is_a?(FurCoat) #=> true