非默认值之前的多个构造函数/默认参数

时间:2014-10-15 17:54:47

标签: python constructor

我尝试了以下内容:

def __init__(self, name, x, y, z, cg_x = 0, cg_y = 0, cg_z = 0, mass, inertia):
    self.ref_x = x
    self.ref_y = y
    self.ref_z = z
    self.cg_x = cg_x
    self.cg_y = cg_y
    self.cg_z = cg_z
    self.name = name
    self.mass = mass
    self.inertia = inertia

正如预期的那样,python抱怨构造函数不正确。

但是我怎么重塑这个呢?我确实试图阻止(A)在质量/惯性之后移动cg_x / y / z。并且(B)我仍然希望提供不必定义那些的选项。

3 个答案:

答案 0 :(得分:1)

在Python 3中,您可以将massinertia指定为keyword-only arguments。在Python 2中,您必须使用**kwargs并从kwargs中手动提取massinertia

请注意,使用此设置时,massinertia 必须按关键字传递。从概念上讲,除非为所有mass参数传递值,否则无法在位置上传递inertiacg_。如果您想传递mass但不是cg_x的值,则唯一的选择就是foo('name', 'x', 'y', 'z', mass=0, inertia=0)。在Python中不可能定义一个带有参数的函数,“只有时候”必须通过关键字传递,所以如果必须通过关键字传递参数的任何情况,你必须使它们总是按关键字传递。

答案 1 :(得分:0)

也许创建一个classmethod,这是一个替代构造函数?

class SomeThing(object):
    def __init__(self, name, x, y, z, cg_x, cg_y, cg_z, mass, inertia):
        self.ref_x = x
        self.ref_y = y
        self.ref_z = z
        self.cg_x = cg_x
        self.cg_y = cg_y
        self.cg_z = cg_z
        self.name = name
        self.mass = mass
        self.inertia = inertia
    @classmethod
    def no_cg(cls, name, x, y, z, mass, inertia):
        return cls(name, x, y, z, 0, 0, 0, mass, inertia)

然后你可以做任何一个:

foo = SomeThing('bar', 1, 2, 3, 4, 5, 6, "10g", some_vector)

foo = SomeThing.no_cg('bar', 1, 2, 3, "10g", some_vector)

或者为massinertia添加默认参数,然后测试它们

class SomeThing(object):
    def __init__(self, name, x, y, z, cg_x=0, cg_y=0, cg_z=0, mass=None, inertia=None):
        if mass is None or inertia is None:
            raise ValueError("Must provide mass and inertia values")
        self.ref_x = x
        self.ref_y = y
        self.ref_z = z
        self.cg_x = cg_x
        self.cg_y = cg_y
        self.cg_z = cg_z
        self.name = name
        self.mass = mass
        self.inertia = inertia

答案 2 :(得分:0)

你声称你在重载(我假设)C ++时这样做了。但是除name之外的所有参数看起来都是相同的类型。很明显,你只是在参数的数字上重载,而不是类型。像这样:

ClassName(string name, double x, double y, double z,
          double mass, double inertia) :
    name_(name), x_(x), y_(y), z_(z), 
    cg_x_(0), cg_y_(0), cg_z(0), 
    mass_(mass), inertia_(inertia) {}
ClassName(string name, double x, double y, double z,
          double cg_x, double cg_y, double cg_z,
          double mass, double inertia) :
    name_(name), x_(x), y_(y), z_(z), 
    cg_x_(cg_x), cg_y_(cg_y), cg_z(cg_z), 
    mass_(mass), inertia_(inertia) {}

你想知道如何在Python中做类似的事情。

最好的方法可能就是:

def __init__(self, name, x, y, z, *args):
    self.name, self.x, self.y, self.z = name, x, y, z
    if len(args) == 2:
        self.cg_x = self.cg_y = self.cg_z = 0
        self.mass, self.inertia = args
    else:
        self.cg_x, self.cg_y, self.cg_z, self.mass, self.inertia = args

虽然你可以做一些像:

def __init__(self, name, x, y, z, cg_x_or_mass, cg_y_or_inertia,
             cg_z=None, mass=None, inertia=None):
    self.name, self.x, self.y, self.z = name, x, y, z
    if cg_z is None:
        self.cg_x = self.cg_y = self.cg_z = 0
        self.mass, self.inertia = cg_x_or_mass, cg_y_or_inertia
    else:
        self.cg_x, self.cg_y, self.cg_z = cg_x_or_mass, cg_y_or_inertia, cg_z
        self.mass, self.inertia = mass, inertia
然而,无论哪种方式,这都有点难看。在Python中,重载总是有点丑陋;我们鼓励您使用关键字参数或替代构造函数,或者在某些情况下设置一些"可选"建设后的属性。但它有时很有用。


您还提到了RTTI。 Python的RTTI比C ++更好 。您可以为任何对象编写type(spam),并获取一个类对象(type或其他元类的实例);您可以使用__dict__函数检查其vars,您可以使用inspect模块对对象或其类型等执行各种操作。或者,使用第三方模块,你可以得到类似Dylan或Common Lisp的多重调度(比如虚函数,但是切换所有参数的类型,而不仅仅是self)。但我不确定你是如何在这里实际使用的。如果参数的运行时类型在某种程度上相关,那将很容易;例如,isinstance(cg_x_or_mass, int)会告诉您cg_x_or_mass是否为int。但我不知道你对此做了什么。