· 

PythonでOOP(Part 5)

前の編もお読みください:Part 1Part 2Part 3Part4

 

1.Getting Started

  Pythonを使ってOOPすなわちObject-Oriented Programmingの解説をします。

今回は、Special (Magic/Dunder) Methodsです。

 

 2.References

Youtubeとして、

Python OOP Tutorial 5: Special (Magic/Dunder) Methods

また、Documentationとして、

https://docs.python.org/3/tutorial/classes.html

を挙げておきます。

 

3.前回までのCode

一部変更したりしていますが、今回使うcodeは次のものです。

class Employee:

 

    raise_amt = 1.04     # class variable

 

    def __init__(self, first, last, pay):

        self.first = first

        self.last = last

        self.email = first + '.' + last + '@company.com'

        self.pay = pay

 

    def fullname(self):

        return '{} {}'.format(self.first, self.last)

 

    def apply_raise(self):

        self.pay = int(self.pay * self.raise_amt)

 

 

emp_1 = Employee('Mark', 'Twain', 50000)

emp_2 = Employee('Test', 'User', 6000)

 

print(emp_1.email)

print(emp_1.fullname())

 

4.Special methods

(1) special methodsは、init methodのように

__methodname__

すなわち、method nameの前後をdouble underscoreで、挟み込んだ形をとります。double underscoreのことを、dunderと呼びます。

 

(2) ここでは、2つのspecial methodsを紹介します。repr(ar-ee-pe-arと読みます)methodとstr methodです。ひとまず、中身を pass だけにして、class Employee: の、一番下に付け加えます。

    def __repr__(self):

        pass

 

    def __str__(self):

        pass

 

(3) まずは、repr methodの中身を書き換えます。

    def __repr__(self):

        return "Employee({}, {}, {})".format(self.first, self.last, self.pay)

 

    #def __str__(self):

    #    pass

reprでは、Employee()のかっこの中に、first, last, payの中身を入れる形になっています。また、str methodは、#を付けて動かないようにしておきます。さらに、codeの一番下に、

print(emp_1)

を追加します。

 

(4) まず、repr methodがない場合にどうなるかを調べるために、先ほどのrepr methodをcomment化します。

    #def __repr__(self):

    #    return "Employee({}, {}, {})".format(self.first, self.last, self.pay)

これをrunします。

出力結果の最初の2行は、もともとあったprint()文によるものです。3行目は、

print(emp_1)

の通常の出力結果です。Employeeというobjectであることと、addressらしきものが表示されます。emp_1がどういうものであるかを調べたいときに、上の2行のように、emp_1.emailとか、emp_1.fullname()により、具体的なattributeごとに調べなくてはならないのは、少し面倒です。

 

(5) そこで、repr methodの#を取り除き、動くようにして、もう1度、runしてみます。

3行目は、やはり、

print(emp_1)

の出力結果です。しかし、今度は、repr methodが自動的に動いて、address等ではなくて、class名のEmployeeとそのattributesのMark, Twain, 5000が表示されました。

 

このように、repr methodは、instance名をprintしようとしたときに、本来は、object名とaddressが表示されるところで、object名とattributesの内容が表示されるようにするものといえます。

 

5.dunder str method

(1) 次は、str methodです。次のcodeに書き換えます。

    def __repr__(self):

        return "Employee({}, {}, {})".format(self.first, self.last, self.pay)

 

    def __str__(self):

        return '{} - {}'.format(self.fullname(), self.email)

 

このstr methodでは、full nameとemailが dashでつながれて表示されます。repr methodも動く状態のままで、codeをrunしてみます。

出力結果の3行目が、

print(emp_1)

によるものです。repr methodがあるにもかかわらず、str methodのみがcall されて、full nameとemailが表示されました。このように、str methodがあるときは、repr methodは完全に無視されます

 

(2) そうすると、repr methodが意味がないものとなってしまいます。そこで、それぞれのmethodを個別に使いたいときは、print(emp_1)でなくて、

print(repr(emp_1))

の形で書きます。これをrunすると、

となり、repr methodで表示されました。したがって、str methodの場合は、

print(emp_1)

print(str(emp_1))

のどちらでも、表示できます。runしてみます。

同じものが2回表示されました。

 

(3) さらに、print()文の箇所を、次の4行のcodeに書き換えます。

print(repr(emp_1))

print(str(emp_1))

 

print(emp_1.__repr__())

print(emp_1.__str__())

これをrunしてみます。

上下で同じ結果が出ました。

つまり、repre(emp_1)とemp_1.__repr__()は同じであり、str(emp_1)とemp_1.__str__()は同じということになります。

 

6.dunder add method

(1) dunder methodsで頻繁に使うのは、init method, repr method, str methodの3つですが、他の例も挙げてみます。

print(1+2)

print(int.__add__(1,2))

2行目は、+のbackgroundで使われているcodeです。the integer objectのdunder add methodを使って、1+2を行っているわけです。これをrunします。

同じ結果が2つ出ました。

 

(2) stringの+(concatenation)も同様です。

print('a'+'b')

print(str.__add__('a', 'b'))

2行目では、the string object のdunder add methodが使われています。

やはり、同じ出力結果が出ました。

 

(3) これらと同じようなdunder add methodをEmployeeの中に作ってみます。

    def __add__(self, other):

        return self.pay + other.pay

 

このcodeをclass Employee:の一番下に付け加え、さらに、

emp_1 = Employee('Mark', 'Twain', 50000)

emp_2 = Employee('Test', 'User', 6000)

の下に、

 

print(emp_1 + emp_2)

print(emp_1.__add__(emp_2))

を付け加えます。これをrunしてみます。

1行目は、+記号によるもの、2行目は、dunder add methodをそのまま使ったものです。どちらも、正しい答えが出力されました。

 

(4) このようなdunder methodeは、Python Documentation の3.3.8. Emulating numeric typesにて、見つけることができます。

 

(5) もう1つdunder methodを作ってみます。

    def __len__(self):

        return len(self.fullname())

これは、full nameのlengthをreturnするmethodです。その使用codeとして、

print(emp_1.fullname())

print(len(emp_1))

print(emp_1.__len__())

をcodeの一番下に付け加えます。そして、runします。

full nameがMark Twainなので、10文字です。1つめのprint()文も、2つめのprint()文も、正しく10を出力しています。

 

次は、Part 6です。