Методы с тем же именем в одном классе в Python? - PullRequest
41 голосов
/ 22 февраля 2011

Как объявить несколько методов с одинаковыми именами, но с разным количеством параметров или разных типов в одном классе?

Что я должен изменить в этом классе:

class MyClass:
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
    def my_method(self,parameter_A_that_Must_Be_String):
        print parameter_A_that_Must_Be_String

    def my_method(self,parameter_A_that_Must_Be_String,parameter_B_that_Must_Be_String):
        print parameter_A_that_Must_Be_String
        print parameter_B_that_Must_Be_String

    def my_method(self,parameter_A_that_Must_Be_String,parameter_A_that_Must_Be_Int):
        print parameter_A_that_Must_Be_String * parameter_A_that_Must_Be_Int

Ответы [ 9 ]

57 голосов
/ 22 февраля 2011

У вас может быть функция, которая принимает переменное число аргументов.

def my_method(*args, **kwds):
    # do something

# when you call the method
my_method(a1, a2, k1=a3, k2=a4)

# you get: 
args = (a1, a2)
kwds = {'k1':a3, 'k2':a4}

Таким образом, вы можете изменить свою функцию следующим образом:

def my_method(*args):
    if len(args) == 1 and isinstance(args[0], str):
        # case 1
    elif len(args) == 2 and isinstance(args[1], int):
        # case 2 
    elif len(args) == 2 and isinstance(args[1], str):
        # case 3
22 голосов
/ 22 февраля 2011

Вы не можете.Здесь нет перегрузок, мультиметодов или подобных вещей.Одно имя относится к одной вещи.Что касается языка в любом случае, вы всегда можете имитировать их сами ... Вы могли бы проверять типы с помощью isinstance (но, пожалуйста, сделайте это правильно - например, в Python 2, используйте basestring для обнаружениякак строки, так и юникод), но это некрасиво, как правило, не рекомендуется и редко полезно.Если методы делают разные вещи, дайте им разные имена.Также учтите полиморфизм.

5 голосов
/ 22 февраля 2011

Краткий ответ: вы не можете ( см. Предыдущее обсуждение ).Обычно вы используете что-то вроде (вы можете добавить больше проверки типов и переупорядочения):

def my_method(self,parameter_A, parameter_B=None):
  if isinstance(parameter_B, int):
    print parameter_A * parameter_B
  else:
    print parameter_A
    if parameter_B is not None:
      print parameter_B
1 голос
/ 22 февраля 2011

Вы можете попробовать мультиметоды в Python:

http://www.artima.com/weblogs/viewpost.jsp?thread=101605

Но я не верю, что мультиметод - это путь. Скорее объекты, которые вы передаете методу, должны иметь общий интерфейс. Вы пытаетесь добиться перегрузки метода, подобной той, что в C ++, но это очень редко требуется в python. Один из способов сделать это - каскад ifs с использованием isinstance, но это ужасно.

0 голосов
/ 05 июня 2019

Это не может работать.Независимо от того, сколько аргументов у вас есть, имя m будет переопределено вторым методом m.

class C:
    def m(self):
        print('m first')
    def m(self, x):
        print(f'm second {x}')


ci=C();
#ci.m() # will not work TypeError: m() missing 1 required positional argument: 'x'
ci.m(1) # works

Вывод будет простым:

m second 1
0 голосов
/ 01 декабря 2015

Я думаю, что один очень простой пример отсутствует во всех ответах, а именно: что делать, когда единственная разница между вариациями метода - это количество аргументов.Ответ по-прежнему заключается в использовании метода с переменным числом аргументов.

Скажем, вы начинаете с метода, который требует использования двух аргументов

def method(int_a, str_b):
    print("Got arguments: '{0}' and '{1}'".format(int_a, str_b)

, затем вам необходимо добавить вариант спросто второй аргумент (скажем, потому что целое число является избыточным), решение очень простое:

def _method_2_param(int_a, str_b):
    print("Got arguments: '{0}' and '{1}'".format(int_a, str_b))

def _method_1_param(str_b):
    print("Got argument: '{0}'".format(str_b))

def method(*args, **kwargs):
    if len(args) + len(kwargs) == 2:
        return _method_2_param(args, kwargs)
    elif len(args) + len(kwargs) == 1:
        return _method_1_param(args, kwargs)
    else:
        raise TypeError("Method requires one or two arguments")

Хорошая особенность этого решения в том, что независимо от того, использовал ли вызывающий код аргументы из ключевых слов или позиционные аргументы до, он все еще будет работать.

0 голосов
/ 26 октября 2012
class MyClass:
    def __init__(this, foo_str, bar_int):
        this.__foo = foo_str
        this.__bar = bar_int

    def foo(this, new=None):
        if new != None:
            try:
                this.__foo = str(new)
            except ValueError:
                print("Illegal value. foo unchanged.")

        return this.__foo

    def bar(this, new=None):
        if new != None:
            try:
                this.__bar = int(new)
            except ValueError:
                print("Illegal value. bar unchanged.")

        return this.__bar

obj = MyClass("test", 42)
print(obj.foo(), obj.bar())

print(obj.foo("tset"), obj.bar(24))

print(obj.foo(42), obj.bar("test"))

Output:
    test 42
    tset 24
    Illegal value. bar unchanged.
    42 24
0 голосов
/ 22 февраля 2011

Возможно, вам нужен шаблон, подобный следующему: Обратите внимание, что добавление '_' в начало имени метода является условием для пометки частного метода.

class MyClass:
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
    def my_method(self,parameter_A_that_Must_Be_String, param2=None):
        if type(param2) == str:
            return self._my_method_extra_string_version(parameter_A_that_Must_Be_String, param2)
        elif type(param2) == int:
            return self._my_method_extra_int_version(parameter_A_that_Must_Be_String, param2)
        else:
            pass # use the default behavior in this function
        print parameter_A_that_Must_Be_String

    def _my_method_extra_string_version(self,parameter_A_that_Must_Be_String, parameter_B_that_Must_Be_String):
        print parameter_A_that_Must_Be_String
        print parameter_B_that_Must_Be_String

    def _my_method_extra_int_version(self,parameter_A_that_Must_Be_String, parameter_A_that_Must_Be_Int):
        print parameter_A_that_Must_Be_String * parameter_A_that_Must_Be_Int
0 голосов
/ 22 февраля 2011

Python не похож на Java.

На самом деле нет типов, только объекты с методами.

Существует способ проверить, является ли переданный объект из класса, но в основном этоПлохая практика.

Однако код, который вы хотите создать для двух первых методов, должен выглядеть примерно так:

class MyClass(object):
    def my_method(self, str1, str2=None):
        print str1
        if str2: print str2

Для третьего ... ну, используйте другое имя ...

...