【问题标题】:Python like __getattr__ for Ruby / JRubyPython 像 __getattr__ 用于 Ruby / JRuby
【发布时间】:2011-11-28 19:09:43
【问题描述】:

对于 Ruby,是否有类似 Python __getattr__ 的东西?在 Python 中,当引用未定义的属性(方法或属性)时,会调用 obj.__getattr__。我在 Ruby 中找到了method_missing,但它不适用于属性。

我的用例是: 我正在测试 Mirah 作为 JRuby -> Java 编译器。在标准 JRuby 中,Swing 方法和属性是“Rubyfied”(例如:label.setText "x" => label.text = "x"),但在 Mirah 中不是,因为 Mirah 没有像 JRuby 这样的专有运行时库.然后,我想在运行时获取属性引用并将每个调用映射到相应的 Swing 方法(label.text => label.getText() / label.text = "x" => label.setText("x") ) .

【问题讨论】:

  • @jsalonen:没有重复,getattr __getattr__。 Python getattr 类似于 Ruby 的“方法”:obj.getattr("value") 等价于 obj.value。 __getattr__ 是一个“魔术”方法,在引用未定义的属性时调用

标签: ruby jruby mirah


【解决方案1】:

我不确定这是否涵盖了您的用例,但总的来说,method_missing 应该可以解决问题。您希望 Ruby 类如何知道未定义的方法和未定义的“属性”之间的区别?它所知道的只是它被传递了一个它不认识的名字。它应该是一种方法还是一种属性?谁知道?除非您在谈论 setter 属性,否则在这种情况下,名称后面会附加一个 =

 class X
   def method_missing name,*args
     puts "missing '#{name}' called with #{args}"
   end
 end  

.

> x = X.new
=> #<X:0xe6b322>
> x.unknown_method
missing 'unknown_method' called with []
=> nil
> x.unknown_property
missing 'unknown_property' called with []
=> nil
> x.unknown_property= 42
missing 'unknown_property=' called with [42]
=> 42     

【讨论】:

    【解决方案2】:

    JRuby 在 Java 代码中进行这种转换,方法是遍历反射类的方法并为 Ruby 名称添加别名。您也可以从 Ruby 中执行此操作。 Mirah 可以访问您正在编译的所有类的实际 java.lang.Class 实例,因此可以在编译阶段执行相同的名称别名。

    具体如何做到这一点的细节留给读者作为练习:)

    【讨论】:

    • 我想我可以使用object.methods' and then something like :add_method`(我是 Ruby/Mirah 新手,如果我没有正确理解你,请见谅)。但我一直在寻找一个动态的解决方案,因为这是我在 Python 中解决这个问题时会使用的方法,并且 Ruby 与 Python 如此相似——至少对我而言——当我发现 method_missing 时,我认为有办法做属性也一样。不管怎样,继续使用 JRuby!
    【解决方案3】:

    Ruby 中的对象没有“属性”。它们有实例变量(每个实例存储数据的私有变量)和可以访问这些变量的方法。

    因为括号在 Ruby 方法调用中是可选的,并且因为语法糖允许您编写 obj.foo = 42 作为调用方法 obj.foo=( 42 ) 的更好方式,所以您可能认为这些是属性。他们不是;它们是与其他任何方法都无法区分的方法。

    这段代码:

    class Foo
       attr_accessor :bar
    end
    f = Foo.new
    f.bar = 42
    puts f.bar  #=> 42
    

    与这个(更长的)代码完全相同:

    class Foo
      def bar
        @bar
      end
      def bar=( val )
        @bar = val
      end
    end
    f = Foo.new
    f.bar=( 42 )
    puts( f.bar() ) #=> 42
    

    attr_* 方法实际上为您创建方法。

    【讨论】:

      猜你喜欢
      • 2012-05-26
      • 2010-10-25
      • 1970-01-01
      • 1970-01-01
      • 2021-09-27
      • 1970-01-01
      • 1970-01-01
      • 2011-02-14
      相关资源
      最近更新 更多