1

I am not even sure, whether the following is possible. My question is easily described with the following code.

My module is defined as

asdf = 5
class MyClass:
    def myfct(self):
        return asdf

I have a module which defines a complex class. It uses a definition of the module it is in. Here I call it asdf. In fact, asdf is a class definition in itself, I just have it as an integer here for simplicity sake.

I want to remove asdf from the module as a member, but still have the class work. So before deleting it from the module, I first write it into the definition MyClass dynamically after loading the module, then I delete it from the module.

import mymodule

MyClass.asdf = asdf
del sys.modules['mymodule'].asdf

Finally I use this to instantiate the new class

myobj = mymodule.MyClass()
myobj.myfct()

but of course, this throws the error

NameError: name 'asdf' is not defined

How can I make the class work without changing the code of the class, namely without changing return asdf to return self.asdf and but still deleting asdf from the module (and not adding other module attributes). However, I am allowed to change the function dynamically after import mymodule.

Keep in mind that the function definition is very complex, so something like writing it again with exec (https://stackoverflow.com/a/11291851/4533188) is not an option.

One idea of mine is to change the signature of the method dynamically such that it receives an optional argument asdf. That way, the code inside would use that variable, but I do not know how to do that. Possibly helpfull might be Byteplay/Metaclasses:

Make42
  • 12,236
  • 24
  • 79
  • 155
  • 2
    What's the need to delete `mymodule.asdf` at all in the first place? What's wrong with not deleting it and just letting the module work as it does? – blhsing Feb 27 '20 at 17:58

1 Answers1

0

The following answer works, but is semi-great. Basically we save the original method in a dummy variable myfct_original. Then we redefine our function such that the variable MyClass.asdf is copied to the module, the original method is applied, and the variables is removed from the module - so for a short time it is available in the module.

asdf = 5
class MyClass:
    def myfct(self, test=1):
        return asdf

MyClass.asdf = asdf
MyClass.myfct_original = MyClass.myfct

del sys.modules[__name__].asdf
delattr(MyClass, 'myfct')

def newmyfct(self, *args, **kwargs):
    setattr(sys.modules[__name__], 'asdf', MyClass.asdf)
    result = MyClass.myfct_original(self, *args, **kwargs)
    del sys.modules[__name__].asdf
    return result

setattr(MyClass, 'myfct', newmyfct)

myobj = MyClass()
myobj.myfct()

Maybe someone can do better (see end of the question).

Make42
  • 12,236
  • 24
  • 79
  • 155