2010-01-29 2 views
112

Можно создать дубликат:
What is a clean, pythonic way to have multiple constructors in Python?Несколько конструкторов в python?

Это не представляется возможным определить несколько конструкторов в Python, с разными подписями? Если нет, каков общий способ обойти это?

Например, предположим, что вы хотите, чтобы определить класс City

я хотел бы быть в состоянии сказать someCity = City() или someCity = City("Berlin"), где первый раз дает значение по умолчанию имя, а второй определяет его.

+2

заставляют меня думать, этот вопрос - http://stackoverflow.com/questions/682504/what-is-a-clean-pythonic-way-to-have-multiple -constructors-in-python – Gant

+0

Лучшее: [Как перегрузить метод '__init__' на основе типа аргумента?] (https://stackoverflow.com/questions/141545/how-to-overload-init-method-based-on- аргумент-тип) –

ответ

143

В отличие от Java, вы не можете определить несколько конструкторов. Однако вы можете определить значение по умолчанию, если оно не передано.

def __init__(self, city="Berlin"): 
    self.city = city 
2

Самый простой путь через именованные аргументы:

class City(): 
    def __init__(self, city=None): 
    pass 

someCity = City(city="Berlin") 

Это довольно основной материал, может быть, посмотреть на the python docs?

+0

опечатки в комментариях; Кроме того, это не вопрос, который он задал - он спросил о включении типов, он просто показал плохие примеры. – pavpanchekha

+1

@pavpanchekha: это именно то, что было задано. кроме, конечно, отсутствующего «самого себя». – SilentGhost

+5

@ Джэк, ваш пример на самом деле не хранит «город» нигде, поэтому новичкам это может быть довольно сложный ответ. –

2

Для примера вы дали, использовать значения по умолчанию:

class City: 
    def __init__(self, name="Default City Name"): 
     ... 
    ... 

В общем, у вас есть два варианта:

1) У if - elif блоков на основе типа:

def __init__(self, name): 
    if isinstance(name, str): 
     ... 
    elif isinstance(name, City): 
     ... 
    ... 

2) Используйте утиную печать, то есть предположите, что пользователь вашего класса достаточно интеллектуальный, чтобы использовать его правильно. Обычно это предпочтительный вариант.

+0

@Ghost Значения по умолчанию .... um ... Наверное, это все. Дело принято. Почему я голосовал за это? Ах, дерьмо, голос слишком стар, чтобы измениться сейчас. –

140

Если ваши подписи отличаются только числом аргументов, используя аргументы по умолчанию является правильный способ сделать это. Если вы хотите иметь возможность передавать разные аргументы , я попытался бы избежать подхода, основанного на isinstance, упомянутого в другом ответе, вместо этого используя аргументы ключевого слова. Если использование только аргументов ключевого слова становится громоздким, вы можете комбинировать его с classmethods (код bzrlib любит этот подход). Это просто глупый пример, но я надеюсь, что вы получите идею:

class C(object): 

    def __init__(self, fd): 
     # Assume fd is a file-like object. 
     self.fd = fd 

    @classmethod 
    def fromfilename(cls, name): 
     return cls(open(name, 'rb')) 

# Now you can do: 
c = C(fd) 
# or: 
c = C.fromfilename('a filename') 

УВЕДОМЛЕНИЕ все эти методы класса еще пройти через то же __init__, но используя методы класса могут быть гораздо более удобно, чем вспомнить, какие комбинации ключевых аргументов до __init__ произведение.

isinstance лучше избегать, так как утка, набрав питона делает его трудно понять, какой объект был фактически принят в Например:., Если вы хотите взять либо имя файла или файла, как объект, который вы не можете использовать isinstance(arg, file) потому что это много файлов-подобных объектов, которые не являются подклассами file (например, те, которые возвращаются из urllib или StringIO, или ...). Как правило, лучше всего просто указать, что вызывающий абонент явно указал вам, какой именно объект имел в виду, используя разные аргументы ключевых слов.

+0

Как вы говорите, это отличный подход, если вам нужно передать разные аргументы. В этих случаях я обычно использую очень простой '__init__' и делаю несколько методов класса для каждого случая. – zekel

+0

это наиболее общеприменимое решение –

2

Jack M.правильно, сделайте это так:

>>> class City: 
...  def __init__(self, city=None): 
...   self.city = city 
...  def __repr__(self): 
...   if self.city: return self.city 
...   return '' 
... 
>>> c = City('Berlin') 
>>> print c 
Berlin 
>>> c = City() 
>>> print c 

>>> 
Смежные вопросы