在Ruby或Python中,类的概念能被重写吗?

时间:2022-07-04 18:06:18

first time at stack overflow.

第一次堆栈溢出。

I'm looking into using some of the metaprogramming features provided by Ruby or Python, but first I need to know the extent to which they will allow me to extend the language. The main thing I need to be able to do is to rewrite the concept of Class. This doesn't mean that I want to rewrite a specific class during run time, but rather I want to make my own conceptualization of what a Class is. To be a smidge more specific here, I want to make something that is like what people normally call a Class, but I want to follow an "open world" assumption. In the "closed world" of normal Classes, if I declare Poodle to be a subclass of Dog to be a subclass of Animal, then I know that Poodle is not going to also be a type of FurCoat. However, in an open world Class, then the Poodle object I've defined may or may not be and object of type FurCoat and we won't know for sure until I explain that I can wear the poodle. (Poor poodle.) This all has to do with a study I'm doing concerning OWL ontologies.

我正在研究使用Ruby或Python提供的一些元编程特性,但首先我需要知道它们允许我扩展语言的程度。我需要做的主要事情是重写类的概念。这并不意味着我想在运行时重写一个特定的类,而是我想对类进行自己的概念化。更具体地说,我想做一些人们通常称之为类的东西,但我想遵循“开放世界”的假设。在正常班级的“封闭世界”中,如果我把贵宾犬定义为狗的一个子类,那么我知道贵宾犬也不会是一种皮毛大衣。然而,在一个开放世界的课堂上,我定义的狮子狗对象可能是也可能不是,我们不能确定,除非我解释我可以戴它。(可怜的狮子狗。)这一切都与我正在做的关于OWL本体的研究有关。

Just so you know, I've tried to find information online, but due to the overloading of terms here I haven't found anything helpful.

就像你知道的,我试着在网上找资料,但是由于这里的术语太多,我没有发现任何有用的东西。

Super thanks, John

非常谢谢你,约翰

UPDATE: I just thought of a good use case for my open-world concept of Class. Perhaps this will provide a better understanding of what I really wish to do. I want to be able to "describe" a Class rather than define it. For instance, I want to be able to say that a Dog is anything that a) has four legs b) barks. Then I want to be able to create an object of unspecified Class, and describe that this object has four legs. At this point the object is still of unspecified type. Then I want to say that the object barks. At this point, the object will be known to be (possibly among other things) a Dog.

更新:我刚刚想到了一个很好的用例来描述我的开放世界的类概念。也许这能更好地理解我真正想做的事情。我希望能够“描述”一个类,而不是定义它。例如,我想说狗是任何a)有四条腿b)吠的东西。然后,我希望能够创建一个未指定类的对象,并描述该对象有四条腿。此时对象仍然是未指定的类型。然后我想说这个物体叫。在这一点上,这个物体将被知道是一只狗(可能还有其他东西)。

5 个解决方案

#1


7  

I agree with Samir that it just sounds like duck typing. You don't need to care what 'type' an object really 'is' you only need bother with what an object can 'do'. This is true in both Ruby and Python.

我同意萨米尔的观点,那听起来就像鸭子打字。你不需要关心一个对象真正的类型是什么,你只需要关心一个对象可以做什么。在Ruby和Python中都是如此。

However if you really are checking the types of classes and you really do need to have a Poodle object optionally also be a FurCoat at runtime, then the way to do this in Ruby is to mixin a FurCoat module into the Poodle object, as follows:

但是,如果您确实在检查类的类型,并且您确实需要在运行时有一个可选的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

EDIT (due to your updated question):

编辑(由于您更新的问题):

You still do not need to rewrite Class to achieve what you want, you just need to monkey-patch the kind_of? and is_a? (and potentially instance_of?) methods on Ruby's Kernel module. Since Ruby has open classes this is easily done:

您仍然不需要重写类来实现您想要的,您只需要monkeypatch的kind_of?和is_a吗?Ruby内核模块上的方法。由于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

And then define for each class (or module) what it means for an object to implement its interface:

然后为每个类(或模块)定义对象实现其接口的含义:

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

Now test it:

现在测试它:

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

#2


8  

Sounds like duck typing to me. Just declare the methods you want and remember that it's easier to ask forgiveness than permission:

听起来像鸭子在打字。只需声明你想要的方法,记住请求宽恕比请求许可更容易:

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

#3


6  

No, you cannot do that in Ruby. In Ruby, the object model is baked into the language specification and is not accessible (and certainly not modifiable) from within the program. Even in Rubinius, which is a Ruby implementation written mostly in Ruby, and with amazing metaprogramming capabilities that extend far beyond what the Ruby specification offers, some of the fundamental primitives are hardwired in C++.

不,你不能在Ruby中那样做。在Ruby中,对象模型被放入语言规范中,并且在程序中不可访问(当然也不能修改)。即使在Rubinius中,它是一个大部分是用Ruby编写的Ruby实现,并且具有令人惊叹的元编程能力,远远超出了Ruby规范所提供的功能,一些基本的原语也是用c++编写的。

I am not that intimately familiar with Python, but I'm pretty sure it's the same way, even in PyPy.

我对Python不是很熟悉,但是我很确定,即使在PyPy中也是如此。

You might be able to do that in Smalltalk, by modifying (or subclassing) the Behavior class, which is the superclass of Class and defines the behavior of both classes and metaclasses.

在Smalltalk中,可以通过修改(或子类化)行为类来实现这一点,该类是类的超类,定义了类和元类的行为。

You can certainly do that in CLOS, or more precisely using CLOS's MOP (Meta-Object Protocol). After all, that's what a MOP is for: defining the object model.

当然,您可以在CLOS中这样做,或者更准确地说,您可以使用CLOS的MOP(元对象协议)。毕竟,这就是MOP的用途:定义对象模型。

The closest OO concept to what you are describing seems to be that of Predicate Classes. A predicate class is a class whose instances are not defined statically, but by a set of predicates: all objects that satisfy the set of predicates are instances of the class, as soon as and for as long as the predicate holds. In a language with mutable state, this obviously means that objects can "move" in and out of predicate classes as their state changes. It also means that at any given time an object can be an instance of many or no predicate classes.

与您所描述的内容最接近的OO概念似乎是谓词类。谓词类是一个类,它的实例不是静态定义的,而是通过一组谓词来定义的:满足谓词集的所有对象都是类的实例,只要谓词保持不变。在具有可变状态的语言中,这显然意味着对象可以随着状态的改变而在谓词类中“移动”。它还意味着,在任何给定的时间,对象都可以是多个谓词类的实例,也可以是多个谓词类的实例。

The only mainstream language (for a rather broad definition of "mainstream") I know of that has predicate classes is Factor.

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

However, please note that even here, the predicates are defined and an object either fulfils them or it doesn't. There is no concept of discovering whether or not an object fulfils a predicate at runtime.

但是,请注意,即使在这里,谓词也是定义的,对象要么完成谓词,要么不完成谓词。在运行时,没有发现对象是否满足谓词的概念。

You might also be interested in Clojure's idea of ad-hoc taxonomy.

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

Last, but certainly not least, you might take a look at Mikel Evins's object system called Categories. The best description of Categories, is to simply follow the blog entries in chronological order:

最后,但同样重要的是,您可以看看Mikel Evins的对象系统,称为类别。对分类的最好描述,就是按照时间顺序简单地按照博客的条目来做:

  1. Protocols
  2. 协议
  3. Categories
  4. 类别
  5. A peek at Categories
  6. 一窥类别
  7. No Kings in Rome
  8. 在罗马没有国王
  9. Up pops a reasonable facsimile thereof
  10. 弹出一个合理的传真
  11. Different Categories of Categories
  12. 不同类别的类别
  13. Categories Bugs
  14. 分类错误
  15. Flat Cat in a C3 Vat
  16. 平底猫在C3桶
  17. Categories 0.2
  18. 0.2类
  19. Bard
  20. 吟游诗人
  21. Bard intricacies
  22. 吟游诗人错综复杂

In the future, most of the development on Categories is going to be done in Mikel's new language Bard and you can follow their progress by following the Categories tag and the Bard tag on Mikel's new blog.

将来,在Mikel的新语言吟游诗人中,将会有很多种类的开发,你可以根据Mikel的新博客上的类别标签和吟游诗人标签来跟踪他们的进展。

However, in general, I would say that the fact that Knowledge Management and Object-Orientation both use the word class is mainly a historic accident. I don't think that modeling one with the other is a good fit.

然而,总的来说,我认为知识管理和面向对象都使用类这个词的事实主要是一个历史性的意外。我认为一个人和另一个人做模特不太合适。

#4


2  

In Python you can change the inheritence of a class at runtime, but at every given time a class is not a subclass of another one unless declared otherwise. There is no "may or may not" - that would need ternary logic which Python doesn't support. But of course you can write your own "Is-a" and "Has-a" functions to map OWL ontologies to Python classes.

在Python中,您可以在运行时更改类的继承,但是在每次给定的时候,类都不是另一个类的子类,除非声明为非类。没有“可能”或“不可能”——这需要用Python不支持的三元逻辑。但是当然,您可以编写自己的“Is-a”和“Has-a”函数来将OWL本体映射到Python类。

#5


1  

I think relying on a class structure, no matter how dynamic, is a step backwards when representing information with an open word assumption.

我认为依赖一个类结构,无论多么动态,在用开放的词假设表示信息时都是倒退。

Classes serving as templates and objects serving as instances give absolutely no advantage when used with an OWA. Consider a Person class where we encode the knowledge that a person has 2 legs. However, we cannot deduce that a instance of Person will have two legs, as the person may have a disability.

作为模板的类和作为实例的对象在与OWA一起使用时绝对没有优势。考虑一个Person类,我们在其中编码一个人有两条腿的知识。然而,我们不能推断一个人会有两条腿,因为这个人可能有残疾。

If class properties don't mean anything as in the above example, there seems little point in using them or any other hierarchical structure to encode information.

如果类属性与上面的示例没有任何意义,那么使用它们或任何其他层次结构来编码信息似乎没什么意义。

#1


7  

I agree with Samir that it just sounds like duck typing. You don't need to care what 'type' an object really 'is' you only need bother with what an object can 'do'. This is true in both Ruby and Python.

我同意萨米尔的观点,那听起来就像鸭子打字。你不需要关心一个对象真正的类型是什么,你只需要关心一个对象可以做什么。在Ruby和Python中都是如此。

However if you really are checking the types of classes and you really do need to have a Poodle object optionally also be a FurCoat at runtime, then the way to do this in Ruby is to mixin a FurCoat module into the Poodle object, as follows:

但是,如果您确实在检查类的类型,并且您确实需要在运行时有一个可选的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

EDIT (due to your updated question):

编辑(由于您更新的问题):

You still do not need to rewrite Class to achieve what you want, you just need to monkey-patch the kind_of? and is_a? (and potentially instance_of?) methods on Ruby's Kernel module. Since Ruby has open classes this is easily done:

您仍然不需要重写类来实现您想要的,您只需要monkeypatch的kind_of?和is_a吗?Ruby内核模块上的方法。由于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

And then define for each class (or module) what it means for an object to implement its interface:

然后为每个类(或模块)定义对象实现其接口的含义:

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

Now test it:

现在测试它:

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

#2


8  

Sounds like duck typing to me. Just declare the methods you want and remember that it's easier to ask forgiveness than permission:

听起来像鸭子在打字。只需声明你想要的方法,记住请求宽恕比请求许可更容易:

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

#3


6  

No, you cannot do that in Ruby. In Ruby, the object model is baked into the language specification and is not accessible (and certainly not modifiable) from within the program. Even in Rubinius, which is a Ruby implementation written mostly in Ruby, and with amazing metaprogramming capabilities that extend far beyond what the Ruby specification offers, some of the fundamental primitives are hardwired in C++.

不,你不能在Ruby中那样做。在Ruby中,对象模型被放入语言规范中,并且在程序中不可访问(当然也不能修改)。即使在Rubinius中,它是一个大部分是用Ruby编写的Ruby实现,并且具有令人惊叹的元编程能力,远远超出了Ruby规范所提供的功能,一些基本的原语也是用c++编写的。

I am not that intimately familiar with Python, but I'm pretty sure it's the same way, even in PyPy.

我对Python不是很熟悉,但是我很确定,即使在PyPy中也是如此。

You might be able to do that in Smalltalk, by modifying (or subclassing) the Behavior class, which is the superclass of Class and defines the behavior of both classes and metaclasses.

在Smalltalk中,可以通过修改(或子类化)行为类来实现这一点,该类是类的超类,定义了类和元类的行为。

You can certainly do that in CLOS, or more precisely using CLOS's MOP (Meta-Object Protocol). After all, that's what a MOP is for: defining the object model.

当然,您可以在CLOS中这样做,或者更准确地说,您可以使用CLOS的MOP(元对象协议)。毕竟,这就是MOP的用途:定义对象模型。

The closest OO concept to what you are describing seems to be that of Predicate Classes. A predicate class is a class whose instances are not defined statically, but by a set of predicates: all objects that satisfy the set of predicates are instances of the class, as soon as and for as long as the predicate holds. In a language with mutable state, this obviously means that objects can "move" in and out of predicate classes as their state changes. It also means that at any given time an object can be an instance of many or no predicate classes.

与您所描述的内容最接近的OO概念似乎是谓词类。谓词类是一个类,它的实例不是静态定义的,而是通过一组谓词来定义的:满足谓词集的所有对象都是类的实例,只要谓词保持不变。在具有可变状态的语言中,这显然意味着对象可以随着状态的改变而在谓词类中“移动”。它还意味着,在任何给定的时间,对象都可以是多个谓词类的实例,也可以是多个谓词类的实例。

The only mainstream language (for a rather broad definition of "mainstream") I know of that has predicate classes is Factor.

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

However, please note that even here, the predicates are defined and an object either fulfils them or it doesn't. There is no concept of discovering whether or not an object fulfils a predicate at runtime.

但是,请注意,即使在这里,谓词也是定义的,对象要么完成谓词,要么不完成谓词。在运行时,没有发现对象是否满足谓词的概念。

You might also be interested in Clojure's idea of ad-hoc taxonomy.

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

Last, but certainly not least, you might take a look at Mikel Evins's object system called Categories. The best description of Categories, is to simply follow the blog entries in chronological order:

最后,但同样重要的是,您可以看看Mikel Evins的对象系统,称为类别。对分类的最好描述,就是按照时间顺序简单地按照博客的条目来做:

  1. Protocols
  2. 协议
  3. Categories
  4. 类别
  5. A peek at Categories
  6. 一窥类别
  7. No Kings in Rome
  8. 在罗马没有国王
  9. Up pops a reasonable facsimile thereof
  10. 弹出一个合理的传真
  11. Different Categories of Categories
  12. 不同类别的类别
  13. Categories Bugs
  14. 分类错误
  15. Flat Cat in a C3 Vat
  16. 平底猫在C3桶
  17. Categories 0.2
  18. 0.2类
  19. Bard
  20. 吟游诗人
  21. Bard intricacies
  22. 吟游诗人错综复杂

In the future, most of the development on Categories is going to be done in Mikel's new language Bard and you can follow their progress by following the Categories tag and the Bard tag on Mikel's new blog.

将来,在Mikel的新语言吟游诗人中,将会有很多种类的开发,你可以根据Mikel的新博客上的类别标签和吟游诗人标签来跟踪他们的进展。

However, in general, I would say that the fact that Knowledge Management and Object-Orientation both use the word class is mainly a historic accident. I don't think that modeling one with the other is a good fit.

然而,总的来说,我认为知识管理和面向对象都使用类这个词的事实主要是一个历史性的意外。我认为一个人和另一个人做模特不太合适。

#4


2  

In Python you can change the inheritence of a class at runtime, but at every given time a class is not a subclass of another one unless declared otherwise. There is no "may or may not" - that would need ternary logic which Python doesn't support. But of course you can write your own "Is-a" and "Has-a" functions to map OWL ontologies to Python classes.

在Python中,您可以在运行时更改类的继承,但是在每次给定的时候,类都不是另一个类的子类,除非声明为非类。没有“可能”或“不可能”——这需要用Python不支持的三元逻辑。但是当然,您可以编写自己的“Is-a”和“Has-a”函数来将OWL本体映射到Python类。

#5


1  

I think relying on a class structure, no matter how dynamic, is a step backwards when representing information with an open word assumption.

我认为依赖一个类结构,无论多么动态,在用开放的词假设表示信息时都是倒退。

Classes serving as templates and objects serving as instances give absolutely no advantage when used with an OWA. Consider a Person class where we encode the knowledge that a person has 2 legs. However, we cannot deduce that a instance of Person will have two legs, as the person may have a disability.

作为模板的类和作为实例的对象在与OWA一起使用时绝对没有优势。考虑一个Person类,我们在其中编码一个人有两条腿的知识。然而,我们不能推断一个人会有两条腿,因为这个人可能有残疾。

If class properties don't mean anything as in the above example, there seems little point in using them or any other hierarchical structure to encode information.

如果类属性与上面的示例没有任何意义,那么使用它们或任何其他层次结构来编码信息似乎没什么意义。