Python中是否有速记初始化器?

Is there a shorthand initializer in Python?

我没有找到一个简短的构造函数调用的引用,它会初始化调用者选择的变量。 我在寻找

1
2
3
4
5
class AClass:
    def __init__(self):
        pass

instance = AClass(var1=3, var2=5)

而不是写更重

1
2
3
4
class AClass:
    def __init__(self, var1, var2):
        self.var1 = var1
        self.var2 = var2

或者更重

1
2
3
instance = AClass()
instance.var1 = 3
instance.var2 = 5

我错过了什么吗?


您可以直接更新对象的__dict__属性,这是存储属性的位置

1
2
3
4
5
class AClass:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

c = AClass(var1=1, var2='a')


这是一个很好的问题,对我来说也是一个难题。

在现代Python世界中,有三个(优秀的)速记初始化器(这个术语很聪明,我采用它),这取决于你的需求。没有任何需要使用__init__方法的步法(这是你想要首先避免的)。

命名空间对象

如果您希望为实例分配任意值(即不由类强制执行),则应使用名为namespace的特定数据结构。命名空间对象是可通过点表示法访问的对象,您可以基本上为其分配所需的对象。

您可以从argparse导入Namespace类(这里介绍:如何创建Python命名空间(argparse.parse_args值)?)。从Python 3.3开始。标准类型包中提供了SimpleNamespace类。

1
2
from types import SimpleNamespace
instance = SimpleNamespace(var1=var1, var2=var2)

你也可以写:

1
2
3
instance = SimpleNamespace()
instance.var1 = var1
instance.var2 = var2

让我们说它是"快速而肮脏的方式",它可以在许多情况下起作用。一般来说,甚至没有必要申报你的课程。

如果您希望实例仍然具有一些方法和属性,您仍然可以执行以下操作:

1
2
3
class AClass(Namespace):
    def mymethod(self, ...):
        pass

然后:

1
instance = AClass(var1=var1, var2=var2, etc.)

这为您提供了最大的灵活性

命名为元组

另一方面,如果您希望类强制执行这些属性,那么您还有另一个更可靠的选项。

命名元组生成不可变实例,它们一劳永逸地初始化。将它们视为普通元组,但每个项目也可以用点符号访问。这个类namedtuple是Python标准发行版的一部分。这是你如何生成你的类:

1
2
from collections import namedtuple
AClass = namedtuple("AClass","var1 var2")

注意定义有多酷和短,而不是__init__方法。之后你可以完成课程。

并创建一个对象:

1
instance = AClass(var1, var2)

要么

1
instance = AClass(var1=var1, var2=var2)

命名清单

但是,如果您希望该实例是可变的,即允许您更新实例的属性,该怎么办?答案是命名列表(也称为RecordClass)。从概念上讲,它就像一个普通的列表,其中的项目也可以用点表示法访问。

有各种实现。我个人使用恰当命名的命名列表。

语法相同:

1
2
from namedlist import namedlist
AClass = namedlist("AClass","var1 var2")

并创建一个对象:

1
instance = AClass(var1, var2)

要么:

1
instance = AClass(var1=var1, var2=var2)

然后你可以修改它们:

1
instance.var1 = var3

但是您无法添加未定义的属性。

1
2
3
>>> instance.var4 = var4
  File"<stdin>", line 1, in <module>
AttributeError: 'instance' object has no attribute 'var4'

用法

这是我的两位:

  • 命名空间对象是为了获得最大的灵活性,甚至不需要声明一个类;存在不正常行为的风险(但Python是同意成人的语言)。如果您只有一个实例和/或您知道自己在做什么,那将是最佳选择。

  • namedtuple类生成器非常适合生成函数返回的对象(请参阅Raymond Hettinger讲座中的简要说明)。返回的元组不是返回用户需要在文档中查找的平淡元组,而是不言自明(dir或help会执行此操作)。并且它无论如何都与元组使用兼容(例如k,v, z = my_func())。加上它是不可改变的,它有自己的优势。

  • namedlist类生成器在很多情况下都很有用,包括当你需要从函数返回多个值时,需要在稍后阶段进行修改(你仍然可以解压它们:k, v, z = instance)。如果您需要具有强制属性的适当类的可变对象,那么这可能是首选解决方案。

  • 如果您使用它们,这可能会显着减少编写类和处理实例所花费的时间!


    您可以使用对象属性的字典表示,并使用给定构造函数的关键字参数更新其元素:

    1
    2
    3
    4
    5
    6
    class AClass:
        def __init__(self, **kwargs):
            self.__dict__.update(**kwargs)

    instance = AClass(var1=3, var2=5)
    print(instance.var1, instance.var2) # prints 3 5

    但是,考虑到这个问题的风格,请考虑这个问题及其答案。 除非你知道自己在做什么,否则最好一个一个地明确设置参数。 对于你和其他人来说,这将更容易理解 - 明确比隐含更好。 如果以__dict__.update方式执行,请正确记录。


    尝试

    1
    2
    3
    class AClass:
        def __init__(self, **vars):
            self.var1 = vars.get('var1')