with - upper python




Múltiplos construtores em python? (4)

Duplicata Possível:
O que é uma maneira limpa e python de ter múltiplos construtores em Python?

Não é possível definir vários construtores em Python, com assinaturas diferentes? Se não, qual é a maneira geral de contornar isso?

Por exemplo, digamos que você queria definir uma classe City

Eu gostaria de poder dizer someCity = City() ou someCity = City("Berlin") , onde o primeiro apenas fornece um valor de nome padrão e o segundo define.


A maneira mais fácil é através de argumentos de palavras-chave:

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

someCity = City(city="Berlin")

Isso é bastante básico, talvez veja os documentos em python ?


Ao contrário do Java, você não pode definir vários construtores. No entanto, você pode definir um valor padrão se um não for passado.

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

Para o exemplo que você deu, use os valores padrão:

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

Em geral, você tem duas opções:

1) Faça if - elif blocos baseados no tipo:

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

2) Use a tipagem de pato - isto é, suponha que o usuário da sua classe seja inteligente o suficiente para usá-lo corretamente. Esta é tipicamente a opção preferida.


Se as suas assinaturas diferem apenas no número de argumentos usando argumentos padrão, é o caminho certo para fazê-lo. Se você quiser ser capaz de passar em diferentes tipos de argumento eu tentaria evitar a abordagem baseada em isinstance mencionada em outra resposta, em vez disso, usando argumentos de palavra-chave. Se usar apenas argumentos de palavra-chave torna-se pesado, você pode combiná-lo com métodos de classe (o código bzrlib gosta dessa abordagem). Este é apenas um exemplo bobo, mas espero que você entenda:

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')

Observe que todos esses métodos de classe ainda passam pelo mesmo __init__ , mas o uso de métodos de classe pode ser muito mais conveniente do que ter que lembrar quais combinações de argumentos de palavra-chave a __init__ funcionam.

É melhor evitá-lo porque a tipagem de pato do python torna difícil descobrir em que tipo de objeto foi realmente passado. Por exemplo: se você quer pegar um nome de arquivo ou um objeto tipo arquivo você não pode usar isinstance(arg, file) há muitos objetos semelhantes a arquivos que não são file subclasse (como aqueles retornados de urllib, ou StringIO, ou ...). Geralmente, é uma idéia melhor fazer com que o chamador lhe diga explicitamente que tipo de objeto foi usado, usando diferentes argumentos de palavra-chave.





constructor