☆☆ 新着記事 ☆☆

2019年3月13日水曜日

Python self を理解する


クラスの定義
Pythonではクラスの定義にclass文を使用します。class文を使った定義の仕方は以下のようになります。

class クラス名:

class文の後にそのクラスの名前となるクラス名をつけて、最後に「:」を付け加えます。そのあとに一段落インデントを入れてクラス定義をしていきます。

class Test:
    pass  #何もしないクラスの場合はpassと記入する
test = Test()  #インスタンスを生成

メソッド
クラスにはメソッドを定義することができます。メソッドの定義は以下のように行います。
(※メソッドとは、簡単に言うとクラスの中で定義された関数のことです。)
class クラス名:
    def メソッド名(self):
        #メソッドの定義

メソッドは必ず1つ以上の引数を持ちます。また、引数のうち最初のものはselfという名前にすることになっています。

メソッドを呼び出し。

インスタンス.メソッド名()

class Test:

    def test_print(self):
        print('This is test')

test = Test()      #インスタンス生成
test.test_print()  #メソッド呼び出し

実行結果

This is test


以下のコードは、生成したインスタンスを使って”methodName”という名前のメソッドを
呼び出したものです。

>>> class className():
       def methodName(self):
           print("Hello World")
>>> instance =className()
>>> instance.methodName()

こちらを実行すると、

Hello World

と表示されました。 ここで記述したメソッドの引数として、“self”が登場します。


selfとは?

上述のように、クラスの中のコンストラクタやメソッドには、selfというものが存在します。
このselfは、インスタンス自身を示すものです。 また、selfはpythonの設計仕様で欠かすことはできません。
なお、名前を”self”以外のキーワード(例えば、myselfなど)にすることは可能ですが、慣例としてselfを使用しています。
pythonでは作成されたコードを後から読む人が、どのように実装されているかが一目でわかるように書く事が重要である為、基本的には”self”とするのが良いでしょう。
以降では、selfがどのように使われるかを確認します。

selfの使い方

インスタンス変数として参照する

まずはじめに、コンストラクタで使用する例を見てみましょう。
pythonにおけるコンストラクタは”__init__”と表記します。

class className():
    def __init__(self, strA, strB):
        self.strA = strA
        self.strB = strB
test = className("Hello", "World!")
print(test.strA)
print(test.strB)

 class className():
    def __init__(self, strA, strB):
        self.strA = strA
        self.strB = strB

test = className("Hello", "World!")
print(test.strA)
print(test.strB)

このように実装すると、以下のような結果を得られます。

Hello
World!

このように、インスタンスを生成する際に引数を渡すと、selfを使ってインスタンス変数として代入する事ができます。
この時に確認していただきたい点は、selfはインスタンス自身を示すものなので、呼び出す側は引数として値を入れない事です。
また、”__init__”のように__で囲まれた関数や変数は特殊な機能をもったものです。
発見したら注意しましょうね。


クラス変数として参照する
また、以下のようにクラス変数として別メソッドでも使う事ができます。

class className():
    def __init__(self, strA, strB):
        self.strA = strA
        self.strB = strB
   
    def output(self):
        print(self.strA)
        print(self.strB)

test = className("Hello", "World!")
test.output()



実行結果は、先ほどと同様です。

クラス継承の際も使える

selfはクラス変数として参照する事ができるので、クラスを継承した際にも参照する事ができます。

class classA():
    def __init__(self):
        self.strA = "Hello World!"
class classB(classA):
    def output(self):
        print(self.strA)
test = classB()
test.output()



実行結果:

Hello World!


selfの注意点
一点だけselfで注意していただきたい点があります。
以下のコードをご確認ください。

# -*- coding: utf-8 -*-
class cls():
    strA = "Hello python"
    def __init__(self):
        print("1: " + self.strA)
        self.strA = "Hello World!"
        print("2: " + self.strA)
        strA = "Hello python"
        print("3: " + self.strA)
test = cls()


これらを実行すると、何が表記されると思いますか?
実行結果は以下になります。

1: Hello python
2: Hello World!
3: Hello World!


予想に反した結果だと思った方も多いのではないでしょうか?
まず1について、”self.strA”はクラス内で定義したクラス変数”strA”と同じ意味を持っている為、参照エラーとはなりません。
続いて2について、こちらはインスタンス変数として”self.strA”が代入されたので、このような結果となります。
そして3番、こちらは最後に代入された”Hello Python”が表示されない点に疑問を感じられませんか?
実はこれ、pythonの仕様なのです。
pythonは、クラス変数もインスタンス変数も”self.変数名”という表記で参照できるのですが、
クラス変数にもインスタンス変数にも値がある場合は、インスタンス変数を優先して参照します。





コンストラクタとデストラクタ
メソッドの中でも、インスタンスが生成されるときに自動的に呼び出されるメソッドのことをコンストラクタと言います。コンストラクタを定義するには「init」という名前のメソッドを作成します。

class Test:
    def __init__(self, 引数1, 引数2, ….):
        #コンストラクタの定義

initも必ずselfという引数が必要になります。それ以外にも引数をつけることができ、その引数はインスタンスを生成する際にクラスを呼び出す時の引数が渡されます。

class Test:
    def __init__(self, num):
        self.num = num;  #このクラスが持つ「num」変数に引数を格納
    def print_num(self):
        print('引数で渡された数字は{}です。'.format(self.num))

test = Test(10)   #ここで渡された引数が__init__のnumに渡される
test.print_num()

実行結果

引数で渡された数字は10です。



コンストラクタとは逆に、インスタンスが不要になり削除される時に呼ばれるメソッドをデストラクタと言います。デストラクタは「del」という名前のメソッドで定義されます。

class Test:
    def __init__(self):
        print('コンストラクタが呼ばれました')
    def __del__(self):
        print('デストラクタが呼ばれました')

test = Test()  #インスタンスを生成
del test      #インスタンスを削除

実行結果

コンストラクタが呼ばれました
 デストラクタが呼ばれました

継承
Pythonのクラスも他のクラスを継承し、拡張することができます。クラスを継承する場合はクラス文に親となるクラスを指定します。親のクラスのメソッドを呼び出す場合はsuper()を使います。

class Test:
    def __init__(self, num):
        self.num = num;
    def print_num(self):
        print('引数で渡された数字は{}です。'.format(self.num))

class Test2(Test):  #Testクラスを継承
    def print_test2_info(self):
        print('このクラスはTestクラスを継承しています。')
        super().print_num()  #親クラスのprint_num()を呼び出す
test = Test2(10)
test.print_test2_info()

実行結果

このクラスはTestクラスを継承しています。
 引数で渡された数字は10です。

 シェルスクリプトで実行する特殊メソッド __repr__
•呼び方: レパー
•備考 : シェルスクリプトのみで実行可能なコード
 class Length():
    def __init__(self, data):
        self.data = data
    def __repr__(self):
        return "Length(%s, %s) " % (len(self.data), id(self))
    def __str__(self):
        return "Length(%s) " % (len(self.data))

>>> l = Length([1,2,3])
>>> l
実行結果:確認要
>>> print(l)
実行結果:確認要

__init__(self)__repr__(self) の例

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

0 件のコメント:

コメントを投稿