Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #77653 > unrolled thread
| Started by | ISE Development <isenntp@gmail.com> |
|---|---|
| First post | 2014-09-06 18:13 +0200 |
| Last post | 2014-09-08 00:25 +0200 |
| Articles | 6 — 3 participants |
Back to article view | Back to comp.lang.python
__qualname__ in python 3.3 ISE Development <isenntp@gmail.com> - 2014-09-06 18:13 +0200
Re: __qualname__ in python 3.3 Peter Otten <__peter__@web.de> - 2014-09-06 18:47 +0200
Re: __qualname__ in python 3.3 ISE Development <isenntp@gmail.com> - 2014-09-06 19:09 +0200
Re: __qualname__ in python 3.3 Peter Otten <__peter__@web.de> - 2014-09-06 20:11 +0200
Re: __qualname__ in python 3.3 Antoine Pitrou <antoine@python.org> - 2014-09-07 13:03 +0000
Re: __qualname__ in python 3.3 ISE Development <isenntp@gmail.com> - 2014-09-08 00:25 +0200
| From | ISE Development <isenntp@gmail.com> |
|---|---|
| Date | 2014-09-06 18:13 +0200 |
| Subject | __qualname__ in python 3.3 |
| Message-ID | <540b3293$0$2056$426a74cc@news.free.fr> |
Hi,
When a class is defined within a function, the class generation function's
'__qualname__' attrbute is not qualified a name.
For instance:
def test():
class T:
def method(self):
pass
t = T()
t.method()
When tracing a call to 'test()' using 'sys.settrace()', extracting the
'code' object from the frames of 'call' events and matching it to a
'function' object (using 'gc.get_referrers()') results in the following:
'code' object 'function' object
---------------- ------------------------------------
co_name: test __qualname__: test
co_name: T __qualname__: T
co_name: method __qualname__: test.<locals>.T.method
The second call corresponds to the class definition and not the call to the
constructor (which is in fact a call to 'object.__init__', a C function
hence not traced as a 'call' event - I checked this by disassembling the
code object).
I would expect the second call's '__qualname__' to be 'test.<locals>.T'. Can
this be considered a bug? If so, I'll open one.
-- isedev
[toc] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2014-09-06 18:47 +0200 |
| Message-ID | <mailman.13836.1410022089.18130.python-list@python.org> |
| In reply to | #77653 |
ISE Development wrote: > Hi, > > When a class is defined within a function, the class generation function's > '__qualname__' attrbute is not qualified a name. > > For instance: > > def test(): > class T: > def method(self): > pass > t = T() > t.method() > > When tracing a call to 'test()' using 'sys.settrace()', extracting the > 'code' object from the frames of 'call' events and matching it to a > 'function' object (using 'gc.get_referrers()') results in the following: > > 'code' object 'function' object > ---------------- ------------------------------------ > co_name: test __qualname__: test > co_name: T __qualname__: T > co_name: method __qualname__: test.<locals>.T.method > > The second call corresponds to the class definition and not the call to > the constructor (which is in fact a call to 'object.__init__', a C > function hence not traced as a 'call' event - I checked this by > disassembling the code object). > > I would expect the second call's '__qualname__' to be 'test.<locals>.T'. > Can this be considered a bug? If so, I'll open one. I don't understand what you are doing, so I tried to reproduce the unqualified class name in 3.4 with the simpler approach of returning T: Python 3.4.0 (default, Apr 11 2014, 13:05:11) [GCC 4.8.2] on linux Type "help", "copyright", "credits" or "license" for more information. >>> def test(): ... class T: ... def method(self): pass ... return T ... >>> T = test() >>> T.__qualname__ 'test.<locals>.T' >>> T.method.__qualname__ 'test.<locals>.T.method' If you do it that way with 3.3 (I don't have it handy) do you still see T instead of test.<locals>.T?
[toc] | [prev] | [next] | [standalone]
| From | ISE Development <isenntp@gmail.com> |
|---|---|
| Date | 2014-09-06 19:09 +0200 |
| Message-ID | <540b3fe4$0$2055$426a74cc@news.free.fr> |
| In reply to | #77655 |
Peter Otten wrote:
> ISE Development wrote:
>
>> Hi,
>>
>> When a class is defined within a function, the class generation
>> function's '__qualname__' attrbute is not qualified a name.
>>
>> For instance:
>>
>> def test():
>> class T:
>> def method(self):
>> pass
>> t = T()
>> t.method()
>>
>> When tracing a call to 'test()' using 'sys.settrace()', extracting the
>> 'code' object from the frames of 'call' events and matching it to a
>> 'function' object (using 'gc.get_referrers()') results in the following:
>>
>> 'code' object 'function' object
>> ---------------- ------------------------------------
>> co_name: test __qualname__: test
>> co_name: T __qualname__: T
>> co_name: method __qualname__: test.<locals>.T.method
>>
>> The second call corresponds to the class definition and not the call to
>> the constructor (which is in fact a call to 'object.__init__', a C
>> function hence not traced as a 'call' event - I checked this by
>> disassembling the code object).
>>
>> I would expect the second call's '__qualname__' to be 'test.<locals>.T'.
>> Can this be considered a bug? If so, I'll open one.
>
> I don't understand what you are doing, so I tried to reproduce the
> unqualified class name in 3.4 with the simpler approach of returning T:
>
> Python 3.4.0 (default, Apr 11 2014, 13:05:11)
> [GCC 4.8.2] on linux
> Type "help", "copyright", "credits" or "license" for more information.
>>>> def test():
> ... class T:
> ... def method(self): pass
> ... return T
> ...
>>>> T = test()
>>>> T.__qualname__
> 'test.<locals>.T'
>>>> T.method.__qualname__
> 'test.<locals>.T.method'
>
> If you do it that way with 3.3 (I don't have it handy) do you still see
> T instead of test.<locals>.T?
Python 3.3 behaves in the same way in that case.
This following shows the behaviour I am referring to:
import gc
import sys
import inspect
def global_trace(frame,event,arg):
if event == 'call':
code = frame.f_code
funcs = [obj for obj in gc.get_referrers(code)
if inspect.isfunction(obj)]
if len(funcs) == 1:
f = funcs[0]
print(f.__qualname__)
def test():
class C:
def method(self):
self
c = C()
c.method()
sys.settrace(global_trace)
try:
test()
finally:
sys.settrace(None)
which produces:
test
C
test.<locals>.C.method
[toc] | [prev] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2014-09-06 20:11 +0200 |
| Message-ID | <mailman.13840.1410027079.18130.python-list@python.org> |
| In reply to | #77657 |
ISE Development wrote: > Peter Otten wrote: > >> ISE Development wrote: >> >>> Hi, >>> >>> When a class is defined within a function, the class generation >>> function's '__qualname__' attrbute is not qualified a name. >>> >>> For instance: >>> >>> def test(): >>> class T: >>> def method(self): >>> pass >>> t = T() >>> t.method() >>> >>> When tracing a call to 'test()' using 'sys.settrace()', extracting the >>> 'code' object from the frames of 'call' events and matching it to a >>> 'function' object (using 'gc.get_referrers()') results in the following: >>> >>> 'code' object 'function' object >>> ---------------- ------------------------------------ >>> co_name: test __qualname__: test >>> co_name: T __qualname__: T >>> co_name: method __qualname__: test.<locals>.T.method >>> >>> The second call corresponds to the class definition and not the call to >>> the constructor (which is in fact a call to 'object.__init__', a C >>> function hence not traced as a 'call' event - I checked this by >>> disassembling the code object). >>> >>> I would expect the second call's '__qualname__' to be 'test.<locals>.T'. >>> Can this be considered a bug? If so, I'll open one. >> >> I don't understand what you are doing, so I tried to reproduce the >> unqualified class name in 3.4 with the simpler approach of returning T: >> >> Python 3.4.0 (default, Apr 11 2014, 13:05:11) >> [GCC 4.8.2] on linux >> Type "help", "copyright", "credits" or "license" for more information. >>>>> def test(): >> ... class T: >> ... def method(self): pass >> ... return T >> ... >>>>> T = test() >>>>> T.__qualname__ >> 'test.<locals>.T' >>>>> T.method.__qualname__ >> 'test.<locals>.T.method' >> >> If you do it that way with 3.3 (I don't have it handy) do you still see >> T instead of test.<locals>.T? > > Python 3.3 behaves in the same way in that case. > > This following shows the behaviour I am referring to: > > import gc > import sys > import inspect > > def global_trace(frame,event,arg): > if event == 'call': > code = frame.f_code > funcs = [obj for obj in gc.get_referrers(code) > if inspect.isfunction(obj)] > if len(funcs) == 1: > f = funcs[0] > print(f.__qualname__) > > def test(): > class C: > def method(self): > self > c = C() > c.method() > > sys.settrace(global_trace) > try: > test() > finally: > sys.settrace(None) > > which produces: > > test > C > test.<locals>.C.method OK, I get the same output in Python 3.4. That C seems to be an internal function that helps build the class test.<locals>.C, and I have no expectations as to its name. If anything I'd use something completely different, _init_namespace_C, say. I'm sorry I am not familiar enough with Python's internals to answer your question -- but if in doubt, file a report.
[toc] | [prev] | [next] | [standalone]
| From | Antoine Pitrou <antoine@python.org> |
|---|---|
| Date | 2014-09-07 13:03 +0000 |
| Message-ID | <mailman.13847.1410094999.18130.python-list@python.org> |
| In reply to | #77653 |
Hi,
ISE Development <isenntp <at> gmail.com> writes:
> 'code' object 'function' object
> ---------------- ------------------------------------
> co_name: test __qualname__: test
> co_name: T __qualname__: T
> co_name: method __qualname__: test.<locals>.T.method
>
> The second call corresponds to the class definition and not the call to the
> constructor (which is in fact a call to 'object.__init__', a C function
> hence not traced as a 'call' event - I checked this by disassembling the
> code object).
There's nothing wrong here. That's just the way things are implemented
internally. This may change in the future without prior notice, so
you shouldn't rely on it.
If you want to dig more, you have to look at how the hidden function ("T")
works:
>>> def f():
... class T: pass
...
>>> f.__code__.co_consts
(None, <code object T at 0x7f4d9d0f4a00, file "<stdin>", line 2>, 'T')
>>> dis.dis(f.__code__.co_consts[1])
2 0 LOAD_NAME 0 (__name__)
3 STORE_NAME 1 (__module__)
6 LOAD_CONST 0 ('f.<locals>.T')
9 STORE_NAME 2 (__qualname__)
12 LOAD_CONST 1 (None)
15 RETURN_VALUE
Regards
Antoine.
[toc] | [prev] | [next] | [standalone]
| From | ISE Development <isenntp@gmail.com> |
|---|---|
| Date | 2014-09-08 00:25 +0200 |
| Message-ID | <540cdb4f$0$2926$426a74cc@news.free.fr> |
| In reply to | #77670 |
Antoine Pitrou wrote:
> Hi,
>
> ISE Development <isenntp <at> gmail.com> writes:
>> 'code' object 'function' object
>> ---------------- ------------------------------------
>> co_name: test __qualname__: test
>> co_name: T __qualname__: T
>> co_name: method __qualname__: test.<locals>.T.method
>>
>> The second call corresponds to the class definition and not the call to
>> the constructor (which is in fact a call to 'object.__init__', a C
>> function hence not traced as a 'call' event - I checked this by
>> disassembling the code object).
>
> There's nothing wrong here. That's just the way things are implemented
> internally. This may change in the future without prior notice, so
> you shouldn't rely on it.
>
> If you want to dig more, you have to look at how the hidden function ("T")
> works:
>
>>>> def f():
> ... class T: pass
> ...
>>>> f.__code__.co_consts
> (None, <code object T at 0x7f4d9d0f4a00, file "<stdin>", line 2>, 'T')
>>>> dis.dis(f.__code__.co_consts[1])
> 2 0 LOAD_NAME 0 (__name__)
> 3 STORE_NAME 1 (__module__)
> 6 LOAD_CONST 0 ('f.<locals>.T')
> 9 STORE_NAME 2 (__qualname__)
> 12 LOAD_CONST 1 (None)
> 15 RETURN_VALUE
>
> Regards
>
> Antoine.
Ok, I accept it's implementation specific. That's fair enough.
Yet wouldn't it make more sense to have the 'T' function '__qualname__'
attribute refer to the defining context, i.e. in the present case,
'test.<locals>.T' (much along the lines of the actual method qualified
names, e.g. 'test.<locals>.T.__init__', and identical to the qualified name
of the actual object if returned by the defining function - see Peter Otten
reply)?
The rationale is that a properly qualified name is easier to interpret than
the current unqualified one. To properly identify the 'T' function if a
'class T' is defined in more than enclosing function requires some
additional complex (and hence error prone) logic as things stand: one has to
examine the previous stack frame.
Effectively, I am not saying the current behaviour is wrong, simply that it
is inconsistent and could be improved. In that context, is it worth an
enhancement request?
-- isedev
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web