Ruby、Pythonでインスタンス変数を動的に取得/設定する

ちょっと前まではrubyで、最近はpythonで仕事をしているので、rubyでやっていたアレ、pythonだとどうやるんだろ?と思うことがたまにあります。
逆にpython書いてて、あれこれrubyで(ry とか


で、インスタンス変数の操作ですが、
pythonではあらかじめ定義をしていなくても、インスタンス.変数名に代入することでインスタンス変数をセットすることができます
またインスタンスの__dict__に変数名と値が格納されていますので、それを参照することで、インスタンス変数になにが設定されているのか知ることができます

python
class Person():
    def __init__(self, name):
        self.name = name

me = Person('yuhei')

# インスタンス変数をセット
me.age = 33 

# インスタンス変数名の一覧を取得
print me.__dict__.keys()
# => ['age', 'name']

# インスタンス変数の値一覧を取得
print me.__dict__.values()
# => [33, 'yuhei']

# インスタンス変数名、値の辞書を取得
print me.__dict__
# => {'age': 33, 'name': 'yuhei'}
ruby

rubyでは、インスタンス.変数名に代入しようとするとエラーになります

class Person
  def initialize(name)
    @name = name
  end
end

me = Person.new('yuhei')
me.age = 33
# NoMethodError: undefined method `age='


クラスをオープンしてメソッドを追加すれば、me.age=で代入できるようになります
参考)
RubyPythonでクラスのインスタンスメソッドを追加する
http://d.hatena.ne.jp/yuheiomori0718/20120114/1326545228

class Person
  attr_accessor :age
end

me.age = 33


すべてのクラスにメソッドを追加したくない場合は、特異クラスにメソッドを定義することができます

# 1.9.2
me.singleton_class.class_eval{ attr_accessor :age }
# 1.8.7 
me.instance_eval { class << self; attr_accessor :age; end; }

me.age = 33


もう一つの選択肢としてinstance_variable_*系のメソッドがあります。

# インスタンス変数を設定
me.instance_variable_set(:@age, 33)

# インスタンス変数名を取得
print me.instance_variables
# => [:@name, :@age]

# インスタンス変数の値取得
print me.instance_variables.map {|sym| me.instance_variable_get(sym)}
# => ["yuhei", 33]

# インスタンス変数名、値のハッシュを取得
hash = {}.tap {|h|
  me.instance_variables.each { |sym|
    h[sym] = me.instance_variable_get(sym)
  }
}
print hash
#=> {:@name=>"yuhei", :@age=>33}