type hint for an instance of a non specific dataclass

2024/11/21 0:35:02

I have a function that accepts an instance of any dataclass. what would be an appropriate type hint for it ?

haven't found something official in the python documentation


this is what I have been doing, but i don't think it's correct

from typing import Any, NewTypeDataClass = NewType('DataClass', Any)
def foo(obj: DataClass):...

another idea is to use a Protocol with these class attributes __dataclass_fields__, __dataclass_params__.

Answer

Despite its name, dataclasses.dataclass doesn't expose a class interface. It just allows you to declare a custom class in a convenient way that makes it obvious that it is going to be used as a data container. So, in theory, there is little opportunity to write something that only works on dataclasses, because dataclasses really are just ordinary classes.

In practice, there a couple of reasons why you would want to declare dataclass-only functions anyway, and something like this is how you should go about it:

from dataclasses import dataclass
from typing import ClassVar, Dict, Protocolclass IsDataclass(Protocol):# as already noted in comments, checking for this attribute is currently# the most reliable way to ascertain that something is a dataclass__dataclass_fields__: ClassVar[Dict] def dataclass_only(x: IsDataclass):...  # do something that only makes sense with a dataclass@dataclass
class Foo:passclass Bar:passdataclass_only(Foo())  # a static type check should show that this line is fine ..
dataclass_only(Bar())  # .. and this one is not

This approach is also what you alluded to in your question. If you want to go for it, keep in mind that you'll need a third party library such as mypy to do the static type checking for you, and if you are on python 3.7 or earlier, you need to manually install typing_extensions since Protocol only became part of the standard library in 3.8.

Also noted that older version of mypy (>=0.982) mistakenly expect __dataclass_fields__ to be an instance attribute, so the protocol should be just __dataclass_fields__: Dict[1].


When I first wrote it, this post also featured The Old Way of Doing Things, back when we had to make do without type checkers. I'm leaving it up, but it's not recommended to handle this kind of feature with runtime-only failures any more:

from dataclasses import is_dataclassdef dataclass_only(x):"""Do something that only makes sense with a dataclass.Raises:ValueError if something that is not a dataclass is passed.... more documentation ..."""if not is_dataclass(x):raise ValueError(f"'{x.__class__.__name__}' is not a dataclass!")...

[1]Kudos to @Kound for updating and testing the ClassVar behavior.

https://en.xdnf.cn/q/26262.html

Related Q&A

Is there a static constructor or static initializer in Python?

Is there such a thing as a static constructor in Python? How do I implement a static constructor in Python?Here is my code... The __init__ doesnt fire when I call App like this. The __init__ is not…

What does this - in jinja2 template engine do?

I am learning jinja2 because Google App Engine recommends it.I found this example on Wikipedia: http://en.wikipedia.org/wiki/Jinja_%28template_engine%29{%- for item in item_list %}{{ item }}{% if not l…

When to apply(pd.to_numeric) and when to astype(np.float64) in python?

I have a pandas DataFrame object named xiv which has a column of int64 Volume measurements. In[]: xiv[Volume].head(5) Out[]: 0 252000 1 484000 2 62000 3 168000 4 232000 Name: Volume, d…

How to change folder names in python?

I have multiple folders each with the name of a person, with the first name(s) first and the surname last. I want to change the folder names so that the surname is first followed by a comma and then t…

Python return list from function

I have a function that parses a file into a list. Im trying to return that list so I can use it in other functions. def splitNet():network = []for line in open("/home/tom/Dropbox/CN/Python/CW2/net…

Python Json loads() returning string instead of dictionary?

Im trying to do some simple JSON parsing using Python 3s built in JSON module, and from reading a bunch of other questions on SO and googling, it seems this is supposed to be pretty straightforward. Ho…

Sort dataframe by string length

I want to sort by name length. There doesnt appear to be a key parameter for sort_values so Im not sure how to accomplish this. Here is a test df:import pandas as pd df = pd.DataFrame({name: [Steve, Al…

How to mock pythons datetime.now() in a class method for unit testing?

Im trying to write tests for a class that has methods like:import datetime import pytzclass MyClass:def get_now(self, timezone):return datetime.datetime.now(timezone)def do_many_things(self, tz_string=…

How can I select only one column using SQLAlchemy?

I want to select (and return) one field only from my database with a "where clause". The code is:from sqlalchemy.orm import load_only@application.route("/user", methods=[GET, POST])…

Get first list index containing sub-string?

For lists, the method list.index(x) returns the index in the list of the first item whose value is x. But if I want to look inside the list items, and not just at the whole items, how do I make the mos…