什么是数据对象可接受的样式python

时间:2014-04-10 23:08:25

标签: python

python中数据对象的正常样式是什么。假设我有一个方法可以从某个地方(net,DB,....)获取客户应返回的对象类型。我看到了几个选择:

  • 一个元组
  • 字典
  • 一个类实例(数据类'正常')

我相信还有其他人。做我的第一个大python项目,所以想开始使用最佳实践开始

哇 - 对这个问题的负面反应感到惊讶。也许不清楚

我有许多不同的数据项,我想传递给我的代码。用户,产品,客户,订单......(实际上它们不是那样的,但它更简单,有明显类型的东西)。所以我有

def get_user():
  return x

x应该是什么。一个名为user,dict,tuple ...的类的实例。

没有与对象关联的方法,纯数据

看起来像是命名元组

编辑:这作为一种风格

class product:
   pass

...

def get_product():
   ... db read stuff
   pr = product()
   pr.name = dbthing[0]
   pr.price = dbthing[1]
   return pr

这个barf诱导或完善的风格或奇怪或什么?有用。从消费者的角度来看,它是可读的代码

def xxx():
  pr = get_product()
  total = amount * pr.price

3 个答案:

答案 0 :(得分:2)

对于简单数据记录,您通常应首先考虑collections.namedtuple,如果由于任何原因不适合,请使用其他选项之一。一旦你知道为什么它不适合通常建议使用其他人。您可以将collections.namedtuple视为快速定义不可变"数据类的快捷方式"。

以数据库为例,如果您正在使用ORM,那么即使是最简单的记录也会被表示为对象[*],并且有充分的理由,因为它们都会共同执行您可以执行的一些操作它们如将更改存储回数据库。 ORM的教程/文档将指导您。如果您直接使用Python db API,那么SQL查询中的行将(最初)作为元组返回,但是当您拥有它们时,您当然可以使用它们执行您喜欢的操作。此外,数据库连接器可以在调用execute()之前提供操作它们的方法,例如在sqlite3中设置行工厂。

采取"网络"作为一个例子 - 嗯,有许多数据交换方法,但一个常见的例子是访问返回JSON数据的API。在这种情况下,没有多少选择,但最初在程序中以与JSON结构相同的方式表示此数据:包含列表,词典,字符串和数字的列表和词典。再一次,一旦拥有它,你可以用你喜欢的东西做。使用它是相当正常的,将它重新组织成其他东西也是相当正常的。个人偏好和特定情况都会影响您实际选择的内容。

您当然应该将所有这些事情视为可用选项。一般来说,你会使用:

  • 每个职位都有自己意义的元组。这就是为什么Python返回"多个值"从一个函数返回一个元组,因为不同的东西可能是完全不同的类型,具有不同的含义。
  • 当可用键因记录而异时的字典。
  • 每个记录的密钥相同时的数据类。您可以将namedtuple用于不可变记录。
  • 订单很重要时的列表或元组但位置都是等价的。观察到这里之间存在一点紧张关系;元组是不可变的,列表是可变的" vs."元组用于异构数据,列表用于同类数据"。我个人倾向于前者,但我已经看到后者的合理论据,所以如果你一直在问人们如何做出选择,你就不能忽视它。

[*]好吧,元组和字典当然也是对象,我指的是除了这些数据结构之外的对象; - )

答案 1 :(得分:1)

我将“数据对象”解释为不可变的对象,通常只有几个字段。

您经常看到的一个选项是使用标准词典,并将字段作为键。但我个人并不喜欢这样,随着软件变得越来越大,很难确切地看到哪些密钥存在以及它们来自何处。人们开始编写为现有词典添加新密钥的功能,这一切都变得一团糟。

您的空产品类对我来说有点奇怪 - 如果您要这样做,请将值传递给构造函数并让它设置属性。然后它是关于最常用的方式 - 一个带有一些属性的简单类,没有别的。

但是,命名元素更酷,因为它们是不可变的,所以当你阅读代码时,你不必担心某些字段会在某处发生变化:

from collections import namedtuple

Product = namedtuple('Product', 'name price')

p = Product("some product", 10)

但是现在你想要为它添加功能,比如一个__unicode__方法,它返回产品及其价格的描述。您现在可以再次将其转换为普通类,构造函数采用相同的参数。但你也可以子类一个namedtuple:

class Product(namedtuple('Product', 'name price')):
    def __unicode__(self):
        return "{} (${})".format(self.name, self.price)

它仍然是不可改变的。这就是我需要纯数据对象时所做的事情。如果你需要它成为一个可变类,可以使其中一个属性变成可变的,或者把它变成一个具有相同接口的普通类。

答案 2 :(得分:0)

任何一个命名元组或类都可以工作。这实际上取决于你正在做什么,以及你是否向其他人提供API。类通常用于更好的API,你可以放入更清晰的访问点。

至于最后的代码示例,最好让类在构造期间尽可能地获取参数。这样你就可以从" birth"中返回一个真实的,可用的对象。而不是等待填充的空壳。同样,从API的角度来看,如果在没有设置几个值的情况下无法使用类,那么在没有设置这些值的情况下,应该没有办法创建类的实例。否则你最终会写烦人的"如果没有设置:那么失败"在一堆安全守卫的地方。在C ++或Java等语言中更是如此,但它仍然是一种很好的风格和操作模式。