

Python 3.4.3を利用しています。

モジュールを自作する中でクラスのインスタンスメソッドの共通の処理を切り出して、他のインスタンスメソッドにしているのですが、後者のインスタンスメソッドは前述のインスタンスメソッド以外に呼び出されないようにしたいです(あるいは、コードを見たときに前述のインスタンスメソッドにしか使わないことがわかるようにしたい)

[code]

    class testclass:
        def __init__(self):
            pass
    
        def get_power_two(self, number):  # 2のnumber乗を返す
            answer = 1
            for i in range(0, number):
                answer = self.twice(answer)
            return answer
    
        def twice(self, answer):  # get_power_two以外からは呼び出されない
            return 2*answer
    
    A = testclass()
    print(A.get_power_two(4))  # 16
    A.twice(2)  # これがエラーになってほしい
    
[/code]

上記のコードでは、`get_power_two()`の処理の一部を`twice()`というインスタンスメソッドに切り出していますが、これは`A.twice(2)`と呼び出せてしまいます。
このメソッドが、同じクラス内のメソッド以外から呼び出されない、あるいは呼び出されるべきでないことを明らかにしたいのですが、うまい方法はないでしょうか?  
よろしくお願いします。


CC BY-SA 3.0
2016-08-10T07:52:49.627
28172
2016-08-20T13:12:18.423
18436
question
python
クラス内からしか呼び出さないメソッドを明示する方法はないでしょうか?


メソッド名を `_twice` にしましょう。  
Pythonでは、外から使って欲しくないことを表明するために `_` を付けます。  
それを無視して使われる可能性はありますが、それは使う方の責任ですね。

`__` を付ける方法もありますが、不自由になりすぎるのでお勧めしません。


CC BY-SA 3.0
2016-08-10T09:11:57.293
28174
2016-08-10T09:11:57.293
806
28172
answer


`_`(single-underscore) や `__`(double-underscore) の様な `internal use indicator`
を利用する以外に `decorator` と `inspect` を使う方法を挙げておきます。

[code]

    def local_method(m):
      import inspect, functools
      @functools.wraps(m)
      def lm(self, answer):
        cls = self.__class__
        caller = inspect.stack()[1][0].f_locals
        if 'self' in caller and cls == caller['self'].__class__:
          return m(self, answer)
        raise Exception("Cannot call `{0}' method outside `{1}' class."
                        .format(m.__name__, cls.__name__))
    
      return lm
    
    class testclass:
            :
    
      @local_method
      def twice(self, answer):
        return 2*answer
    
[/code]

ただし、`self` を参照しているので、`testclass` 内の `classmethod` や `staticmethod`
から呼ばれる場合にはエラーになります。

[code]

    class testclass:
            :    
    
      @classmethod
      def class_method(cls):
        cls().twice(10)       // エラー
    
      @staticmethod
      def static_method():
        testclass().twice(10) // エラー
    
[/code]


CC BY-SA 3.0
2016-08-10T17:42:52.677
28186
2016-08-10T18:01:21.643
2016-08-10T18:01:21.643
28172
answer


関数内で関数を定義することもできます：

[code]

    class testclass:
        def __init__(self):
            pass
    
        def get_power_two(self, number):  # 2のnumber乗を返す
            def twice(answer):
                return 2 * answer
    
            answer = 1
            for i in range(0, number):
                answer = twice(answer)
            return answer
    
[/code]

`twice` は `get_power_two` 以外からはアクセス不可能です。


CC BY-SA 3.0
2016-08-20T13:12:18.423
28395
2016-08-20T13:12:18.423
565
28172
answer