1

I'm have a parent class, and I would like to "force" everyone that will inherit from it to implement some specific class attributes.

I don't have this problem with methods, since I have created a dummy method that raises NotImplementedError, which makes it very clear.

As for class attributes- I do not want to create them in the parent class and set them to None since that doesn't force the developer to implement them in the child class.

A little code to demonstrate the current situation:

class Pet(object):
    name = None

    def make_noise(self):
        raise NotImplementedError("Needs to implement in subclass")

    def print_my_name(self):
        print(self.name)

class Dog(Pet):
    # how to force declairing "name" attribute for subclasses?

    def make_noise(self):
        print("Whof Whof")

In this example, developer 1 created Pet class and wanted other developers to implement subclass with a "name" attribute. Developer2 implemented a subclass, but didn't know he needs implement the "name" attribute.

Is it possible to create such restrictions in python?

Nitzan
  • 11
  • 2
  • 1
    See https://docs.python.org/3/library/abc.html , scroll down to the docs for abstractmethod. – codeape Dec 11 '19 at 12:39
  • I feel like name should related to object, if so, you can do .__init__(name)... And if you want some doc to describe dog as a type, you can use .__doc__/.__str__/.__repr__ .etc – Sheng Zhuang Dec 11 '19 at 12:55
  • @ShengZhuang, yeah I tend to agree, i guess i didn't do it that way because in my case the leaf class (dog) is not a direct subclass of the parent (pet), so i didn't want to "drag" that variable in the init of all the other parents, but actually why not? – Nitzan Dec 11 '19 at 13:23

3 Answers3

1

You can try by using ABCMeta metaclass or ABC. After that you can use the @abstractmethod of an @property. eg:

from abc import ABC

class Pet(ABC):
    @abstractmethod
    @property
    def name(self):
        pass

    @abstractmethod
    def make_noise(self):
        raise NotImplementedError("Needs to implement in subclass")

    def print_my_name(self):
        print(self.name)

With this you can add a setter as well with @name.setter.

Kubaba
  • 136
  • 1
  • 8
0

I've had this question for a while as well. After reading the comment by @Sheng Zhuang I think his suggestion is the way to go.

If name is an attribute used by Pet, and indeed must be defined for all Pets but may be different between different types of Pets then the proper way to handle this is with a parameter input to Pet's __init__ function.

class Pet(object):
    def __init__(self, pet_type, name):
        self.pet_type = pet_type
        self.name = name

    def make_noise(self):
        raise NotImplementedError("Needs to implement in subclass")

    def print_my_pet_type(self):
        print(self.pet_type)

    def print_my_name(self):
        print(self.name)

class Dog(Pet):
    def __init__(self, name):
        super().__init__(pet_type='dog', name=name)

    def make_noise(self):
        print("Whof Whof")

I've included pet_type and name for comparison.

pet_type is something that the developer who writes Dog can/should pass into Pet.__init__.

name is something that is still exposed to the end user of Dog class and they can pass in whatever they like.

edit: I think the semantic downside to this is that pet_type is not really an instance attribute the way name is. The intention is that all Dogs will have the same pet_type, so it would be a little more semantically consistent if Pet could somehow enforce that all subclasses must define SubPet.pet_type = as a class attribute, but given that there's no clean way to do that, I think instance attributes passed through super() are the way to go.

Jagerber48
  • 488
  • 4
  • 13
-1

use can use python's Abstract Base Class / ABS or Method Overriding whichever is feasible for you as per your requirements.

Faizan Naseer
  • 589
  • 3
  • 12
  • that looks really cool! in the ABS and method overriding the focus is on the methods and not attributes. I guess if I would use one of this ways i would have to implement a set function – Nitzan Dec 11 '19 at 13:30