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