0

I'm devloping a module that works with another module. The other module requires class attributes to be set before the __init__ method (let's work under the assumption that the behavior of this other module cannot be changed). These class attributes (Signal in the example below) are derived partially from an object that comes from my code.

The method shown below is a disaster for many reasons. For example,

  1. my_obj1 and my_obj2 are not guaranteed to exist; the import in the other module will fail in this case.
  2. There could be a need to create 2 different instances of OtherModuleVodoo1 using 2 different instances from my code (my_obj).

This is a skeleton of the code to explain:

import Signal, Device
from my_module.setup import my_obj1, my_obj2

class OtherModuleVodoo1(Device):
    # The class signal attributes must be defined before the __init__ 
    # and rely upon an object from my module

    x = Signal(my_obj1.cmds['thing_x'], 'thing_x')
    y = Signal(my_obj1.cmds['thing_y'], 'thing_y')

    # ...
    # ...

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)


class OtherModuleVodoo2(Device):
    x = Signal(my_obj2, 'thing1')
    y = Signal(my_obj2, 'thing2')

    # ...
    # ...

    def __init__(self, *args, **kwargs):
       super().__init__(*args, **kwargs)


# now in my file I do this
dev1 = OtherModuleVodoo1()
dev2 = OtherModuleVodoo2()

# but would much prefer to do this 
dev1 = OtherModuleVodoo(my_object_input = my_obj1)
# where I don't need ```Vodoo1, Vodoo2``` but can have a generic 
solution. 

Question:

Is there a way to "input" parameters to the construction of a class (not to the initialization of a class instance)?

What I tried and why each did not work.

  1. Metaclasses. These feel close to the right approach but I wasn't able to get it to work.
  2. __new__ but this doesn't populate the namespace within the class definition (before the __init__)
  3. Setting my_obj1 = None until an OtherModuleVodoo1 instance is needed and then modifying the class attribute before instantiating an object:

An example of attempt 3:

xyq = None
class Test2():
    print(xyq)
    def __init__(self):
        print(self.xyq)

Test2.xyq = 55
t2 = Test2()

However, here the output is:

None
55

I anticipate responses that focus completely on changing the approach. That is warranted. However, my immediate question is how to best band-aid what I have.

2
  • Metaclasses can modify the class before its creation, but only once per class definition and only on code startup. Is that OK? Commented Jul 19, 2018 at 20:11
  • That would be OK and would get me much closer to a reasonable solution! Commented Jul 19, 2018 at 20:15

2 Answers 2

1

This may need some massaging to make it work with your code, but you can use __init_subclass__ in a parent class to accept arguments to class creation. This was introduced in Python 3.6

class Voodoo:
    def __init_subclass__(cls, myobj, **kwargs):
        super().__init_subclass__(**kwargs)
        cls.x = Signal(my_obj1.cmds['thing_x'], 'thing_x')
        cls.y = Signal(my_obj1.cmds['thing_y'], 'thing_y')

class Voodoo1(Voodoo, Device, myobj=myobj1):
    pass

You could also make Voodoo a Device subclass to clean up the signatures of your subclasses.

Sign up to request clarification or add additional context in comments.

Comments

0

Example with a metaclass in Python 3:

class Meta(type):
    def __new__(cls, name, bases, dct):
        dct['xyq'] = 55

        return super().__new__(cls, name, bases, dct)

class A(metaclass=Meta):
    ... # A.xyq == 55

class B(A):
    ... # B.xyq == A.xyq == 55

The metaclass takes action when the classes A and B are created (not instantiated).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.