Python中类似于Scala case class的结构

27

有没有 Python 的 Case Class 等效物?就像自动生成构造函数并将其分配给字段,而不必编写样板代码。


“实现Scala的Case Class”是什么意思?你是在用Python编写Scala编译器吗?“Scala case class的等效物”是什么意思?你想让哪些Scala case class的属性等效?静态类型检查?“类变量”是什么意思?Scala没有类变量。 “不创建类实例”是什么意思?在Scala中,每个值都是一个对象,每个对象都是类的实例。 - Jörg W Mittag
3个回答

48

目前(截至Python 3.7),实现这一功能的现代方法是使用数据类。例如,Scala中的case class Point(x: Int, y: Int)在Python中变为:

from dataclasses import dataclass

@dataclass(frozen=True)
class Point:
    x: int
    y: int

frozen=True 是可选的,你可以省略它来得到一个可变的数据类。我包括它是为了与 Scala 的 case class 相对应。

在 Python 3.7 之前,有 collections.namedtuple:

from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])

Namedtuples是不可变的,因为它们是元组。如果你想添加方法,你可以扩展namedtuple:

命名元组是不可更改的,因为它们是元组。如果您想添加方法,可以扩展命名元组:

class Point(namedtuple('Point', ['x', 'y'])):
    def foo():
        pass

深度嵌套的 dataclassesnamedtuples 是否可以类似于 Scala 的 case class 进行复制,例如使用 lenses 进行操作? - ecoe
2
@ecoe 我不了解镜头,但你可以随时发布另一个问题来了解。 - Brian McCutchon

14

如果你使用的是 python3.7 版本,那么你可以通过@dataclass 得到数据类。官方文档在此:30.6. dataclasses — Data Classes

from dataclasses import dataclass

@dataclass
class CustomerOrder:
  order_id: int
  customer_id: str
  item_name: str

order = CustomerOrder(1, '001', 'Guitar')
print(order)

请确保将python3升级到python 3.7,或者如果您使用的是python 3.6,则从pypi安装dataclass。

在macOS中: brew upgrade python3

而在scala中,以上数据类看起来像这样:

scala> final case class CustomerOrder(id: Int, customerID: String, itemName: String)
defined class CustomerOrder

3
其他关于dataclass的回答都很好,但值得一提的是:
  • 如果你不包含frozen=True,那么你的数据类将无法进行哈希。所以如果你想要与Scala case类保持一致(自动定义toStringhashcodeequals),那么为了获得hashcode,你需要使用@dataclass(frozen=True)
  • 即使你使用了frozen=True,如果你的数据类包含一个不可哈希的成员(比如列表),那么这个数据类也将无法进行哈希。
  • hash(some_data_class_instance)将在值相等的情况下相等(且frozen=True
  • 从快速的实证测试来看,如果你的类型是可哈希的,相等比较似乎并不更快。Python正在遍历类成员以比较相等性。因此,即使你的frozen数据类具有所有可哈希的成员(例如元组而不是列表),它仍然会遍历值以比较相等性,并且非常慢。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接