type hint for an instance of a non specific dataclass

前端 未结 1 1801
醉梦人生
醉梦人生 2021-02-08 00:35

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

1条回答
  •  别那么骄傲
    2021-02-08 01:26

    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 I see two ways to go about it.


    The right way, using a static type checker and writing a Protocol

    from dataclasses import dataclass
    from typing import Dict
    
    from typing_extensions import Protocol
    
    class 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__: Dict
    
    def dataclass_only(x: IsDataclass):
        ...  # do something that only makes sense with a dataclass
    
    @dataclass
    class A:
        pass
    
    dataclass_only(A())  # a static type check should show that this line is fine
    

    This approach is also what you alluded to in your question, but it has three downsides:

    • You need a third party library such as mypy to do the static type checking for you
    • If you are on python 3.7 or earlier, you need to manually install typing_extensions as well, since Protocol is not part of the core typing module in them
    • Last but not least, using protocols for dataclasses in this way doesn't work right now

    Something slightly more EAFP-inspired that actually works

    from dataclasses import is_dataclass
    
    def 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!")
        ...
    

    In this approach, the behavior is still very clear to a maintainer or user of this code thanks to the documentation. But the downside is that you don't get a static analysis of your code (including type hints by your IDE), not now and not ever.

    0 讨论(0)
提交回复
热议问题