💎

PythonとRubyにおけるself.変数の違い

2023/10/30に公開

はじめに

私はPython→Rubyの順に勉強し始めたのですが、インスタンス変数の表記の違いに戸惑ったことがあり、記事にしました。

Pythonではインスタンス変数をself.varのように書きますが、Rubyでは@varのように書くことができます。例えば下記は同じ内容のコードで、いずれも"Hello, Taro!"と出力されます。

# Python
class User:
    def __init__(self, name):
        self.name = name

    def hello(self):
        print(f'Hello, {self.name}!')
        
user = User('Taro')
user.hello()
# Ruby
class User
  def initialize(name)
    @name = name
  end

  def hello
    puts "Hello, #{@name}!"
  end
end

user = User.new("Taro")
user.hello

ところが、Rubyでも(Pythonに似た)self.varのような表記を目にすることがあったため、そのような表記が可能になる条件を調べてみました。

Rubyでself.変数を使ってみる

さっそく初期化メソッドでself.nameに代入しようとしたところ、エラーが出ました。

class User
  def initialize(name)
    self.name = name
  end

  def hello
    puts "Hello, #{self.name}!"
  end
end

user = User.new("Taro")
user.hello
# => in `initialize': undefined method `name=' for #<User:0x000014db28437548> (NoMethodError)

エラー内容を読むと、self.nameに代入しようとすると内部的にはインスタンス変数nameに対応したセッターメソッドを呼んでいることが推察されます。今回はセッターメソッドを定義していないのでエラーが出たようです。

次にセッターメソッドを設定してみると[1]、初期化メソッドの箇所ではエラーが出なくなりました。

class User
  def initialize(name)
    self.name = name
  end

  def hello
    puts "Hello, #{self.name}!"
  end

  # セッターメソッド
  def name=(name)
    @name = name
  end
end

user = User.new("Taro")
user.hello
# => in `hello': undefined method `name' for #<User:0x00001544c1297398 @name="Taro"> (NoMethodError)

今度はhelloメソッド内でエラーが出ていますが、これもインスタンス変数nameに対応した(未定義の)ゲッターメソッドを呼んでいるためのようです。

最後にゲッターメソッドも追加すると[2]、エラーが全く出なくなりました。

class User
  def initialize(name)
    self.name = name
  end

  def hello
    puts "Hello, #{self.name}!"
  end

  # セッターメソッド
  def name=(name)
    @name = name
  end

  # ゲッターメソッド
  def name
    @name
  end
end

user = User.new('Taro')
user.hello()
# => Hello, Taro!

以上の検証結果から、クラス内部でself.varのような表記で読み書きしようとすると、対応するインスタンス変数のゲッター/セッターメソッドが呼ばれ、存在しない時にはエラーが出るらしいということが分かりました。

Rubyでは、クラス外部からインスタンス変数を(インスタンス名.varのような表記で)読み書きしようとすると、ゲッター/セッターメソッドが呼ばれます。クラス内においても同じような挙動になると言えそうです。

まとめ

  • インスタンス変数はPythonだとself.var、Rubyでは@varのように表記する
  • Rubyでself.varのような表記を使って読み書きするには、対応するインスタンス変数についてのゲッター/セッターメソッドが必要

この記事が同じような疑問を覚えた方に役立てば嬉しいです。

脚注
  1. 代わりにattr_writer :nameを追加しても同様の結果になります ↩︎

  2. 代わりにattr_reader :nameを追加しても同様の結果になります ↩︎

Discussion