Get the source of a class reliably?!?
dieter
dieter at handshake.de
Tue Apr 30 02:38:55 EDT 2019
"computermaster360 ." <computermaster360 at gmail.com> writes:
> Does anyone have an idea why classes don't contain their definition
> line number as functions or methods do?
>
>>>> some_fun.__code__.co_firstlineno
> 123
Because classes do not have associated "code" objects.
As you see above, it is not the function itself ("some_fun" in
your case) that carries the line information but the associated
"code object" ("some_fun.__code__").
Functions typically are executed several times and
each execution needs to execute the associated code;
therefore, functions reference this code.
There is no specific code directly associated with a class:
general (i.e. not class specific) code is used to collect
the operands for the class contruction (i.e. base classes, attribute/method
definitions), then the class' metaclass is used to really construct
the class object. Therefore, class objects have no associated "code object".
> ...
> This leads to some funny stuff when using `inspect`, such as this:
>
> -- weird.py -----------------------------
> """
> class C:
> HAHAHA! YOU FOOL!
> """
>
> class C:
> "this is a perfectly ok class"
> ...
>>>> inspect.getsource(weird.C)
> class C:
> HAHAHA! YOU FOOL!
>
>
> Why ???
In order to answer questions of this kind yourself, you
can use the fact that Python is open source.
A look into "inspect.py" shows that Python uses the following
code to find the source lines for a class:
if isclass(object):
name = object.__name__
pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
# make some effort to find the best matching class definition:
# use the one with the least indentation, which is the one
# that's most probably not inside a function definition.
candidates = []
for i in range(len(lines)):
match = pat.match(lines[i])
if match:
# if it's at toplevel, it's already the best one
if lines[i][0] == 'c':
return lines, i
# else add whitespace to candidate list
candidates.append((match.group(1), i))
if candidates:
# this will sort by whitespace, and by line number,
# less whitespace first
candidates.sort()
return lines, candidates[0][1]
The comment "make some effort ..." indicates that the author
knew that the result will not be correct in all cases.
You have found such a case.
More information about the Python-list
mailing list