Rubyを使って簡単なクラスを定義してみる。

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

すごく簡単だ。上の文はこうも書ける。

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

その後、そのクラスを使ったコードで

person1 = Person.new("ichiro")
puts person1.name

とすれば"ichiro"という出力が得られる。
このコードの

puts person1.name

という部分は

puts person1.name()

こう書いても問題ない。
要はperson1.nameはインスタンス変数に直接アクセスしている訳ではなくメソッドを呼び出しているという事。
上記コードの

attr_reader :name

はインスタンス変数@nameに対してのアクセスメソッド(この場合はゲッター)の定義を簡単にしている。
これはRubyのインスタンス変数は基本的にすべてprivateで、アクセスを許可するにはアクセサメソッドを定義しろと言う事だ。
それを簡単にする為、読み出しのみならattr_reader、書き込みのみならattr_writer、両方許可するにはattr_accessorというものが用意されている。

ではPythonを使って同じようなクラスを定義してみる

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

def name(self):
    return self.name

とまあ、こんな感じになるがその後、そのクラスを使い

person1 = Person("ichiro")
print person1.name

とすると期待通り"ichiro"と出力される。がしかし。

print person1.name()

とした場合、

TypeError: 'str' object is not callable

と怒られてしまう。
文字列が格納されている"name"という変数に対してかっこを付けあたかも関数のようにして呼び出そうとしたが"文字列に対して呼び出しは出来ませんよ!"という風に言われてる訳だ。
これはPythonの特徴を考慮すれば納得のいく話だがつまりは、
たとえ中に入っているものが文字列や数値、さらには関数オブジェクトだったとしても、それが変数である事にかわりは無い。
そして同じ名前空間であれば重複は許されないと言う事だ。

person1という名前空間の中でnameという変数を捜したら関数オブジェクトのnameより文字列のnameの方が先に見つかった。
というだけの事なのだ。
person1のインスタンスメソッドとしてではなくPersonクラスのクラスメソッドとして

print Person.name(person1)

とすれば"ichiro"と出力される。
これもクラスPersonの名前空間では関数オブジェクトのnameが見つかるから、と考えれば納得のいく話だ。
ややこしいがクラスとインスタンスではそれぞれ別に名前空間が存在し、インスタンスのそれはクラスのそれを継承している。
インスタンス変数の名前空間を検索し始めたらまずインスタンス自身の名前空間で捜し、見つからなければクラスの方に捜しに行くと言う事だ。
なのでこの場合は

def name(self):

の部分を

def getname(self):

みたいに適当に名前を変え

print person1.getname()

とすればいい。

これはある意味、Rubyでのオブジェクト指向の考え方がPythonだと邪魔になってしまう、と言えるのかもしれない。

カテゴリ:

トラックバック(0)

トラックバックURL: http://blog.beanz-net.jp/beanz_mtos/mt-tb.cgi/16

コメントする