在Ruby或Python中,类的概念可以重写吗?

9 投票
5 回答
582 浏览
提问于 2025-04-15 23:02

这是我第一次在Stack Overflow发帖。

我想了解一下Ruby或Python的一些元编程特性,但首先我需要知道这些特性能让我在多大程度上扩展语言。最重要的是,我想重新定义一下的概念。这并不是说我想在运行时重写某个特定的类,而是我想创造出我自己对的理解。更具体一点,我想做一些类似于人们通常称之为类的东西,但我想遵循一种“开放世界”的假设。在正常类的“封闭世界”中,如果我声明贵宾犬是狗的子类,而狗又是动物的子类,那么我就知道贵宾犬不会同时是毛皮外套的类型。然而,在开放世界的类中,我定义的贵宾犬对象可能是也可能不是毛皮外套的对象,直到我解释说我可以穿上贵宾犬为止。(可怜的贵宾犬。)这一切都与我正在进行的关于OWL本体的研究有关。

顺便说一下,我已经尝试在网上寻找信息,但由于术语太多,我没有找到任何有用的资料。

非常感谢,
约翰

更新:我刚想到一个我开放世界类概念的好用例。也许这能更好地帮助理解我真正想做的事情。我想能够“描述”一个类,而不是定义它。例如,我想说狗是任何a) 有四条腿 b) 会叫的东西。然后我想创建一个未指定类的对象,并描述这个对象有四条腿。此时,这个对象仍然是未指定类型。然后我想说这个对象会叫。此时,这个对象就会被认定为(可能还有其他类型)一只狗。

5 个回答

6

不,您不能在Ruby中这样做。在Ruby中,对象模型是语言本身的一部分,程序内部无法访问(当然也不能修改)。即使在Rubinius中,这个Ruby的实现大部分是用Ruby写的,并且有很强的元编程能力,超出了Ruby规范的范围,但一些基本原理是用C++硬编码的

我对Python不太熟悉,但我相信它也是这样,即使在PyPy中也是如此。

可能可以在Smalltalk中做到这一点,通过修改(或子类化)行为类(Behavior,这个类是Class的父类,定义了类和类元的行为。

CLOS中,或者更准确地说,使用CLOS的MOP元对象协议),您肯定可以做到这一点。毕竟,MOP的目的就是定义对象模型。

您描述的最接近的面向对象概念似乎是谓词类。谓词类是一个类,其实例不是静态定义的,而是由一组谓词定义:所有满足这组谓词的对象都是该类的实例,只要谓词成立。在一个状态可变的语言中,这显然意味着对象可以随着其状态的变化而“移动”进出谓词类。这也意味着在任何给定时刻,一个对象可以是多个或没有谓词类的实例。

我知道的唯一一个有谓词类的主流语言(对于“主流”的定义相对宽泛)是Factor

不过,请注意,即使在这里,谓词是被定义的,一个对象要么满足它们,要么不满足。没有在运行时发现一个对象是否满足某个谓词的概念。

您可能还会对Clojure临时分类法感兴趣。

最后但同样重要的是,您可以看看Mikel Evins的对象系统,叫做类别。对类别的最佳描述是按时间顺序跟随博客文章:

  1. 协议
  2. 类别
  3. 类别的初步了解
  4. 罗马没有国王
  5. 合理的类比出现了
  6. 不同类别的类别
  7. 类别的错误
  8. C3罐中的扁平猫
  9. 类别0.2
  10. 吟游诗人
  11. 吟游诗人的复杂性

未来,类别的大部分开发将会在Mikel的新语言Bard中进行,您可以通过关注类别标签吟游诗人标签来跟踪他们的进展,访问Mikel的新博客

不过,总的来说,我想说的是,知识管理和面向对象都使用“类”这个词,主要是历史原因。我认为将一个模型与另一个模型进行比较并不合适。

8

听起来像是鸭子类型。你只需要声明你想要的方法,记住,事后请求原谅比事先请求许可要简单:

try:
    poodle.wear()
except (AttributeError, TypeError):
    pass
7

我同意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

撰写回答