【问题标题】:Is there a shortcut for creating __init__ functions based on class attributes?是否有基于类属性创建 __init__ 函数的快捷方式?
【发布时间】:2013-08-09 16:17:26
【问题描述】:

我正在使用 sqlalchemy 的 ORM,并且我有一堆具有类属性的 Declarative 类。例如:

class Example(Declarative):
    id = Column(Integer, primary_key=True)
    datum = Column(String(65))

当然,我的课程比这个例子长得多,我大约有两打。我希望能够在实例化时填充它们的字段,因此最好为每个类提供 __init__ 函数。

天真的方法如下:

    def __init__(self, id, datum):
        self.id = id
        self.datum = datumi

这变得非常乏味。有什么捷径吗?也许我可以利用Example.__dict__?这些是新型类。

【问题讨论】:

  • 也许类似的解决方案可能有用:stackoverflow.com/questions/5227839/…
  • @Alex,也许我遗漏了一些明显的东西,但我不明白这会如何简化任何事情。这适用于__init__吗?
  • SQLAlchemy已经为你提供了__init__,为什么要创建你自己的?

标签: python class oop sqlalchemy


【解决方案1】:

您根本不需要创建__init__ 方法; SQLAlchemy 为您提供了一种开箱即用的方法。

即使您确实必须构建一个,您也可以接受任意关键字参数。这正是 SQLAlchemy 版本所做的:

def _declarative_constructor(self, **kwargs):
    """A simple constructor that allows initialization from kwargs.

    Sets attributes on the constructed instance using the names and
    values in ``kwargs``.

    Only keys that are present as
    attributes of the instance's class are allowed. These could be,
    for example, any mapped columns or relationships.
    """
    cls_ = type(self)
    for k in kwargs:
        if not hasattr(cls_, k):
            raise TypeError(
                "%r is an invalid keyword argument for %s" %
                (k, cls_.__name__))
        setattr(self, k, kwargs[k])

翻译成散文,此方法在使用setattr() 设置实例值之前测试您传入的每个关键字是否都是类的属性。

注意这里使用了关键字参数;您无法使用位置参数来执行此操作,因为您的类属性存储在字典中,因此没有设置顺序。如果你想使用位置参数,你需要手动创建一个__init__ 方法,或者为(继承的)__init__ 在类上定义一个顺序 以使用:

class Example(Declarative):
    id = Column(Integer, primary_key=True)
    datum = Column(String(65))
    __order__ = ('id', 'datum')

    def __init__(self, *args, **kwargs):
        cls_ = type(self)
        kwargs.update(zip(cls_.__order__, args))
        for k in kwargs:
            if not hasattr(cls_, k):
                raise TypeError(
                    "%r is an invalid keyword argument for %s" %
                    (k, cls_.__name__))
            setattr(self, k, kwargs[k])

在这里,任何位置参数都被合并到kwargs,给定类的新__order__属性中的存储字段顺序。

【讨论】:

  • 我会被诅咒的。所以我可以在不实现自己的构造函数的情况下做Example(9001, 'hello, world')
  • 差不多。您可以在不实现自己的构造函数的情况下执行Example(id=9001, datum='hello, world')
  • 对我来说已经足够了!感谢您的回答!
  • 在 Python 3 中,还可以覆盖元类上的 __prepare__() 并为类命名空间使用 OrderedDict。 (我不建议这样做——元类被过度使用,以至于我对它们产生了过敏。)
【解决方案2】:

您可以定义一个将字典作为输入的类并执行以下操作:

for (k, v) in inital_dict.iteritems():
    setattr(self, k, v)

如果您从该类继承所有新类将具有相同的方法,您可以使用super 调用它。

【讨论】:

    猜你喜欢
    • 2017-03-25
    • 2021-07-10
    • 1970-01-01
    • 2014-07-11
    • 2011-04-21
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    • 2012-08-24
    相关资源
    最近更新 更多