Pythonでの同じ名前の関数や変数を複数宣言するにはいくつか方法がありますが、呼び出しがどうなるかを把握するためのメモです。
環境はMac OS 15.6.1+Python 3.13.7です。
結論
ローカル変数とグローバル変数
- グローバル変数と同じ名前の関数内ローカル変数を宣言すると、ローカル変数のみアクセス可能
- ネストした関数の内側で外側のローカル変数と同じ名前のローカル変数を宣言すると、内側のみアクセス可能
- ネストした関数の内側でnonlocal宣言すると外側と内側で同じ変数になる
class内の同じ名前のmethod
- instance methodを宣言するとclassmethod, staticmethodは呼べなくなる
- classmethod, staticmethodは後で宣言した方が有効
super()による親クラスの呼び出し
- 関数はMRO順の親クラスになり、菱形継承も問題なく処理できる
- selfやclsは子クラスのまま。親クラスの変数にキャストされない
呼び出された親クラスの関数内でself, clsを使うときに要注意
(提案)定数宣言の関数による代替
- グローバル変数・クラス変数の書き換えを阻止できる
- super()を利用すると親クラスの関数が呼ばれるので、戻る定数値も親クラスの値になる
名前隠しの利点
- 文脈が同じなら同じ名前にできるため、覚える関数名や変数名が少ない
- インターフェイスを揃えれば多態性を利用して複数の処理をまとめられる
- 他の処理からアクセスして欲しくない関数や変数を隠すことができる
名前隠しのやり方
-
関数のネスト
def myfunc(): myvalue = "myfunc_value" def myfunc(): myvalue = "inner_value" print(myvalue)
-
(実用上意味なし)staticmethod, classmethod, instance methodで同じ名前
class myClass: @staticmethod def myfunc(): print("staticmethod") @classmethod def myfunc(cls): print("classmethod") def myfunc(self): print("instance method")
-
(実用上意味なし)staticmethod, classmethodで同じ名前
class myClass: @staticmethod def myfunc(): print("staticmethod") @classmethod def myfunc(cls): print("classmethod")
-
グローバル・クラス・インスタンス・ローカルで同じ名前の変数
myvalue = "global value" class myClass: myvalue = "class value" def __init__(self): self.myvalue = "instance value" def test(self): myvalue = "local value"
-
classの継承によるinstance methodの上書き
class baseclass: myvalue = "base_class value" def myfunc(self): print("base instance method", self.myvalue, self.__class__.myvalue) def __init__(self): self.myvalue = "base instance value" class myclass(baseclass): myvalue = "my_class value" def myfunc(self): print("my instance method", self.myvalue, self.__class__.myvalue) def __init__(self): super().__init__() self.myvalue = "my instance value"
-
classの継承によるclass methodの上書き
class baseclass: myvalue = "base_class value" @classmethod def myfunc(cls): print("base instance method", cls.myvalue) def __init__(self): self.myvalue = "base instance value" class myclass(baseclass): myvalue = "my_class value" @classmethod def myfunc(cls): print("my instance method", cls.myvalue) def __init__(self): super().__init__() self.myvalue = "my instance value"
検証結果
- 関数をネストすると内側の変数が参照される
内側でnonlocal宣言すると「外と同じ名前で別の変数」を使えなくなるdef myfunc(): myvalue = "myfunc_value" def myfunc(): myvalue = "inner_value" print(myvalue) # inner_value myfunc()
- instancemethodを宣言すると同名のstaticmethod, classmethodは呼べなくなる
myfunc() # global method x = myClass() x.myfunc() # insance method x.__class__.myfunc() # Error myClass.myfunc() # Error
- 同名のstaticmethod, classmethodは後のものが有効
class myClass0: @staticmethod def myfunc(): print("static method") @classmethod def myfunc(cls): print("class method") class myClass1: @classmethod def myfunc(cls): print("class method") @staticmethod def myfunc(): print("static method") myClass0.myfunc() # class method myClass1.myfunc() # static method
- globalと関数内localで同じ名前の変数を宣言すると、localしか呼べない
myvalue = "global value" class myClass: myvalue = "class value" def __init__(self): self.myvalue = "instance value" def test(self): myvalue = "local value" print(myvalue) # local value print(self.myvalue) # instance value print(self.__class__.myvalue) # class value x = myClass() x.test()
- super()を使っても、呼び出し先のselfの中身は子クラス
class myclass(baseclass): ... def test(self): print(super().myvalue) print(super().myfunc()) x = myclass() # base_class value x.test() # base instance method, my instance value, my_class value
- super()を使っても、呼び出し先のclsの中身は子クラス
class myclass(baseclass): ... def test(self): print(super().myvalue) print(super().myfunc()) x = myclass() # base_class value x.test() # base instance method, my_class value