2

I already found some similar question where they try to create abstract attributes and they all suggest using @property and @abc.abstractmethod to achieve that like here. There are many similar topics but I cant find a way to do it without using the @property decorator. The reason that I don't want to use it is because I don't want to create setter and getter methods in my concrete classes. I simply want to enforce that my concrete classes will have a specific attribute for example self.filter_name which holds an encrypted version of the class's name.

This is my abstract class at the moment with the @property and @abc.abstractmethod decorators:

import abc
from typing import List

class DataFilter:
    @property
    @abc.abstractmethod
    def filter_name(self)-> str:
        """Returns the filter name encrypted"""
        pass

If I do the above and simply try to set my self.filter_name attribute in my concrete class to a specific value I get an AttributeError: can't set attribute. I wish to only have something like self.filter_name = "blabla" in my concrete class.

KZiovas
  • 3,491
  • 3
  • 26
  • 47
  • what you want is a class method, which has cls input not self – Mahsirat Mar 11 '22 at 15:43
  • have you tried using @classmethod and @abstractmethod? – Mahsirat Mar 11 '22 at 15:44
  • provide the line where you have error – Mahsirat Mar 11 '22 at 15:45
  • @Mahsirat How does replacing the property with a class method help? The OP seems to be trying to simulate abstract "attributes" (which the `ABCMeta` does not provide). – chepner Mar 11 '22 at 15:46
  • @Mahsirat no I ll try now. The error is exactly when I try to assign a value to the self.filter_name attribute but probably you are right let me check. – KZiovas Mar 11 '22 at 15:46
  • Keep in mind that `ABCMeta` doesn't care *what* the subclass assigns to the name `filter_name`, as long as it assigns *something*. The name `abstractmethod` is more aspirational than prescriptive. – chepner Mar 11 '22 at 15:49
  • So using @classmethod is not the answer I think. It does eliminate the error message but also does nothing to enforce that the concrete class implements the self.filter_name. If I dont implement it I get no errors. So that doesn't work – KZiovas Mar 11 '22 at 15:52
  • @chepner Thanks for the reply! When you say that the `abstractmethod` does not care what I assign you refer to enforcing the type ? I know it doesnt do type enforcing at least I want to enforce the existence of it. But thanks for pointing it out ! – KZiovas Mar 11 '22 at 15:53
  • 1
    For example, `class B(DataFilte): filter_name = 3` would be sufficient to *instantiate* `B`, though `B` certainly won't work as intended. – chepner Mar 11 '22 at 16:13

1 Answers1

0

The way to enforce this is not with abstractmethod, but via __init_subclass__.

class DataFilter:
    def __init_subclass__(cls, **kwargs):
       super().__init_subclass__(**kwargs)
       try:
           cls.filter_name
       except AttributeError:
           raise TypeError("Can't instantiate class DataFilter without name 'filter_name'")
    

You can perform additional tests on the value of cls.filter_name if it is present.

chepner
  • 497,756
  • 71
  • 530
  • 681