2

您好我有以下代码,它试图创建一个类的实例并为其分配参数值。我正在尝试使用 *args 来执行此操作,如下所示:

def main():
    testdata = ['FDR', False, 4, 1933]
    apresident = President(testdata)
    print apresident
    print apresident.alive

class President:
    id_iter = itertools.count(1)
    #def __init__(self, president, alive, terms, firstelected):
    def __init__(self, *args):
        self.id = self.id_iter.next()
        self.president = args[0]
        self.alive = args[1]
        self.terms = args[2]
        self.firstelected = args[3]

我收到“元组索引超出范围”错误。正如您从注释行中看到的那样,我之前使用位置参数来完成此操作(有效),并使用如下行来执行此操作:

    self.president = president

在这种情况下使用 *args 的正确方法是什么?我应该使用 *kwargs 吗?

4

3 回答 3

4

您只向 传递一个参数President(),即列表

['FDR', False, 4, 1933]

如果您想将该列表中的项目作为单独的参数传递,您可以这样做:

    apresident = President(*testdata)  # note the * character

正如上校 Panic 指出的那样,在您的示例中,使用参数解包有点毫无意义 - 大概您的实际用例更复杂,并且证明了它的使用是合理的。

更新

您的评论实际上是一个后续问题,作为一个单独的问题会更好,但是:

def main():
    testdata = {
        "president": "FDR",
        "alive": False,
        "terms": 4,
        "firstelected": 1933,
    }
    apresident = President(**testdata)
    anotherpresident = President(president="BHO", terms=2, firstelected=2008)
    print apresident
    print apresident.alive
    print anotherpresident
    print anotherpresident.alive

class President:
    id_iter = itertools.count(1)
    #def __init__(self, president, alive, terms, firstelected):
    def __init__(self, **kwargs):
        self.id = self.id_iter.next()
        self.president = kwargs.get("president", None)
        self.alive = kwargs.get("alive", True)
        self.terms = kwargs.get("president", 1)
        self.firstelected = kwargs.get("president", None)

这也显示了如何定义默认值。

于 2013-08-24T16:44:20.837 回答
2

You should only use *args if you do not know how many arguments will be passed to function.

In your case, it looks like you need all of president, alive, terms, firstelected. There is nothing wrong with having a constructor that takes all of those as parameters.

*kwargs is used for a few reasons. One is if you have default values that should be used, unless the user wants to specify them.

For more info, see this question, this question, and the official documentation.


In response to your comment

I would recommend you do have the datedied property for each president. If they haven't died yet, then the value should be None. When you extend only certain instances with functionality, it becomes harder (but not impossible) to reason about the code.

Having said that, if you wanted arbitrary properties for each president that clearly won't be applicable to each instance, then you could use keyword arguments. But adding properties isn't limited to the constructor. I would simply use setattr() and getattr().

How to set class properties with kwargs

class President(object):
   def __init__(self, *args, **kwargs):
      for name, value in kwargs.items():
         # Make each keyword-argument a property of the class.
         setattr(self, name, value)

tVar = President(is_cool=True)
print tVar.is_cool # Returns True
于 2013-08-24T16:42:50.987 回答
1

您正在调用President(testdata),当您应该President(*testdata)在调用构造函数时解压缩列表时。

现在,您实际上是在传递一个参数(列表),因此IndexError: 您正在传递一个参数,因此args等于[testdata]和 not testdata


*args正如另一个答案中提到的那样,在这里的构造函数中使用它并不是非常Pythonic 。您知道您期望哪些参数,所以只需使用这些参数。

不过,在调用函数时使用它是可以的。

于 2013-08-24T16:44:28.663 回答