在Ruby中,为什么`Array.length`会给出NoMethodError?

时间:2017-10-03 02:59:40

标签: python ruby nomethoderror name-lookup

在Python中,我可以通过调用list方法获得__len__的长度。 __len__没有在每个list个对象上定义list,而是>>> [].__len__() 0 >>> type([]) <class 'list'> >>> list.__len__([]) 0 类。可以通过类直接访问该方法:

> [].length
=> 0
> [].class
=> Array
> Array.length([])
NoMethodError: undefined method `length' for Array:Class

但是,等效代码在Ruby中不起作用:

length

使用Array.length时,为什么找不到{{1}}方法? Ruby中的方法查找与Python的工作方式不同吗?

1 个答案:

答案 0 :(得分:6)

是的,Ruby中的方法查找与Python中的方法查找有很大不同。

TL; DR答案是,如果您真的想从length Class对象中提取Array方法,则需要编写Array.instance_method(:length)。这会得到一个UnboundMethod对象,然后您可以绑定到特定对象并调用:

unbound_method = Array.instance_method(:length)
ary = [1,2,3,4]
bound_method = unbound_method.bind(ary)
bound_method.call #=> 4

不出所料,这在Ruby中并不常见。

在Ruby中,类本身是对象,类Class的实例;这些类有自己的方法,超出了它们为实例提供的方法,例如newnamesuperclass等方法。当然,它会是可能length类对象上定义Array方法,以便您可以编写Array.length,但这与同名的实例方法本身并不相关。核心类和标准库中有一些地方实际上已经完成,但在大多数情况下,它在Ruby中并不是惯用的。

Classmethods方法的输出中可以清楚地看到a instance_methods对象直接响应的方法与它为其实例提供的方法之间的区别。 :

irb(main):001:0> Array.methods
=> [:[], :try_convert, :new, :allocate, :superclass, ...
irb(main):002:0> Array.instance_methods
=> [:each_index, :join, :rotate, :rotate!, :sort!, ...

Ruby中的方法查找不像它在Python中那样工作的一个原因是,可能有一些方法名称,类和实例都需要以不同的方式响应。例如,考虑一个假设的Person类:

Person.ancestors # => [Person, Animal, Organism, Object, Kernel, BasicObject]
john = Person.new(...)
john.ancestors # => [John Sr., Sally, Jospeh, Mary, Charles, Jessica]

在Python中,当然,第一次调用将是一个错误:如果不将Person.ancestors的实例传递给Person,则无法调用__self__任何意义。但是你怎么得到Person类的祖先?您将Person本身传递给函数inspect.getmro(Person)。这在Python中是惯用的,但在Ruby中被认为是非常糟糕的风格。

基本上,作为不同的语言,即使在很多方面它们是相似的,它们仍然有不同的方法来解决某些问题,而一些被认为是良好实践或风格的东西在另一方面相当糟糕(和亦然)。