在Python中不能定义多个构造函数吗?

301 投票
5 回答
347948 浏览
提问于 2025-04-15 18:39

在Python中,是否不能定义多个构造函数,且它们的参数不同?如果不能,那一般有什么方法来解决这个问题呢?

举个例子,假设你想定义一个类叫做City

我希望能够这样使用:someCity = City(),或者someCity = City("Berlin"),前者是给一个默认的名字,后者则是指定一个名字。

5 个回答

15

对于你给出的例子,可以使用默认值:

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

一般来说,你有两个选择:

  1. 根据类型做 if-elif 判断:

    def __init__(self, name):
        if isinstance(name, str):
            # todo 
        elif isinstance(name, City):
            # todo 
        # todo 
    
  2. 使用鸭子类型——也就是说,假设使用你这个类的人足够聪明,能够正确使用它。这通常是更受欢迎的选择。

319

如果你的函数参数只是在数量上有所不同,使用默认参数是个不错的选择。如果你想传入不同类型的参数,我建议避免使用其他答案中提到的基于isinstance的方法,而是使用关键字参数。

如果只用关键字参数变得很麻烦,你可以把它和类方法结合起来(bzrlib的代码就喜欢这种方式)。下面是一个简单的例子,希望能让你明白这个想法:

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

注意所有这些类方法仍然通过同一个__init__,但使用类方法比记住哪些关键字参数组合适用于__init__要方便得多。

最好避免使用isinstance,因为Python的鸭子类型让你很难判断实际传入的是哪种对象。例如:如果你想接受一个文件名或一个类似文件的对象,你不能用isinstance(arg, file),因为有很多类似文件的对象并不继承自file(比如从urllib返回的对象,或者StringIO等等)。通常来说,让调用者明确告诉你想要的对象类型,使用不同的关键字参数会是个更好的主意。

385

跟Java不一样,你不能定义多个构造函数。不过,如果没有传入参数,你可以设置一个默认值。

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

撰写回答