Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python equivalent of Scala case class

Tags:

python

scala

Is there any Python equivalent of Scala's Case Class? Like automatically generating constructors that assign to fields without writing out boilerplate.

like image 905
james.bondu Avatar asked Jul 14 '18 18:07

james.bondu


3 Answers

The current, modern way to do this (as of Python 3.7) is with a data class. For example, the Scala case class Point(x: Int, y: Int) becomes:

from dataclasses import dataclass

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

The frozen=True part is optional; you can omit it to get a mutable data class. I've included it for parity with Scala's case class.

Before Python 3.7, there's collections.namedtuple:

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

Namedtuples are immutable, as they are tuples. If you want to add methods, you can extend the namedtuple:

class Point(namedtuple('Point', ['x', 'y'])):
    def foo():
        pass
like image 193
Brian McCutchon Avatar answered Nov 13 '22 06:11

Brian McCutchon


If you use python3.7 you get data classes as @dataclass. Official doc here - 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)

Make sure to upgrade python3 to python 3.7 or if you use python 3.6 install dataclass from pypi

In macos: brew upgrade python3

While above data class in scala looks like,

scala> final case class CustomerOrder(id: Int, customerID: String, itemName: String)
defined class CustomerOrder
like image 11
prayagupa Avatar answered Nov 13 '22 04:11

prayagupa


The other answers about dataclass are great, but it's worth also mentioning that:

  • If you don't include frozen=True, then your data class won't be hashable. So if you want parity with Scala case classes (which automatically define toString, hashcode and equals) then to get hashcode, you will need @dataclass(frozen=True)
  • even if you do use frozen=True, if your dataclass contains an unhashable member (like a list), then the dataclass won't be hashable.
  • hash(some_data_class_instance) will be equal if the values are equal (and frozen=True)
  • From a quick empirical test, equality comparisons don't appear to be any faster if your type is hashable. Python is walking the class members to compare equality. So even if your frozen dataclass has all hashable members (e.g. tuples instead of lists), it will still walk the values to compare equality and be very slow.
like image 1
Ryan Avatar answered Nov 13 '22 04:11

Ryan