yoshiislandblog.net
元営業の駆け出しアラサーSEが、休日にMACと戯れた際の殴り書きメモ。日々勉強。日々進歩。

Pythonで、グローバル変数、インスタンス変数、ローカル変数のスコープをざっくり理解する〜オブジェクト指向でなぜつくるのかを読んで〜

2021-01-17

オブジェクト指向でなぜつくるのか 第2版という本を読んでいて、変数のスコープについて調べるためにPythonを実際に動かしてみたので結果メモ

オブジェクト指向でなぜつくるのか 第2版

オブジェクト指向でなぜつくるのか 第2版

  1. 「グローバル変数」「インスタンス変数」「ローカル変数」の定義
  2. グローバル変数のスコープを確認する
  3. インスタンス変数のスコープを確認する
  4. ローカル変数のスコープを確認する
  5. 確認コード全体

「グローバル変数」「インスタンス変数」「ローカル変数」の定義

グローバル変数」「インスタンス変数」「ローカル変数」の定義は以下の通り

  • グローバル変数:プログラムのどこからでも使える変数
  • インスタンス変数:クラス内でのみ使える変数
  • ローカル変数:メソッド内でのみ使える変数
  • 近年のオブジェクト指向プログラミングでは、一度作成されたコードが使われる寿命が長くなったことから、「保守性」を重視しているため、
    インスタンス(クラス)の独立性を高めるために、グローバル変数をなるべく減らすのが良いコードらしい

    20210117_python_vars

    グローバル変数のスコープを確認する

    グローバル変数は、プログラムのどこからでもアクセスできる変数

    定義する時は、クラスの外で以下のように記載するだけ

    global_var = "global_var"
    

    クラスの中で使う時は、以下のようにglobalと頭につけて、使う宣言をする
    (これをしなくても動いてしまうこともあるがつけておく)

    global global_var
    

    まとめるとこんな感じになる

    global_var = "global_var"  # global変数作成
    
    class TestClass ():
        global global_var  # global変数をこのクラス内で使う宣言
    

    インスタンス変数のスコープを確認する

    インスタンス変数はインスタンス(クラス)の中でのみ使う変数
    通常、コンストラクタの中で「self」という文言とともに定義をする(selfはインスタンス自身のこと、selfでなくても良いらしいが慣習的にself)

    インスタンス(クラス)内であれば、何回でも使える

    class TestClass ():
    
      # constractor
      def __init__(self):
        self.instance_var = "instance_var"  # instance変数作成
    
      def TestDef1(self):
        return self.instance_var  #ここでも使える
    
      def TestDef2(self):
        return self.instance_var  #ここでも使える
    

    ローカル変数のスコープを確認する

    ローカル変数は、メソッドの中で使う変数
    defの塊の中で定義して、defの塊の中でのみ使える

    class TestClass ():
    
      def TestDef1(self):
        local_var = "local_var1"  # local変数作成
        return local_var   # 中身は"local_var1"
    
      def TestDef2(self):
        local_var = "local_var2"  # local変数作成
        return local_var  # 上のlocal_varとは別物、中身は"local_var2"
    

    参考:PythonのClassとConstractorとMethodをざっくり理解する
    参考:メソッド・def・インスタンスってなに?
    参考:Pythonの中でよくみる「def」から始まる塊について、用語が紛らわしいので整理する

    確認コード全体

    確認コード全体

    % cat test.py
    #!/usr/bin/env python
    # coding: utf-8
    
    
    # global変数を定義する
    global_var = "global_var"
    
    
    class TestClass ():
    
      # global変数をクラス内で使う宣言
      global global_var
    
      # Constractor
      # 通常インスタンス変数はコンストラクタ内で定義する
      def __init__(self):
        # instance変数
        self.instance_var = "instance_var"
    
    
      def TestDef1(self):
        # local変数
        local_var = "local_var1"
        return local_var
    
    
      def TestDef2(self):
        # local変数
        local_var = "local_var2"
        # メソッド内からlocal変数にアクセスする
        print("Here is Testdef2. local var is %s." % local_var)
        # メソッド内からinstance変数にアクセスする
        print("Here is Testdef2. instance var is %s." % self.instance_var)
        # メソッド内からglobal変数にアクセスする
        print("Here is Testdef2. global var is %s." % global_var)
    
    
      def TestDef3(self):
        return self.instance_var
    
    
      def TestDef4(self):
        return global_var
    
    
    # 出力結果成形用の関数
    def PrintTitle(title):
      line = "===================="
      print("%s\n%s\n%s" % (line,title,line))
    
    
    # Execution
    if __name__ == "__main__":
    
      # クラス(設計図)を使うために具現化(インスタンス化)
      TestClass = TestClass()
    
      PrintTitle("ローカル変数をreturnしてクラス外で使う(TestDef1)")
      print(TestClass.TestDef1())
    
      PrintTitle("各変数をメソッド内で使う(TestDef2)")
      print(TestClass.TestDef2())
    
      PrintTitle("インスタンス変数をreturnしてクラス外で使う(TestDef3)")
      print(TestClass.TestDef3())
    
      PrintTitle("グローバル変数をreturnしてクラス外で使う(TestDef4)")
      print(TestClass.TestDef4())
    
      PrintTitle("ローカル変数はクラス外では使えない")
      try:
        print(local_var)
      except NameError as err:
        print("OS error: {0}".format(err))
    
      PrintTitle("インスタンス変数はクラス外では使えない")
      try:
        print(instance_var)
      except NameError as err:
        print("OS error: {0}".format(err))
    
      PrintTitle("グローバル変数はクラス外でも使える")
      try:
        print(global_var)
      except NameError as err:
        print("OS error: {0}".format(err))
    

    出力結果

    % python test.py
    ====================
    ローカル変数をreturnしてクラス外で使う(TestDef1)
    ====================
    local_var1
    ====================
    各変数をメソッド内で使う(TestDef2)
    ====================
    Here is Testdef2. local var is local_var2.
    Here is Testdef2. instance var is instance_var.
    Here is Testdef2. global var is global_var.
    None    # ★TestDef2メソッドにはreturn値が定義されていないのでNoneが返されている
    ====================
    インスタンス変数をreturnしてクラス外で使う(TestDef3)
    ====================
    instance_var
    ====================
    グローバル変数をreturnしてクラス外で使う(TestDef4)
    ====================
    global_var
    ====================
    ローカル変数はクラス外では使えない
    ====================
    OS error: name 'local_var' is not defined
    ====================
    インスタンス変数はクラス外では使えない
    ====================
    OS error: name 'instance_var' is not defined
    ====================
    グローバル変数はクラス外でも使える
    ====================
    global_var
    

    以上