Python:灵活声明构造函数的方法

2 投票
3 回答
621 浏览
提问于 2025-04-17 06:19

如何干净利落地为一个类声明多个构造函数?

比如说,我有一个叫做 Item 的类。创建一个 Item 的一种方法是:

item = Item(product_id, name, description,price)

另一种做法可能是:

item = Item(otherItem)

还有一种情况是.. 也许在某些情况下我没有价格,所以我只想传递:

item = Item(product_id, name,description)

再比如另一种情况可能是:

item = Item(product_id,price)

我还有一个问题: 有一些私有变量可能在运行时被初始化。 假设我有一个随机变量 itemCount,我想在内部跟踪它。

我该如何声明它,这样我就不需要在初始化时设置,而是在运行时的某个地方.. 我可以这样做:

self._count +=1

谢谢

3 个回答

1

通常,复制操作是通过实例上的一个 copy() 方法来完成的,而不是通过提供一个“复制构造函数”。所以,

item = other_item.copy()

而不是

item = Item(other_item)

你提到的其他构造函数的写法,可以很简单地通过默认参数和关键字参数来处理:

def __init__(self, product_id, name=None, description=None, price=None):
    ...

如果你想要一个有完全不同代码的构造函数,那么使用 classmethod 是正确的做法——可以参考Raymond Hettinger的回答。

4

提供多个构造函数的两种最常见的方法是:

  1. 类方法,以及
  2. 工厂函数

这里有一个来自标准库的例子,展示了collections.OrderedDict是如何使用类方法来实现fromkeys()作为一个备用的类构造函数的:

@classmethod
def fromkeys(cls, iterable, value=None):
    '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.
    If not specified, the value defaults to None.

    '''
    self = cls()
    for key in iterable:
        self[key] = value
    return self

作为另一种常见方法的例子,这里有一个在标准库中使用的工厂函数,它出现在symtable.py中:

class SymbolTableFactory:
    def __init__(self):
        self.__memo = weakref.WeakValueDictionary()

    def new(self, table, filename):
        if table.type == _symtable.TYPE_FUNCTION:
            return Function(table, filename)
        if table.type == _symtable.TYPE_CLASS:
            return Class(table, filename)
        return SymbolTable(table, filename)
1

你可以使用默认参数:

class Item(object):

  def __init__(self, product_id = None, name = None, description = None, price = None)
      ... implementation ...

如果你希望默认值是其他的东西,可以把None替换成你想要的任何值。

使用示例:

item1 = Item(product_id = 4, price = 13) # use the field name!
item2 = Item(name = "hammer", description = "used to belong to Thor")

对于复制构造函数,item = Item(otherItem),@Raymond 提出的类方法和工厂函数可能是最符合 Python 风格的做法。


更新:这里有一个关于 Python 中多个构造函数的问题。它还提到了使用*args**kwargs

撰写回答