2016-06-22 9 views
1

intとして:のPython:再バインド機能Iは、テストクラスを持っている

class TestClass: 
    def someFunction(self, someInt): 
     self.i = someInt 
     return self.i 

し、それをテストしていた。

x = MyClass() 
x.someFunction = 3 
print(x.someFunction) 
x.someFunction(4) 

しかし、これはTypeError: 'int' object is not callableにつながります。なぜ私はこのエラーが発生しているのか理解しています。someFunctionは整数(この場合は3)にリバウンドされています。整数は関数ではないため、someFunctionはもはや呼び出し可能ではありません。しかし、メンバーの機能がまるでデータメンバーのようにリバウンドできるようにするのはどういう理由があるのだろうか?偶発的なエラーが発生するようです。私はちょうどPythonを学び始め、Pythonの基本的な側面が見当たらないと感じています。

+6

メソッドは単に呼び出し可能な属性です。それでおしまい。 Pythonは非常に動的な言語であり、名前(属性名を含む)は型付けされていません。 – jonrsharpe

+0

通常、関数の名前は変数名とは十分に異なり、リスクが最小限に抑えられています。例えば、あなたの関数は 'someFunction'と呼ばれます。誤って値を割り当てようとすることはほとんどありません。 –

答えて

1

これが理由属性検索はPythonで動作する方法を許可し、これは仕様によるものです。 Pythonでは、他の言語では推奨されない、禁じられている、または不可能な多くの事柄がユースケースを活用することができます(賢明に使用される場合)。もちろん、より多くのパワーは、より多くの責任を意味します。

After all, we're all consenting adults here.

クラスのインスタンスは、すべてのオブジェクト属性が格納されている空の__dict__属性で始まる属性解像度のいくつかの背景情報。x.someFunctionにアクセスすると、暗黙のうちにx.__dict__['someFunction']が試行されます。 'someFunction'x.__dict__に存在しない場合は、type(x).someFunction以上のtype(x).__dict__['someFunction']のように、xのクラスに対しても同じことが試されます。

を書いてx.someFunction = 3とすると、実際に何が起こるかは、読書属性のアクセスが何を返すかにかかわらず、x.__dict__['someFunction'] = 3です。

のみ実際の(?)マジックselfが自動的に提供されたメソッドの呼び出し中に発生し、すなわちx.someFunction(4)type(x).__dict__['someFunction'](4)代わりに又はx.__dict__['someFunction'](4)type(x).__dict__['someFunction'](x, 4)に解決されます。これは属性へのアクセスに多少の関係があり、混乱を招く可能性があります。

実際には関数を「再バインド」しませんが、クラス属性someFunctionをインスタンス属性someFunctionxで非表示にします。実行した場合、

print(MyClass.someFunction) 
print(MyClass().someFunction) 

が表示されます。あなたも

del x.__dict__['someFunction'] 

注意して初期状態に戻すことができます。私は、解像度として説明物事は概念を説明します。実際には、Pythonの内部動作はより微妙で複雑かもしれませんが、同じ効果があります。例えば、Python 2では、メソッドは、というバインドされていないメソッドとしてラップされています。がクラス辞書に格納されています。 This has been dropped in Python 3ここで、クラス辞書にはプレーン関数が含まれています。

+0

このメーリングリストの投稿をリンクしていただきありがとうございます(たとえ私がその哲学に100%同意しない場合でも) – Sebastian

+0

@セバスチャン他の哲学と他の言語が利用可能です! – jonrsharpe

0

Pythonシェルであなたのデモのコードを実行してください:

>>> class TestClass: 
...  def someFunction(self, someInt): 
...   self.i = someInt 
...   return self.i 
... 
>>> x = TestClass() 
>>> x.someFunction = 3 
>>> print(x.someFunction) 
3 
>>> x.someFunction(4) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'int' object is not callable 

以下の内容をご参照ください:

>>> type(x.someFunction) 
<type 'instancemethod'> 
>>> x.someFunction = 3 
>>> type(x.someFunction) 
<type 'int'> 

あなたがx.someFunction = 3をしようとすると、instancemethodx.someFunctionがに変換caled int。ファーストクラスは、

  • や変数が入力されていないオブジェクトとしてPythonで

  • +1

    OPは質問を読むことから明らかなように、*起こっていることを知っています - 彼らはなぜそれが許可されているのか知りたいです*。 – jonrsharpe

    +1

    http://stackoverflow.com/questions/972/adding-a-method-to-an-existing-object-instance –

    0

    • 機能がthreatedれます。

    「まったくオブジェクトです」というのは、Pythonでのことです。したがって、整数を含む変数と関数を含む変数の基本的な違いはありません。ファーストクラスの関数と型なしの変数の両方には独自の長所と短所がありますが、単純に、整数、文字列、その他のオブジェクトと関数を含むリストを作成します。

    0

    関数変数に何かを割り当てることができるのは、それらがオブジェクトとして実装されているからです。これにより、C言語と異なり、関数を引数として返すことができます。

    この機能の有用性は、「偶発的なエラー」をはるかに上回ります。

    はたとえば、あなたはこのような何かを行うことができます。

    # some code 
    
    def sum(a, b): 
        return a+b 
    
    def product(a, b): 
        return a*b 
    
    def ret_func(str): 
        if str=='add': 
         func = sum 
        elif str=='multiply': 
         func = product 
        return func 
    
    addition_result = ret_func('add')(x, y) 
    multiplication_result = ret_func('multiply')(x, y) 
    
    # some more code 
    
    関連する問題