3

The __qualname__ attribute is useful to me because it contextualizes functions; however, it's difficult for me to use for my use case because:

  1. __qualname__ returns a string. For my usecase, I need references to the parent object(s).

  2. __qualname__ sometimes returns the super class instead of the referenced class. For example:

    class Parent():
    
        def __init__(self):
            pass
    
    
    class Child(Parent):
        pass
    
    
    print(Child.__init__.__qualname__)  # Prints: "Parent.__init__"
    
  3. The package I am developing needs to be robust, and the edge cases for __qualname__ are not documented as far as I can tell.

Outside of parsing the Python file with ast, can __qualname__ be reimplemented in Python3 with inspection? How does Python implement __qualname__? In reimplementing the core functionality, I think I'll be able to adapt it for my use case.


Prior Research:

I was unable to find the qualname implementation in the Python source code.

  • 2
    Can you give a short glimpse in what you're trying to achieve using the `__qualname__` attribute ? Meaning which problem do you want to solve using `__qualname__` ? Maybe there are alternative approaches that come to peoples mind. – klaas Sep 07 '20 at 19:40
  • 2
    Why do you call `__qualname__` output in your example "unexpected"? Since child class doesn't override `__init__`, it get's it inherited from parent class. `__qualname__` returns the string path to method reference, which in this case will be parents `__init__`. – ptyshevs Sep 07 '20 at 19:53
  • Thanks for looking into this :) @klaas I am looking to reconstruct the dotted path given a reference to function or method. For example, if provided a reference to `Child.__init__`, I'd like to be able to return a list consisting of `[Child, Child.__init__]`. This is similar but more general than something like this: https://stackoverflow.com/questions/3589311/get-defining-class-of-unbound-method-object-in-python-3/25959545#25959545 – Michael Petrochuk Sep 07 '20 at 23:19
  • Thanks for getting clarification! @ptyshevs The two functions `Child.__init__` and `Parent.__init__` are different, I think. For example, `Child.__init__` can be decorated separately from `Parent.__init__`. Even so, they have the same `__qualname__`. I didn't expect that two methods could be uniquely decorated and have the same `__qualname__`. – Michael Petrochuk Sep 07 '20 at 23:19
  • @MichaelPetrochuk: But they're not different. They're literally the same object. – user2357112 Sep 07 '20 at 23:33
  • Sure, you could have applied separate decorators to `Child.__init__` and `Parent.__init__`, and if you had, you would probably have two different functions, but you didn't. – user2357112 Sep 07 '20 at 23:34
  • Also, "`__qualname__` returns a string instead of references." - well, yeah. It's a name. What did you want instead? I don't see a good alternative that would still preserve `__qualname__`'s functionality. – user2357112 Sep 07 '20 at 23:37
  • I am not here to argue about the design choices behind `__qualname__`. The implementation of `__qualname__` doesn't suit my application, and I need help to reimplement the functionality. In doing so, I'll be able to adjust it to the specification the application requires. – Michael Petrochuk Sep 08 '20 at 00:34
  • Okay, but what did you want instead? You haven't made that clear. – user2357112 Sep 08 '20 at 00:38
  • 1
    [Here's where CPython determines a function or class's `__qualname__`.](https://github.com/python/cpython/blob/v3.8.5/Python/compile.c#L679) It happens at compile time, and works off of parse tree information. – user2357112 Sep 08 '20 at 00:39
  • 1
    Like the question asks... I'm trying to: "Reimplement Python's `__qualname__` in Python 3.7". Can you help me with that? In order to be helpful, I have adjusted the post to clarify my intentions and perspective. Sorry for the confusion, and thanks for your patience. I'm doing my best! – Michael Petrochuk Sep 08 '20 at 00:46

1 Answers1

4

You're not going to get what you want. You want your_thing(Parent.__init__) to say something about Parent and your_thing(Child.__init__) to say something about Child, but Parent.__init__ and Child.__init__ are the same exact object.

You've accessed that object two different ways, but Python keeps no record of that. Whatever you implement will only receive a function object, without the information you're looking for.

Even if you do some horrible stack inspection thing to look at the fact that the source code for your_thing(Child.__init__) says "Child" in it, that won't work for cases where the function gets stored in a variable or passed around through a few more layers of function calls. It'll only work, unreliably, for a fraction of cases where you don't need it because you already had the information you wanted when you were writing the code.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • As mentioned earlier, the objective is to reimplement `__qualname__`. – Michael Petrochuk Sep 08 '20 at 01:19
  • 2
    @MichaelPetrochuk: The objective is to reimplement `__qualname__` *with adjustments*, one of which is impossible. (Adjustment 1 is pretty trivial, but adjustment 2 is not.) If it wasn't for the adjustments, you would just use `__qualname__`. – user2357112 Sep 08 '20 at 01:21