ChatGPT解决这个技术问题 Extra ChatGPT

Is it not possible to define multiple constructors in Python? [duplicate]

This question already has answers here: Closed 12 years ago.

Possible Duplicate: What is a clean, pythonic way to have multiple constructors in Python?

Is it not possible to define multiple constructors in Python, with different signatures? If not, what's the general way of getting around it?

For example, let's say you wanted to define a class City.

I'd like to be able to say someCity = City() or someCity = City("Berlin"), where the first just gives a default name value, and the second defines it.

Make me think of this question - stackoverflow.com/questions/682504/…
This question is misleading based on the relation of the title and the body. Worse it seems to come as the top answer on google; I wish it was edited or removed, as the question in the body is really basic stuff. Answers to title can be found in the possible duplicate link.

A
Andrew Sledge

Unlike Java, you cannot define multiple constructors. However, you can define a default value if one is not passed.

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

N
Neuron

If your signatures differ only in the number of arguments, using default arguments is the right way to do it. If you want to be able to pass in different kinds of argument, I would try to avoid the isinstance-based approach mentioned in another answer, and instead use keyword arguments.

If using just keyword arguments becomes unwieldy, you can combine it with classmethods (the bzrlib code likes this approach). This is just a silly example, but I hope you get the idea:

class C(object):

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

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

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

Notice all those class methods still go through the same __init__, but using class methods can be much more convenient than having to remember what combinations of keyword arguments to __init__ work.

isinstance is best avoided because Python's duck typing makes it hard to figure out what kind of object was actually passed in. For example: if you want to take either a filename or a file-like object you cannot use isinstance(arg, file), because there are many file-like objects that do not subclass file (like the ones returned from urllib, or StringIO, or...). It's usually a better idea to just have the caller tell you explicitly what kind of object was meant, by using different keyword arguments.


As you say, this is a great approach if you need to pass in different kinds of arguments. In those cases I tend to use a very basic __init__ and make more than one class method for each case.
this is the most generally applicable solution
is there a good way (your recommendation) to not run the usual __init__ function from the second constructor? eg because both will construct the object from scratch
N
Neuron

For the example you gave, use default values:

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

In general, you have two options:

Do if-elif blocks based on the type: def __init__(self, name): if isinstance(name, str): # todo elif isinstance(name, City): # todo # todo Use duck typing - that is, assume the user of your class is intelligent enough to use it correctly. This is typically the preferred option.


N
Neuron

The answer by Jack M. is correct. Do it this way:

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

>>>

P
Peter Mortensen

The easiest way is through keyword arguments:

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

someCity = City(city="Berlin")

This is pretty basic stuff. Maybe look at the Python documentation?


typos in comments; also, that's not the question he asked --- he asked about switching on types, he just provided a bad example.
@pavpanchekha: it's exactly what was asked. except of course missing self.
@Jack, your example doesn't actually store city anywhere either, so to a newbie this could be a pretty confusing answer.