2012-03-15 9 views
6

パラメータ化されていないメソッドfirstを呼び出す必要がありますが、パラメータ化されたfirstも必要ですが、エラーが発生しています。メソッドがPythonでオーバーロードされる

>>> class A: 
...  def first(self): 
...    print 'first method' 
...  def first(self,f): 
...    print 'first met',f 
... 
>>> a=A() 
>>> a.first() 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: first() takes exactly 2 arguments (1 given) 

JavaのようにPythonでメソッドのオーバーロードを実行することはできますか?

+1

* *オブジェクトから継承して下さい!あなたは本当に古いスタイルのクラスを望んでいないのですか? (これはPython 3では問題ではありませんが、printステートメントはPython 2を使っていると伝えています) –

答えて

9

第2のfirstメソッドは、元のfirstメソッドをオーバーライドしています。 Pythonでは、Javaと同じ方法でオーバーロードされたメソッドを作成することはできません。

ただし、オプションまたはキーワードベースの引数を使用してメソッドを作成し、それに応じてメソッドを処理できます。ここでは例です:

class A: 
    def first(self, f=None): 
     if f is not None: 
      print 'first met', f 
     else: 
      print 'first method' 

は使用方法:

a = A() 
a.first() 
a.first('something') 
+2

うん。 Pythonのデフォルトの引数スタイルは実際にはより簡潔であり、引数の数を減らしてオーバーライドされたメソッドのJavaスタイルの巨大なリストを読みやすく維持するのが簡単です。 –

0

PythonはC++やJavaではありません。同じ方法でメソッドをオーバーロードすることはできません。

は本当に、あなたがやりたいための唯一の方法は、二番目のパラメータの有無をテストすることです:

class A: 
    def first(self, f=None): 
     if f is None: 
     print 'first method' 
     else: 
     print 'first met',f 

あなたはまだ、より洗練されたことができ、fの種類を確認するが、それはすることができ危険であり、常に「ピジョンソニック」ではない。 (ただし、Python 3のfunction annotationsのユースケースの1つは、この種の「汎用プログラミング」を許可することです)。

0

オーバーロードされたメソッドを使用するように見えるシステムを作成することは可能ですが、関与し、通常は必要ではありません。

通常のイディオムがそうのように、Noneにおそらく不要なパラメータのデフォルト値を持つことです:あなたはかどうか、この基づいて異なる振る舞いをしたいあなたのケースでは、

class A: 
    def first(self, f=None): 
     if f is None: 
      print 'first method' 
     else: 
      print 'first met',f 

は、そのメソッドの最初の呼び出しで、これは私がどうなるのかです:

class A: 
    def first(self): 
     print 'first method' 
     self.first = self._first 
    def _first(self, f):     # '_' is convention for private name 
     print 'first met',f 

とサンプル出力:

a = A() 
a.first() 
a.first(3) 

プリント:

first method 
first met 3 
5

Pythonは関数のオーバーロードを行いません。これは、疎結合型言語の結果です。その代わりに、未知数の引数を指定して、関数論理でその解釈を扱うことができます。

これを行うにはいくつかの方法があります。あなたは、特定のオプションの引数を指定することができます。

def func1(arg1, arg2=None): 
    if arg2 != None: 
     print "%s %s" % (arg1, arg2) 
    else: 
     print "%s" % (arg1) 

は、我々が得るそれを呼び出す:

>>> func1(1, 2) 
1 2 

それとも、すなわち(無名の引数の未知の数を指定することができます配列に渡される引数):

>>> func2(1, 2, 3, 4, 5) 
2 
3 
4 
5 

それとも、名前付き引数の辞書に渡された(すなわち引数)の未知の数を指定することができます:

def func3(arg1, **args): 
    if args: 
     for k, v in args.items(): 
      print "%s %s" % (k, v) 
    else: 
     print arg1 

def func2(arg1, *args): 
    if args: 
     for item in args: 
      print item 
    else: 
     print arg1 

は、我々が得るそれを呼び出します

電話してください:

>>> func3(1, arg2=2, arg3=3) 
arg2 2 
arg3 3 

これらの構造を使用して、オーバーロードで探していた動作を生成できます。

+1

あなたの 'func1()'は 'func1(1、0)'と呼ばれるときに呼び出されるかもしれないので動作しません。 – bgporter

+0

ああ、良いキャッチです。変更を加えました。 – cjm

3

通常、指定された名前のクラスには1つのメソッドしか定義できません。あなたの例では、2つの引数のfirst()メソッドは1つの引数first()を上書きします。同じ名前の2つのメソッドが必要な場合は、python 3でfunctools.singledispatchを使用し、インスタンスメソッド名を静的メソッドディスパッチャーOuch!にマップする必要があります。言っ

、私は本当にオブジェクト指向プログラミングにおける暗黙の動的ディスパッチが好きで、私は最初の「マスター」のいくつかの種類に拡張に繰り返して脆い()関数を、手動ディスパッチロジックを書くよりも、それはきれい見つけます。

質問:A.first(A arg)のような別のメソッドを追加してください。

あなたがこれをしようとすると、おそらく多くのPython型システムについて学ぶでしょう!

#!/opt/local/bin/python3.4 

from functools import singledispatch; 

class A(object): 

    # default method handles dispatch for undefined types 
    # note reversed positional args to match single dispatch functools 
    @singledispatch 
    def _first(arg, self): 
     raise TypeError("no match for A._first(%s)" % type(arg)); 

    # adapter maps instance call to (reversed) static method call 
    def first(self, arg = None): return A._first(arg, self); 

    # def first() 
    @_first.register(type(None)) 
    def _(none, self): 
     print("A.first() called"); 

    # def first(float f) 
    @_first.register(float) 
    def _(f, self): 
     print("A.first(float %s) called" % f); 

a = A(); 
a.first();    # A.first() called 
a.first(None);   # A.first() called 
a.first(3.14);   # A.first(float 3.14) called 

class B(object): pass; 
b = B();     
try: a.first(b);  # no match for A._first(<class '__main__.B'>) 
except TypeError as ex: print(ex); 
+0

あなたはいいです!良い例 – madjardi

+0

ああ、それは賢い* :-) –

1

チェックこのコードを、それが役に立つ場合:

from math import pi 

class Geometry: 

    def area(self,length = None,breadth = None,side = None,radius = None): 
     self.length = length 
     self.breadth = breadth 
     self.side = side 
     self.radius = radius 

     if length != None and breadth != None: 
      return length * breadth 
     elif side != None: 
      return side * side 
     else: 
      return pi * radius * radius 

obj1 = Geometry() 
print('Area of rectangle is {0}.'.format(obj1.area(length=5,breadth=4))) 
print('Area of square is {0}.'.format(obj1.area(side=5))) 
print('Area of circle is {0:.6}.'.format(obj1.area(radius=10))) 
関連する問題