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

2024-09-28 18:12:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我试过以下方法:

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)在质量/惯性之后移动重心x/y/z。(B)我仍然希望提供一种选择,即不必对其进行定义


Tags: 方法nameselfref定义initdef格式
3条回答
<>你声称你会用超载(我假设)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或其他一些元类的实例);您可以使用vars函数检查它的__dict__,您可以使用inspect模块对对象或其类型执行各种操作,或者,使用第三方模块,您可以获得类似Dylan或类似Common Lisp的多分派(类似于虚拟函数,但是打开所有参数的类型,而不仅仅是self)。但我不知道你会怎么用这些。如果参数的运行时类型在某种程度上是相关的,那就很容易了;例如isinstance(cg_x_or_mass, int)将告诉您cg_x_or_mass是否是int。但我不知道你会怎么做

或者创建一个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

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

注意,在这个设置中,massinertia必须通过关键字传递。从概念上讲,不可能按位置传递massinertia,除非也为所有cg_参数传递值。例如,如果您想传递mass的值,而不是cg_x,那么您唯一的选择就是foo('name', 'x', 'y', 'z', mass=0, inertia=0)。在Python中,不可能定义一个带有参数的函数,这些参数“只是有时”必须通过关键字传递,因此,如果在任何情况下参数必须通过关键字传递,则必须使其始终通过关键字传递

相关问题 更多 >