Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit153b3f7

Browse files
gh-118465: Add __firstlineno__ attribute to class (GH-118475)
It is set by compiler with the line number of the first line ofthe class definition.
1 parent716ec4b commit153b3f7

17 files changed

+61
-89
lines changed

‎Doc/reference/datamodel.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@ A class object can be called (see above) to yield a class instance (see below).
971971
single: __annotations__ (class attribute)
972972
single: __type_params__ (class attribute)
973973
single: __static_attributes__ (class attribute)
974+
single: __firstlineno__ (class attribute)
974975

975976
Special attributes:
976977

@@ -1005,6 +1006,9 @@ Special attributes:
10051006
A tuple containing names of attributes of this class which are accessed
10061007
through ``self.X`` from any function in its body.
10071008

1009+
:attr:`__firstlineno__`
1010+
The line number of the first line of the class definition, including decorators.
1011+
10081012

10091013
Class instances
10101014
---------------

‎Doc/whatsnew/3.13.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,11 @@ Other Language Changes
328328
class scopes are not inlined into their parent scope. (Contributed by
329329
Jelle Zijlstra in:gh:`109118` and:gh:`118160`.)
330330

331+
* Classes have a new:attr:`!__firstlineno__` attribute,
332+
populated by the compiler, with the line number of the first line
333+
of the class definition.
334+
(Contributed by Serhiy Storchaka in:gh:`118465`.)
335+
331336
* ``from __future__ import ...`` statements are now just normal
332337
relative imports if dots are present before the module name.
333338
(Contributed by Jeremiah Gabriel Pascual in:gh:`118216`.)

‎Include/internal/pycore_global_objects_fini_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ struct _Py_global_strings {
113113
STRUCT_FOR_ID(__eq__)
114114
STRUCT_FOR_ID(__exit__)
115115
STRUCT_FOR_ID(__file__)
116+
STRUCT_FOR_ID(__firstlineno__)
116117
STRUCT_FOR_ID(__float__)
117118
STRUCT_FOR_ID(__floordiv__)
118119
STRUCT_FOR_ID(__format__)

‎Include/internal/pycore_runtime_init_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Include/internal/pycore_unicodeobject_generated.h

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎Lib/enum.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2035,7 +2035,7 @@ def _test_simple_enum(checked_enum, simple_enum):
20352035
)
20362036
forkeyinset(checked_keys+simple_keys):
20372037
ifkeyin ('__module__','_member_map_','_value2member_map_','__doc__',
2038-
'__static_attributes__'):
2038+
'__static_attributes__','__firstlineno__'):
20392039
# keys known to be different, or very long
20402040
continue
20412041
elifkeyinmember_names:

‎Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ def _write_atomic(path, data, mode=0o666):
471471
# Python 3.13a1 3567 (Reimplement line number propagation by the compiler)
472472
# Python 3.13a1 3568 (Change semantics of END_FOR)
473473
# Python 3.13a5 3569 (Specialize CONTAINS_OP)
474+
# Python 3.13a6 3570 (Add __firstlineno__ class attribute)
474475

475476
# Python 3.14 will start with 3600
476477

@@ -487,7 +488,7 @@ def _write_atomic(path, data, mode=0o666):
487488
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
488489
# in PC/launcher.c must also be updated.
489490

490-
MAGIC_NUMBER= (3569).to_bytes(2,'little')+b'\r\n'
491+
MAGIC_NUMBER= (3570).to_bytes(2,'little')+b'\r\n'
491492

492493
_RAW_MAGIC_NUMBER=int.from_bytes(MAGIC_NUMBER,'little')# For import.c
493494

‎Lib/inspect.py

Lines changed: 5 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,79 +1035,6 @@ class ClassFoundException(Exception):
10351035
pass
10361036

10371037

1038-
class_ClassFinder(ast.NodeVisitor):
1039-
1040-
def__init__(self,cls,tree,lines,qualname):
1041-
self.stack= []
1042-
self.cls=cls
1043-
self.tree=tree
1044-
self.lines=lines
1045-
self.qualname=qualname
1046-
self.lineno_found= []
1047-
1048-
defvisit_FunctionDef(self,node):
1049-
self.stack.append(node.name)
1050-
self.stack.append('<locals>')
1051-
self.generic_visit(node)
1052-
self.stack.pop()
1053-
self.stack.pop()
1054-
1055-
visit_AsyncFunctionDef=visit_FunctionDef
1056-
1057-
defvisit_ClassDef(self,node):
1058-
self.stack.append(node.name)
1059-
ifself.qualname=='.'.join(self.stack):
1060-
# Return the decorator for the class if present
1061-
ifnode.decorator_list:
1062-
line_number=node.decorator_list[0].lineno
1063-
else:
1064-
line_number=node.lineno
1065-
1066-
# decrement by one since lines starts with indexing by zero
1067-
self.lineno_found.append((line_number-1,node.end_lineno))
1068-
self.generic_visit(node)
1069-
self.stack.pop()
1070-
1071-
defget_lineno(self):
1072-
self.visit(self.tree)
1073-
lineno_found_number=len(self.lineno_found)
1074-
iflineno_found_number==0:
1075-
raiseOSError('could not find class definition')
1076-
eliflineno_found_number==1:
1077-
returnself.lineno_found[0][0]
1078-
else:
1079-
# We have multiple candidates for the class definition.
1080-
# Now we have to guess.
1081-
1082-
# First, let's see if there are any method definitions
1083-
formemberinself.cls.__dict__.values():
1084-
if (isinstance(member,types.FunctionType)and
1085-
member.__module__==self.cls.__module__):
1086-
forlineno,end_linenoinself.lineno_found:
1087-
iflineno<=member.__code__.co_firstlineno<=end_lineno:
1088-
returnlineno
1089-
1090-
class_strings= [(''.join(self.lines[lineno:end_lineno]),lineno)
1091-
forlineno,end_linenoinself.lineno_found]
1092-
1093-
# Maybe the class has a docstring and it's unique?
1094-
ifself.cls.__doc__:
1095-
ret=None
1096-
forcandidate,linenoinclass_strings:
1097-
ifself.cls.__doc__.strip()incandidate:
1098-
ifretisNone:
1099-
ret=lineno
1100-
else:
1101-
break
1102-
else:
1103-
ifretisnotNone:
1104-
returnret
1105-
1106-
# We are out of ideas, just return the last one found, which is
1107-
# slightly better than previous ones
1108-
returnself.lineno_found[-1][0]
1109-
1110-
11111038
deffindsource(object):
11121039
"""Return the entire source file and starting line number for an object.
11131040
@@ -1140,11 +1067,11 @@ def findsource(object):
11401067
returnlines,0
11411068

11421069
ifisclass(object):
1143-
qualname=object.__qualname__
1144-
source=''.join(lines)
1145-
tree=ast.parse(source)
1146-
class_finder=_ClassFinder(object,tree,lines,qualname)
1147-
returnlines,class_finder.get_lineno()
1070+
try:
1071+
firstlineno=object.__firstlineno__
1072+
exceptAttributeError:
1073+
raiseOSError('source code not available')
1074+
returnlines,object.__firstlineno__-1
11481075

11491076
ifismethod(object):
11501077
object=object.__func__

‎Lib/pydoc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ def visiblename(name, all=None, obj=None):
326326
'__date__','__doc__','__file__','__spec__',
327327
'__loader__','__module__','__name__','__package__',
328328
'__path__','__qualname__','__slots__','__version__',
329-
'__static_attributes__'}:
329+
'__static_attributes__','__firstlineno__'}:
330330
return0
331331
# Private names are hidden, but special names are displayed.
332332
ifname.startswith('__')andname.endswith('__'):return1

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp