Pythonでメソッド呼び出しに()つけ忘れたら変な動きになった話
なんか挙動がおかしかったのでコードを追っかけたらメソッド呼び出しに()がついてなくて、それなのにtry-ExceptionのException側に落ちてなかったのであれっと思って調べた話
サンプルコード
# util class
class utilclass:
# local value
class_value=True
# getter
def get_class_value(self):
return self.class_value
# setter
def set_class_value(self,argv):
self.class_value=argv
# main method
def main():
# instance
myutil = utilclass()
# test-1
print("--- test-1 ---")
print(str(type(myutil.get_class_value())))
print(myutil.get_class_value())
# test-2
print("--- test-2 ---")
myutil.set_class_value(False)
print(str(type(myutil.get_class_value())))
print(myutil.get_class_value())
# test-3
print("--- test-3 ---")
print(str(type(myutil.get_class_value)))
print(myutil.get_class_value)
# test-4
print("--- test-4 ---")
if (myutil.get_class_value):
print("Class Value is True")
else:
print("Calss Value is False")
# call main method
if __name__ == '__main__':
main()
結果
--- test-1 ---
<class 'bool'>
True
--- test-2 ---
<class 'bool'>
False
--- test-3 ---
<class 'method'>
<bound method utilclass.get_class_value of <__main__.utilclass object at 0x785fe4d8a030>>
--- test-4 ---
Class Value is True
各比較
test-1
# test-1
print("--- test-1 ---")
print(str(type(myutil.get_class_value())))
print(myutil.get_class_value())
これに対して
--- test-1 ---
<class 'bool'>
True
こうなっているのでおかしな点は無し
test-2
print("--- test-2 ---")
myutil.set_class_value(False)
print(str(type(myutil.get_class_value())))
print(myutil.get_class_value())
これに対して
--- test-2 ---
<class 'bool'>
False
こうなっているのでこれもおかしな点は無し
test-3
問題はここから
print("--- test-3 ---")
print(str(type(myutil.get_class_value)))
print(myutil.get_class_value)
メソッドを呼び出すのに()をつけないとどうなるか
--- test-3 ---
<class 'method'>
<bound method utilclass.get_class_value of <__main__.utilclass object at 0x785fe4d8a030>>
型はメソッドクラスでオブジェクト番号を参照しているように見える
https://docs.python.org/ja/3.13/tutorial/classes.html#method-objects
これによるとどうやらメソッドオブジェクトというオブジェクト扱いで値(参照というべきか?)が返ってくるようだ
ではこれがif分に渡されるとどうなるかというと次のテスト
test-4
print("--- test-4 ---")
if (myutil.get_class_value):
print("Class Value is True")
else:
print("Calss Value is False")
booleanオブジェクトではないのでTrueやFalseは返してこないと思われる。
ただしboolean型は「整数のサブクラス」なので実際には0かそれ以外かだったような気はするけど資料が見つからず。
https://docs.python.org/ja/3.13/c-api/bool.html
Pythonのif文も"0かそれ以外か"だった気はするのだけれど詳しいことは書かれてなかった。
https://docs.python.org/ja/3.13/reference/compound_stmts.html#the-if-statement
さすがにソースコードまで追いかけるのはめんどかったのでこれを見た誰かがフォローアップ記事を書くかもしれないし書かないかもしれないくらいでお茶を濁しておく。
--- test-4 ---
Class Value is True
結果としては"True"側で判定されている。
何を判定しているかまではちょっとわからなかったが、もし"0かそれ以外か"だと仮定して、オブジェクトのばsy(今回は0x785fe4d8a030)を判定しているのだとすれば一応説明はつくかな、というところ