0

I have a superclass (defined in a framework). Someone makes a subclass of my parent class using my framework (via pip install). Then they init an object of their class. How can I find out all the args AND values that went into that init?

class Parent(object):

class Child(Parent):
    def __init__(self, arg_1, arg_2, some_object):
        pass


obj = Child(2, {'some': 'dict'}, MyObject())

Is there a way to look at the object function to see what values it used? (the object is not created by me... so even looking at self.whatever isn't guaranteed to have all values used in that function call).

some_magic(obj.__init__)  
# {arg_1: 2, arg_2: {'some': 'dict'}, some_object: MyObject_instance}
xela
  • 173
  • 11
  • Use https://docs.python.org/3/library/inspect.html#inspect.signature, you could get something like `)>` – jonrsharpe Sep 26 '19 at 18:32
  • You can use the `dis` disassembler and try to parse the output. – Barmar Sep 26 '19 at 18:32
  • What do you mean by "used"? You mean you want to know if it takes a parameter but doesn't do anything with it? – Barmar Sep 26 '19 at 18:33
  • @jonrsharpe That tells you the parameters it takes, not which ones it uses. – Barmar Sep 26 '19 at 18:34
  • @Barmar sure, but in the example it didn't actually *use* any of them and the OP's expected output is still just the signature binding. – jonrsharpe Sep 26 '19 at 18:34
  • Possible duplicate of [Getting method parameter names in Python](https://stackoverflow.com/questions/218616/getting-method-parameter-names-in-python) – MikeMajara Sep 26 '19 at 18:34
  • I don't see how you can get the parameter bindings *outside* the function itself. Until the function is called, the parameters aren't bound to anything. – Barmar Sep 26 '19 at 18:35
  • This sounds like an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). What is your ultimate goal? – Barmar Sep 26 '19 at 18:37
  • like i said... i want to know which args are used AND the value (even if the object doesn't use them). this is to save a copy of those args in a text file for logging metrics, etc... i don't want to complicate the question with the WHY of why we need this because it's related to distributed training for deep learning models and weight caching/model reconstruction, etc... – xela Sep 26 '19 at 19:33
  • @jonrsharpe signature(obj.__init__) returns the arg names not the actual values... – xela Sep 26 '19 at 19:37
  • @xela Figured it out - was fun; let me know if this works (worked for me for a large module) – OverLordGoldDragon Sep 26 '19 at 19:40
  • i don't have access to the source code... this saving mechanism that needs this operates on a class defined by someone else @OverLordGoldDragon – xela Sep 26 '19 at 19:51
  • @xela How do you use the class if you don't have its source code? When you do `from module import object`, the "import" fetches it "from" somewhere - this "somewhere" is stored in `module.__file__` – OverLordGoldDragon Sep 26 '19 at 19:53
  • @xela Also, if you seek to inspect a _previously initialized_ object (which you can no longer re-initialize), I doubt this can be done - as objects don't preserve their modification history metadata unless explicitly programmed to do so. Your best bet is `print(object.__dict__)`, but any attributes you see may have been modified after `__init__()` – OverLordGoldDragon Sep 26 '19 at 20:15
  • @xela of course it does, until you [bind](https://docs.python.org/3/library/inspect.html#inspect.Signature.bind) it you haven't even told it what the arguments are. – jonrsharpe Sep 27 '19 at 06:34
  • the pattern for my code is that someone subclasses my class and instantiates their subclass. when they call save, i want to know what parameters they used in the init... so i can reload and re-init their object for them. however there is no guarantee they tracked the arguments they used to init, so i can’t just use object.__dict__ – xela Sep 27 '19 at 13:03
  • @xela This is very different from your original question - the intended usage matters. Worth updating the question. So to clarify, the usage is: (1) you make a class; (2) someone uses that class in THEIR class, as a subclass; (3) you want to get the init args and values of _both_ your class and their (super) class, from a _save_ of their object? (Also, use @ to notify users of your response) – OverLordGoldDragon Sep 27 '19 at 19:03
  • 1) I make a class. 2) They subclass my class. 3) they init an object of their class. 4) i want to know the params and values that went into the init – xela Sep 27 '19 at 19:54
  • @xela See new answer – OverLordGoldDragon Sep 28 '19 at 19:31

1 Answers1

0

You can get the user arguments and their values that are passed into your subclass, as follows:

class MyClass():
    def __init__(self, arg1, arg2=2):
        self.arg1 = arg1
        self.arg2 = arg2
        self.user_args = dict([(key,val) for key,val in locals().items() 
                                       if key!='self' and key!='__class__'])
    # def other_methods() ...

Then, when user creates own class usr_class = UserClass(a, b, some_object=MyClass(5, 10)) - you can:

print(user_class.some_object.user_args)
# {'arg1': 5, 'arg2': 10}


If you seek to also get the UserClass arguments, that's vastly more involved, if even reliably possible; a major complication is, MyClass is passed to UserClass as an argument, rather than inherited - meaning, MyClass is first instantiated, then set as an attribute to UserClass. In other words, as far as MyClass is concerned, UserClass doesn't exist.

One way I see to get UserClass args without inheritance is, decompile the pycache generated during runtime, which can be accessed from within MyClass via globals() - but it won't be easy.

OverLordGoldDragon
  • 1
  • 9
  • 53
  • 101