Lightweight classes with specified fields in Python
Asked Answered
E

2

8

I'm looking for something very like namedtuples:

>>> from collections import namedtuple
>>> Party = namedtuple('Party', ['guests', 'location'])
>>> p = Party(['Jed', 'Fred', 'Kathy'], "Steve's House")

which I use a wrapper class around to add extensibility:

>>> class Party(namedtuple('Party', ['guests', 'location'])):
    ...

but with two differences. I would like the fields to be mutable, and I would like inheritance to work. (Right now I don't think there's a way to have one namedtuple inherit from another).

I've heard about types.SimpleNamespace, but I don't think it allows positional arguments in creation (someone correct me if I'm wrong). I like namedtuples because they keep me from having to write __init__, __repr__, and __eq__, all of which I need for my use case.

What is important to me: built-in implementations of __init__, __repr__ and __eq__ so I don't have to write them myself. I'm going to need many (30+) of these class definitions, and some of them will have many (15+) fields.

What isn't important to me (right now): memory efficiency. I don't plan to have more than five hundred instances of these at any one time.

I'm thinking of rolling my own, but want to make sure I'm not re-inventing the wheel.

Ezekielezell answered 3/8, 2015 at 15:9 Comment(14)
Would using the __slots__ attribute in class Party suffice?Trichoid
When you say "very like namedtuple", what precise qualities are you looking for? If it's a space issue, then @chepner's suggestion to use __slots__ is a good one.Leonie
@jonrsharpe: Yes, good question. I want __eq__, __repr__ and __init__. It doesn't need to be hashable or to subclass tuple.Ezekielezell
@EliRose so size isn't an issue? Why don't you just write a regular class?Leonie
@jonrsharpe: I'm going to have 50 of these, some with many fields, and don't want to rewrite the same __repr__ and __init__ logic for every one of them. So, the amount of code it takes to define a class is important to me.Ezekielezell
@EliRose 50 classes, or 50 instances? As it stands, it is profoundly unclear what you're asking for; please edit the question to clarify what exactly you're trying to achieve generally and why you can't just write a regular superclass specifically. You could always look at the source code for namedtuple and borrow what you need from that.Leonie
You're right, thanks for helping me realize how to communicate this better. The 50 refers to class definitions.Ezekielezell
Python isn't designed for type checking, so it does not really make very much sense (in some cases it can make, I admit) to make own classes for these lightweight data structures. How about just using an arbitrary data type?Polypetalous
@Alfe: Looks interesting, but I'd like to be able to specify my fields in the class definition and throw an error (as namedtuple does) if you try to instantiate without providing all of them.Ezekielezell
You could probably achieve what you want by writing a single metaclass that provides the dynamic implementation of __eq__ etc, then each of your actual classes would be instances of that, which just provide the names of that class's attributes.Spooky
@TomDalton: That's what I was going to do, but I wanted to make sure I wasn't re-inventing the wheel. (There seems to be a lot of coding involved in e.g. making sure subclassing works correctly).Ezekielezell
FWIW, there's a simple way to combine namedtuples. But I guess that's not really relevant here, since you need mutability.Pyrrho
Which namedtuple features do you actually need? Eg, do you need numerical indexing & the ability to iterate?Pyrrho
@PM2Ring: I need nothing except the implementations of __init__, __repr__ and __eq__.Ezekielezell
R
5

For anyone finding this question in 2022, the most appropriate Python feature that achieves this is now dataclasses:

from dataclasses import dataclass
from typing import List

@dataclass
class Party:
    guests: List[str]
    location: str
Renfred answered 20/1, 2022 at 23:13 Comment(0)
S
1

For a problem you need 50 class definitions for less than five hundred instances . . . in total ? Maybe you should re-consider the problem and find a very different approach ? Tried looking at dictionaries ?

item1 = {'party':'easter', 'guests': ['john', fred','kathy'], 'location':'here'}

Than you need only the standard python dict-class and can easy test field presence, add fields and so on, it has init, repr and eq.

Or provide some more information on the problem.

Shamus answered 13/8, 2015 at 9:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.