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=で代入できるようになります
参考)
Ruby、Pythonでクラスのインスタンスメソッドを追加する
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}