在 __init__ 中使用 **kwargs

using **kwargs in __init__

我 运行 遇到以下问题:

class Student():
    def __init__(self,firstname, lastname, **kwargs):
        self.firstname = firstname
        self.lastname = lastname

student1 = Student("John" ,"Johnson" , {"Nationality": "Middle-Earth" , "Sports": ["volleyball","skiing"]})

我希望能够创建所有都有名字和姓氏的学生,但只有一些学生有关于国籍或运动的信息。 (实际上,我正在尝试从 json 文件中重建对象。) 所以我想把kwarg key变成实例变量名,就像这个伪代码

for key,value in kwargs:
   self.key = value

上面是伪代码,但是有没有办法正确地做到这一点python?换句话说:从 kwargs 派生实例变量名而不是所有预定义的。

我知道这不会产生防错代码等...,但我想知道是否可以做到。

您需要将解压缩的 kwargs 传递给 Student 并使用 setattr(object, name, value) 设置值:

class Student():
    def __init__(self,firstname, lastname, **kwargs):
        self.firstname = firstname
        self.lastname = lastname

        for (k,v) in kwargs.items():
            setattr(self, k, v)

student1 = Student("John" ,"Johnson" , **{"Nationality": "Middle-Earth" , "Sports": ["volleyball","skiing"]})
print(student1.__dict__)

输出:

{'lastname': 'Johnson', 'Sports': ['volleyball', 'skiing'], 'firstname': 'John', 'Nationality': 'Middle-Earth'}

您可以在 __init__ 方法中使用它:

for k, v in kwargs.items():
    setattr(self, k, v)

但是,对于需要可重用的代码,不建议这样做。如果关键字参数中有拼写错误,您将无法捕捉到它们。 pylint 等代码检查工具无法识别像这样初始化的 class 属性。您可以使用以下模式(尤其是在有很多关键字参数的情况下):

class Student:
    def __init__(self, firstname, lastname, **kwargs):
        self.firstname = str(firstname)
        self.lastname = str(lastname)
        self.nationality = None
        self.sports = None

        for k, v in kwargs.items():
            if k in self.__dict__:
                setattr(self, k, v)
            else:
                raise KeyError(k)

# this works
s=Student('John', 'Doe', sports=['socker'])

# this will give an error
s=Student('John', 'Doe', sprots=['socker'])

我建议预先说明实例可以具有哪些属性,并使用 None 之类的标记值来指示缺少 "real" 值而不是完全消除该属性。例如:

class Student():
    def __init__(self,firstname, lastname, nationality=None, sports=None):
        self.firstname = firstname
        self.lastname = lastname
        self.nationality = nationality
        self.sports = [] if sports is None else sports

然后

student1 = Student("John" ,"Johnson" , "Middle-Earth" , ["volleyball","skiing"])
student2 = Student("Bob", "Smith", nationality="Australia")  # No sports
student3 = Student("Alice", "Doe", sports=["hockey"])  # No nationality

如果你想解析 JSON 可能有与你的参数名称不匹配的键名,定义一个 class 方法来进行处理以获得适当的参数。例如,

@classmethod
def from_dict(cls, data):
    firstname = data["FirstName"]
    lastname = data["some last name"]
    nationality = data.get("Nationality")
    sports = data.get("Sports", [])
    return cls(firstname, lastname, nationality, sports)

然后

student = Student.from_dict({'FirstName': 'John', 'some_last_name': 'Doe',})