

Javaではstaticメソッドはオーバーライドできないとされています。  
たとえば、以下のようなコードはオーバーライドではないとされています。  
(オーバーライドではなく、隠蔽(hiding)であるとされる)

[code]

    class A {
        public static void a() { 
            System.out.println("A.a()");
        }
    }   
    
    class B extends A {
        public static void a() {
            System.out.println("B.a()");
        }
    }
    
[/code]

  * [Overriding static methods in java](https://stackoverflow.com/questions/16617408/overriding-static-methods-in-java)
  * [Javaのドキュメンテーション](http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html)

* * *

一方、Pythonで似たようなコードを書いてみます。

[code]

    class A(object): 
        @staticmethod
        def a():
            print("A.a()")
    
    class B(A):
        @staticmethod
        def a():
            print("B.a()")
    
[/code]

これはオーバーライドなのでしょうか?

**質問:**

  * 上記のPythonコード例はオーバーライドと考えるべきか否か? その判断の根拠は?
  * staticmethodではなく、classmethodや普通のメソッドの場合は?
  * 一般に動的言語でどう考えるべきか? 


CC BY-SA 3.0
2014-12-22T07:56:06.183
2373
2014-12-24T17:53:07.300
2017-05-23T12:38:55.250
-1
848
question
java python
Pythonのメソッドはオーバーライドされているのか


ちょっと乱暴な回答になりますが、より良い回答がつくまでのつなぎにどうぞ。

> 上記のPythonコード例はオーバーライドと考えるべきか否か? その判断の根拠は?

考えて良いでしょう。以下のコードでは、ベースクラス `A` にスタティックメソッド `a()` を呼び出すインスタンスメソッド `call_a()`
を追加し、`B` のインスタンスの `call_a()` を呼んだ時、`B.a()` が実行されています。これが根拠です。

[code]

    class A(object): 
        @staticmethod
        def a():
            print("A.a()")
    
        def call_a(self):
            self.a()
    
    class B(A):
        @staticmethod
        def a():
            print("B.a()")
    
    p = B()
    p.call_a()    # B.a()
    
[/code]

> staticmethodではなく、classmethodや普通のメソッドの場合は?

`classmethod` については同様の方法で実験してみてください。 普通のメソッドについては、当然オーバーライドとみなせます。

> 一般に動的言語でどう考えるべきか?

OOP の基本に立ち返ると「オーバーライドができる」というのは、 「あるメッセージに対する既存の振る舞いを変更=上書きできる」ということです。

最初の例はまさにそれを確認する作業で 仮に `call_a()` がBのインスタンスに対しても `A.a()` を呼び出すようならば、
これは振る舞いを変更できなかったことになるので、 オーバーライドできていないとなるわけです。


CC BY-SA 3.0
2014-12-22T09:10:12.953
2377
2014-12-22T09:10:12.953
208
2373
answer


オーバーライドとはメソッドを置き換えて動作をカスタマイズすることで、ハイディングとは、クラスに限らず、広いスコープの名前より狭いスコープの名前が優先され、通常の方法では広いスコープ側を参照できなくすることです。

Java のサンプルコードがオーバーライドでないのは、次のような場合に B クラスの a メソッドが呼ばれず、カスタマイズに失敗しているからです。

[code]

    class A {
        public static void a() { 
            System.out.println("A.a()");
        }
        public static void b() {
            a();
        }
    }   
    
    class B extends A {
        public static void a() {
            System.out.println("B.a()");
        }
    }
    
    B.b();  // -> A.a() が表示される
    
[/code]

一方、このコードがハイディングになっているのは、 B クラス内で普通に `a()` を呼び出した時に `A.a()` ではなく `B.a()`
が呼ばれるようになっているからです。

Python の staticmethod の場合だと、 KoRoN さんの例ではカスタマイズに成功しているのですが、 `call_a()` を
staticmethod にした場合にカスタマイズに失敗しています。なので、これがオーバーライドになっているかどうかは `a()` の呼び出し方によります。

[code]

    class A(object): 
        @staticmethod
        def a():
            print("A.a()")
    
        @staticmethod
        def call_a():
            A.a()
    
    class B(A):
        @staticmethod
        def a():
            print("B.a()")
    
    p = B()
    p.call_a()    # A.a()
    
[/code]

一方、 Python の classmethod の場合、呼び出し元が classmethod でもカスタマイズに成功していて、なおかつあえて
staticmethod ではなく classmethod を利用しているのはカスタマイズを可能にする目的があるので、完全にオーバーライドと呼べるでしょう。

このように、「オーバーライドかハイディングか」は、カスタマイズを目的としているか否かで判断するのが良いと思います。

余談ですが、次のような場合は明確にオーバーライドではなくハイディングです。

[code]

    x = 3
    
    def a(x):
        print x
    
    a(5)  # 5
    
[/code]


CC BY-SA 3.0
2014-12-24T01:30:23.357
2452
2014-12-24T17:53:07.300
2014-12-24T17:53:07.300
208
3019
2373
answer