0

i have come across some weird behavior when using ABC library in Python 3.8.10.

from abc import ABC, abstractproperty, abstractstaticmethod, abstractmethod
from dataclasses import dataclass

@dataclass
class Message(ABC):
    _type: str = None
    _error: str = None
    _error_msg: str = None

    def error(self):
        return self._error is not None

    def error_msg(self):
        return self._error_msg

    @abstractstaticmethod
    def from_payload(payload: dict):
        """Static initiator of the Message class."""

    @abstractproperty
    def json(self):
        """Returns json string suitable for websocket communication."""

class ActionsLogDetail(Message):
    """Represents detail for one action log from db."""

    def __init__(self, id):
        super().__init__(_type='ActionsLogDetail')
        self.id = id

ActionsLogDetail.from_payload({'x':1})                                                                                                                                                                     
None  # This should raise error and not return None

Well i did some digging in the documentation and found this:


enter image description here

But, if I change the code appropriately:

@staticmethod
@abstractmethod
def from_payload(payload: dict):
    """Static initiator of the Message class."""

ActionsLogDetail.from_payload({'x':1})
None  # Still returns None!

Well now I am thinking whether it could be maybe due to dataclass, but don't think so. This kind of defeats the purpose and kind of forces me to go back to raise NotImplementedError in the parent class, but that lets me initiate, which I want to avoid.

Jan Janáček
  • 109
  • 1
  • 9

1 Answers1

1

The problem here is that abstract static methods are just weird. You'd think that abstract static methods wouldn't be directly callable, or something like that, but that's not what they do. Instead, abstract static methods just make a class abstract, like abstract regular methods.

If you try to instantiate ActionsLogDetail, you'll find you can't, because the class has an abstract static method and an abstract property (inherited from the parent and not overridden), so the class is abstract, and object.__new__ will refuse to create instances of an abstract class. That does absolutely nothing to stop you from calling the abstract static method.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • Well, you are right ofc. It should have occurred to me, but i got mixed up, because I used that staticmethod as a constructor - returning object of that class, therefore somehow thought that I am indeed initiating. Thank you. – Jan Janáček Aug 03 '22 at 14:24
  • @JanJanáček: *Alternative constructors* are usually implemented a `classmethod`s. – martineau Aug 03 '22 at 14:34