New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
subclasses of BaseModel can be hashable #1303
Comments
I would create your own from pydantic import BaseModel
class MyBaseModel(BaseModel):
def __hash__(self):
return hash((type(self),) + tuple(self.__dict__.values()))
class Foo(MyBaseModel):
foo: str = 'foo'
f = Foo()
d = {f: 'bar'}
print(d)
I would argue that this is:
You'd basically need to implement an entire hashable subset of python e.g. for lists, dicts, custom types etc. So let's stick with the above of people people implementing their own solution for now. |
Yeah, I understand the desire to not bloat the API surface area. I was just missing this feature from dataclasses. FWIW I don't think you'd need to implement a hashable subset of the standard library: I don't consider (or want) models with lists to be hashable, which is a nice side effect of the implementation above that just forwards to the tuple hash function. Anyway, for anybody who decides to do this on their own, note that you should also look into the "immutability" flag that Pydantic offers. I'm only trying to prevent me from shooting myself in the foot so it doesn't need to be watertight (and indeed, it's a pain to try to make it so when subclasses are involved), but it's good hygiene to require the flag to be set. |
This makes a lot of sense. It's just counter intuitive to me, because I treat pydantic.BaseModel as a drop-in replacement of dataclass. Can you please document hash is unimplemented for pydantic.BaseModel? |
Pr welcome to add it to documentation. |
By the way, you can use the pydantic dataclass support for this, maybe it's sufficient? from pydantic.dataclasses import dataclass as pyd_dataclass
@pyd_dataclass(eq=True, frozen=True)
class Foo:
foo: str = "foo"
d = { Foo(): "bar" } |
Building on antonl's response, here is a custom decorator in pydantic's style: import typing def hashable_dataclass(_cls: typing.Optional[typing.Type[typing.Any]] = None,
|
Good stuff, but don't use
If you need stable hash, use this guy:
|
Feature Request
Output of
python -c "import pydantic.utils; print(pydantic.utils.version_info())"
:I use Pydantic extensively in place of dataclasses throughout my projects. It would be nice to be able to use some of the simpler types as dict keys, or to put into sets:
I tried writing a superclass/mixin to selectively add this behavior to existing models:
though this particular implementation has struggles, as it doesn't work when it's not the first in the list of inherited classes. I think this has something to do with Pydantic's initialization and maybe metaclasses, but I didn't dig too deep. So I wrote it as a decorator instead:
which seems to work more or less alright, though I haven't really run it through its paces so I don't know if I've missed anything.
Anyway, it would be great to have this baked in, even if it were default off. Maybe with something on
Config
?The text was updated successfully, but these errors were encountered: