Python具有元类的概念,如果我理解正确,允许您在构造时修改类的对象。您没有修改类,而是要创建的对象然后进行初始化。
Python(至少从3.0开始,我相信)也有类装饰器的想法。如果我理解正确的话,类装饰器允许在声明它时修改类定义。
现在我相信Ruby中的类装饰器有一个相同的特性或功能,但我目前还没有意识到类似于元类的东西。我确信你可以通过一些函数轻松地抽取任何Ruby对象并按照你的意愿去做,但是语言中是否有一个像metaclass那样设置的功能?
再说一遍,Ruby是否有类似于Python的元类的东西?
编辑我关闭了Python的元类。元类和类装饰器做的事情非常类似。它们都在定义时以不同的方式修改类。希望Python大师能够在Python中更好地解释这些功能。
但是类或类的父类可以实现__new__(cls[,..])
函数,该函数在使用__init__(self[,..])
初始化之前自定义对象的构造。
编辑此问题主要用于讨论和了解两种语言在这些功能中的比较。我熟悉Python但不熟悉Ruby并且很好奇。希望其他对这两种语言有相同问题的人会发现这篇文章很有帮助,也很有启发性。
答案 0 :(得分:23)
Ruby没有元类。 Ruby中有一些构造,有些人有时会错误地调用元类,但它们不是(这是无穷无尽的混淆的源头)。
但是,有很多方法可以在Ruby中实现与使用元类相同的结果。但是,如果不告诉我们你想做什么,就不知道这些机制可能是什么。
简而言之:
那么,究竟是什么元类?嗯,他们是班级。那么,让我们退后一步:类究竟是什么?
课程......
例如,Array
类生成数组对象,定义数组的行为并定义“array-ness”的含义。
回到元类。
元类......
在Ruby中,这三个职责分为三个不同的地方:
Class
类创建类并定义一些行为Class
继承来创建一种新方法,以不同的方式查找方法,或者类似的东西 - 方法查找算法硬连线到解释器中)所以,这三个东西一起扮演元类的角色,但这些都不是元类(每个都只实现元类所做的一小部分), sum 也不是那些元类(因为它们做的远不止于此)。
不幸的是,有些人称类的特殊类是元类。 (直到最近,我才成为那些被误导的灵魂之一,直到我终于看到光明。)其他人称之为所有特征类元类。 (不幸的是,其中一个人是关于Ruby元编程和Ruby对象模型的最受欢迎的教程之一。)一些流行的库向metaclass
添加Object
方法,返回对象的本征类(例如ActiveSupport,Facets,metaid)。有些人称所有虚拟类(即本征类和包含类)元类。有些人称Class
为元类。即使在Ruby源代码本身中,“metaclass”一词也用于指代不是元类的东西。
答案 1 :(得分:12)
您的更新问题现在看起来很不一样了。如果我理解正确,你想要挂钩对象分配和初始化,这绝对没有任何与元类有关。 (但你仍不写你真正想做的事情,所以我可能仍然会离开。)
在一些面向对象的语言中,对象由构造函数创建。但是,Ruby没有构造函数。构造函数只是工厂方法(有愚蠢的限制);如果您可以使用(更强大的)工厂方法,则没有理由将它们用于精心设计的语言中。
Ruby中的对象构造如下:对象构造分为两个阶段,分配和初始化。分配由名为allocate
的公共类方法完成,该方法被定义为类Class
的实例方法,并且通常从不覆盖。 (事实上,我不认为你实际上可以覆盖它。)它只是为对象分配内存空间并设置几个指针,但是,此时对象并不真正可用
这就是初始化器的用武之地:它是一个名为initialize
的实例方法,它设置对象的内部状态并将其置于一个完全定义的一致状态,可供其他对象使用。
因此,为了完全创建一个新对象,您需要做的是:
x = X.allocate
x.initialize
[注意:Objective-C程序员可能会认识到这一点。]
但是,因为很容易忘记调用initialize
并且作为一般规则,对象在构造之后应该是完全有效的,有一个称为Class#new
的便利工厂方法,它可以完成所有这些工作。为你工作,看起来像这样:
class Class
def new(*args, &block)
obj = allocate
obj.initialize(*args, &block)
return obj
end
end
[注意:实际上,initialize
是私有的,因此必须使用反射来绕过这样的访问限制:obj.send(:initialize, *args, &block)
]
顺便说一下,这就是构建一个你调用公共类方法Foo.new
的对象的原因,但你实现私有实例方法{ {1}},这似乎惹恼了很多新人。
然而, none 的任何方式都以这种语言为基础。任何类的主要工厂方法通常称为Foo#initialize
这一事实只是一种约定(有时我希望它不同,因为它看起来类似于Java中的构造函数,但完全不同)。在其他语言中,构造函数必须具有特定名称。在Java中,它必须与类具有相同的名称,这意味着a)只能有一个构造函数,而b)匿名类不能有构造函数,因为它们没有名称。在Python中,工厂方法必须被称为new
,这意味着只能有一个。{1}}。 (在Java和Python中,你当然可以使用不同的工厂方法,但是调用它们看起来与调用默认值不同,而在Ruby中(和Smalltalk从这个模式发起)它看起来是一样的。)
在Ruby中,可以有任意数量的工厂方法,您可以使用任何名称,工厂方法可以有许多不同的名称。 (例如,对于集合类,工厂方法通常是__new__
的别名,这允许您编写[]
而不是List[1, 2, 3]
,它们看起来更像一个数组,从而强调集合列表的性质。)
简而言之:
List.new(1, 2, 3)
,但它可以是任何Foo.new
调用Foo.new
为空对象分配内存allocate
foo
然后调用Foo.new
,即foo.initialize
实例方法Foo#initialize
,你无法从Ruby真正做到这一点在Python中,allocate
大致对应Ruby中的__new__
和new
,allocate
完全对应__init__
在Ruby中。主要区别在于,在Ruby中,initialize
调用new
而在Python中,运行时会在initialize
之后自动调用__init__
。
例如,这是一个只允许创建最多2个实例的类:
__new__