-2

I'm trying to come up with a way to allow specification of any number of class attributes upon instantiation, very similar to a dictionary. Ideal use case:

>>> instance = BlankStruct(spam=0, eggs=1)
>>> instance.spam
0
>>> instance.eggs
1

where BlankStruct is defined as:

class BlankStruct(Specifiable):
    @Specifiable.specifiable
    def __init__(self, **kwargs):
        pass

I was thinking of using a parent class decorator, but am lost in a mind-trip about whether to use instance methods, class methods or static methods (or possibly none of the above!). This is the best I've come up with so far, but the problem is that the attributes are applied to the class instead of the instance:

class Specifiable:
    @classmethod
    def specifiable(cls, constructor):
        def constructor_wrapper(*args, **kwargs):
            constructor(*args, **kwargs)
            cls.set_attrs(**kwargs)
        return constructor_wrapper

    @classmethod
    def set_attrs(cls, **kwargs):
        for key in kwargs:
            setattr(cls, key, kwargs[key])

How can I make such a parent class?


NOTE: Yes, I know what I'm trying to do is bad practice. But sometimes you just have to do what your boss tells you.

Nathaniel Jones
  • 939
  • 1
  • 14
  • 25
  • Are the downvotes here because this is a poorly asked question, or because what I'm trying to do is frowned upon? If the former: Ok, please leave a comment or suggest an edit. If the latter: This seems unnecessary. Good/bad practice can be addressed in answers and comments, which can be helpful to future readers. – Nathaniel Jones Sep 18 '20 at 22:47
  • what is `@Specifiable.specifiable`?? I didn't downvote, btw, just noticed this question was from a year ago... – juanpa.arrivillaga Sep 18 '20 at 22:56
  • @juanpa.arrivillaga It's a parent class I had created to help me achieve the desired functionality for `BlankStruct`. (Though, as stated in the question, it wasn't working as desired.) It's defined in the third code block. – Nathaniel Jones Sep 21 '20 at 20:46

2 Answers2

2

Yes, you can do the following, however I do NOT recommend as this clearly goes against the explicit is better than implicit principle:

class BlankStruct:

    def __init__(self, **attrs):
        self.__dict__.update(**attrs)
    def __getattr__(self, attr):
        return self.__dict__.get(attr, None)

f = BlankStruct(spam=0, eggs=1)

A more complete response is available here and inspired this answer.

I would recommend being explicit in terms of the properties you want your class to have. Otherwise, you are left with a class that has a high degree of variability, which likely detracts for it's usefulness.

rahlf23
  • 8,869
  • 4
  • 24
  • 54
0

I believe you can do this without decorators:

class Specifiable:

  def __init__(self, **kwargs):
    for key, value in kwargs.items():
      setattr(self, key, value)


class BlankStruct(Specifiable):

  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    # Do other stuff.
luther
  • 5,195
  • 1
  • 14
  • 24