Python:快速和脏数据类型(DTO)

时间:2012-12-18 12:49:36

标签: python dto

很多时候,我发现自己编写了像

这样的简单数据类型
def Pruefer:
    def __init__(self, ident, maxNum=float('inf'), name=""):
        self.ident  = ident
        self.maxNum = maxNum
        self.name   = name

虽然这非常有用(显然我不想用匿名的3元组替换上面的内容),但它也是非常有用的。

现在例如,当我想在dict中使用该类时,我必须添加更多样板

    def __hash__(self):
        return hash(self.ident, self.maxNum, self.name)

我承认在我的所有样板类中都可能很难识别出一般模式,但我仍然喜欢这个问题:

  • 有没有 python中流行的习惯用来获取带有命名访问器的快速和脏数据类型?

  • 或许如果没有,也许Python大师可能想展示一些元类黑客或类工厂来让我的生活更轻松?

6 个答案:

答案 0 :(得分:20)

>>> from collections import namedtuple
>>> Pruefer = namedtuple("Pruefer", "ident maxNum name")
>>> pr = Pruefer(1,2,3)
>>> pr.ident
1
>>> pr.maxNum
2
>>> pr.name
3
>>> hash(pr)
2528502973977326415

要提供默认值,您需要做更多...简单的解决方案是使用__new__方法的重新定义编写子类:

>>> class Pruefer(namedtuple("Pruefer", "ident maxNum name")):
...     def __new__(cls, ident, maxNum=float('inf'), name=""):
...         return super(Pruefer, cls).__new__(cls, ident, maxNum, name)
... 
>>> Pruefer(1)
Pruefer(ident=1, maxNum=inf, name='')

答案 1 :(得分:2)

Python 3.6中最有前途的事情之一是变量注释。它们允许以下一种方式将namedtuple定义为类:

In [1]: from typing import NamedTuple

In [2]: class Pruefer(NamedTuple):
   ...:     ident: int
   ...:     max_num: int
   ...:     name: str
   ...:     

In [3]: Pruefer(1,4,"name")
Out[3]: Pruefer(ident=1, max_num=4, name='name')

与namedtuple相同,但保存注释并允许使用某些静态类型分析器(如mypy)检查类型。

更新:15.05.2018

现在,在Python 3.7中存在dataclasses,因此这是定义DTO的首选方式,也可以使用attrs库来实现向后兼容性。

答案 2 :(得分:1)

我没有太多可以添加Alexey Kachayev已经很好的答案 - 但是,可能有用的一件事是以下模式:

Pruefer.__new__.func_defaults = (1,float('inf'),"")

这将允许您创建一个工厂函数,该函数返回一个可以具有默认参数的新命名元组:

def default_named_tuple(name,args,defaults=None):
    named_tuple = collections.namedtuple(name,args)
    if defaults is not None:
        named_tuple.__new__.func_defaults = defaults
    return named_tuple

这可能看起来像黑魔法 - 它起初对我有用,但它全部记录在Data Model中并在this post中进行了讨论。

行动中:

>>> default_named_tuple("Pruefer", "ident maxNum name",(1,float('inf'),''))
<class '__main__.Pruefer'>
>>> Pruefer = default_named_tuple("Pruefer", "ident maxNum name",(1,float('inf'),''))
>>> Pruefer()
Pruefer(ident=1, maxNum=inf, name='')
>>> Pruefer(3)
Pruefer(ident=3, maxNum=inf, name='')
>>> Pruefer(3,10050)
Pruefer(ident=3, maxNum=10050, name='')
>>> Pruefer(3,10050,"cowhide")
Pruefer(ident=3, maxNum=10050, name='cowhide')
>>> Pruefer(maxNum=12)
Pruefer(ident=1, maxNum=12, name='')

仅将某些参数指定为默认值:

>>> Pruefer = default_named_tuple("Pruefer", "ident maxNum name",(float('inf'),''))
>>> Pruefer(maxNum=12)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __new__() takes at least 2 arguments (2 given)
>>> Pruefer(1,maxNum=12)
Pruefer(ident=1, maxNum=12, name='')

请注意,正如所写的那样,将tuple作为defaults传递可能是安全的。但是,通过确保函数中有一个合理的tuple对象,您可以轻松获得更多的幻想。

答案 3 :(得分:1)

另一种可能有助于您使锅炉板代码更通用的方法是对(本地)变量dicts的迭代。这使您可以将变量放在列表中并在循环中处理这些变量。例如:

class Pruefer:
     def __init__(self, ident, maxNum=float('inf'), name=""):
         for n in "ident maxNum name".split():
             v = locals()[n]  # extract value from local variables
             setattr(self, n, v)  # set member variable

     def printMemberVars(self):
         print("Member variables are:")
         for k,v in vars(self).items():
             print("  {}: '{}'".format(k, v))


P = Pruefer("Id", 100, "John")
P.printMemberVars()

给出:

Member Variables are:
  ident: 'Id'
  maxNum: '100'
  name: 'John'

从有效利用资源的角度来看,这种方法当然不是最理想的。

答案 4 :(得分:0)

如果使用Python 3.7,则可以使用数据类;数据类可以被认为是“带有默认值的可变命名元组”

https://docs.python.org/3/library/dataclasses.html

https://www.python.org/dev/peps/pep-0557/

答案 5 :(得分:0)

  

Python中是否有任何流行的惯用语来派生具有命名访问器的快速...数据类型?

Dataclases。他们完全满足了这一需求。

一些答案​​提到了数据类,但这是一个示例。

代码

import dataclasses as dc


@dc.dataclass(unsafe_hash=True)
class Pruefer:
    ident : int
    maxnum : float = float("inf")
    name : str  = ""

演示

pr = Pruefer(1, 2.0, "3")

pr
# Pruefer(ident=1, maxnum=2.0, name='3')

pr.ident
# 1

pr.maxnum
# 2.0

pr.name
# '3'

hash(pr)
# -5655986875063568239

详细信息

您得到:

  • 漂亮代表
  • 默认值
  • 散列
  • 点缀属性访问
  • ...更多

您没有(直接)得到:

  • 打开元组(与namedtuple不同)

这是有关数据类详细信息的guide