An Informal Introduction to Python

3. An Informal Introduction to Python¶
In the following examples, input and output are distinguished by the presence or absence of prompts (>>> and …): to repeat the example, you must type everything after the prompt, when the prompt appears; lines that do not begin with a prompt are output from the interpreter. Note that a secondary prompt on a line by itself in an example means you must type a blank line; this is used to end a multi-line command.
You can use the “Copy” button (it appears in the upper-right corner when hovering over or tapping a code example), which strips prompts and omits output, to copy and paste the input lines into your interpreter.
Many of the examples in this manual, even those entered at the interactive
prompt, include comments. Comments in Python start with the hash character,
#
, and extend to the end of the physical line. A comment may appear at the
start of a line or following whitespace or code, but not within a string
literal. A hash character within a string literal is just a hash character.
Since comments are to clarify code and are not interpreted by Python, they may
be omitted when typing in examples.
Some examples:
# this is the first comment
spam = 1 # and this is the second comment
# ... and now a third!
text = "# This is not a comment because it's inside quotes."
3.1. Using Python as a Calculator¶
Let’s try some simple Python commands. Start the interpreter and wait for the
primary prompt, >>>
. (It shouldn’t take long.)
3.1.1. Numbers¶
The interpreter acts as a simple calculator: you can type an expression into it
and it will write the value. Expression syntax is straightforward: the
operators +
, -
, *
and /
can be used to perform
arithmetic; parentheses (()
) can be used for grouping.
For example:
>>> 2 + 2
4
>>> 50 - 5*6
20
>>> (50 - 5*6) / 4
5.0
>>> 8 / 5 # division always returns a floating-point number
1.6
The integer numbers (e.g. 2
, 4
, 20
) have type int
,
the ones with a fractional part (e.g. 5.0
, 1.6
) have type
float
. We will see more about numeric types later in the tutorial.
Division (/
) always returns a float. To do floor division and
get an integer result you can use the //
operator; to calculate
the remainder you can use %
:
>>> 17 / 3 # classic division returns a float
5.666666666666667
>>>
>>> 17 // 3 # floor division discards the fractional part
5
>>> 17 % 3 # the % operator returns the remainder of the division
2
>>> 5 * 3 + 2 # floored quotient * divisor + remainder
17
With Python, it is possible to use the **
operator to calculate powers [1]:
>>> 5 ** 2 # 5 squared
25
>>> 2 ** 7 # 2 to the power of 7
128
The equal sign (=
) is used to assign a value to a variable. Afterwards, no
result is displayed before the next interactive prompt:
>>> width = 20
>>> height = 5 * 9
>>> width * height
900
If a variable is not “defined” (assigned a value), trying to use it will give you an error:
>>> n # try to access an undefined variable
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'n' is not defined
There is full support for floating point; operators with mixed type operands convert the integer operand to floating point:
>>> 4 * 3.75 - 1
14.0
In interactive mode, the last printed expression is assigned to the variable
_
. This means that when you are using Python as a desk calculator, it is
somewhat easier to continue calculations, for example:
>>> tax = 12.5 / 100
>>> price = 100.50
>>> price * tax
12.5625
>>> price + _
113.0625
>>> round(_, 2)
113.06
This variable should be treated as read-only by the user. Don’t explicitly assign a value to it — you would create an independent local variable with the same name masking the built-in variable with its magic behavior.
In addition to int
and float
, Python supports other types of
numbers, such as Decimal
and Fraction
.
Python also has built-in support for complex numbers,
and uses the j
or J
suffix to indicate the imaginary part
(e.g. 3+5j
).
3.1.2. Text¶
Python can manipulate text (represented by type str
, so-called
“strings”) as well as numbers. This includes characters “!
”, words
“rabbit
”, names “Paris
”, sentences “Got your back.
”, etc.
“Yay! :)
”. They can be enclosed in single quotes ('...'
) or double
quotes ("..."
) with the same result [2].
>>> 'spam eggs' # single quotes
'spam eggs'
>>> "Paris rabbit got your back :)! Yay!" # double quotes
'Paris rabbit got your back :)! Yay!'
>>> '1975' # digits and numerals enclosed in quotes are also strings
'1975'
To quote a quote, we need to “escape” it, by preceding it with \
.
Alternatively, we can use the other type of quotation marks:
>>> 'doesn\'t' # use \' to escape the single quote...
"doesn't"
>>> "doesn't" # ...or use double quotes instead
"doesn't"
>>> '"Yes," they said.'
'"Yes," they said.'
>>> "\"Yes,\" they said."
'"Yes," they said.'
>>> '"Isn\'t," they said.'
'"Isn\'t," they said.'
In the Python shell, the string definition and output string can look
different. The print()
function produces a more readable output, by
omitting the enclosing quotes and by printing escaped and special characters:
>>> s = 'First line.\nSecond line.' # \n means newline
>>> s # without print(), special characters are included in the string
'First line.\nSecond line.'
>>> print(s) # with print(), special characters are interpreted, so \n produces new line
First line.
Second line.
If you don’t want characters prefaced by \
to be interpreted as
special characters, you can use raw strings by adding an r
before
the first quote:
>>> print('C:\some\name') # here \n means newline!
C:\some
ame
>>> print(r'C:\some\name') # note the r before the quote
C:\some\name
There is one subtle aspect to raw strings: a raw string may not end in
an odd number of \
characters; see
the FAQ entry for more information
and workarounds.
String literals can span multiple lines. One way is using triple-quotes:
"""..."""
or '''...'''
. End-of-line characters are automatically
included in the string, but it’s possible to prevent this by adding a \
at
the end of the line. In the following example, the initial newline is not
included:
>>> print("""\
... Usage: thingy [OPTIONS]
... -h Display this usage message
... -H hostname Hostname to connect to
... """)
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
>>>
Strings can be concatenated (glued together) with the +
operator, and
repeated with *
:
>>> # 3 times 'un', followed by 'ium'
>>> 3 * 'un' + 'ium'
'unununium'
Two or more string literals (i.e. the ones enclosed between quotes) next to each other are automatically concatenated.
>>> 'Py' 'thon'
'Python'
This feature is particularly useful when you want to break long strings:
>>> text = ('Put several strings within parentheses '
... 'to have them joined together.')
>>> text
'Put several strings within parentheses to have them joined together.'
This only works with two literals though, not with variables or expressions:
>>> prefix = 'Py'
>>> prefix 'thon' # can't concatenate a variable and a string literal
File "<stdin>", line 1
prefix 'thon'
^^^^^^
SyntaxError: invalid syntax
>>> ('un' * 3) 'ium'
File "<stdin>", line 1
('un' * 3) 'ium'
^^^^^
SyntaxError: invalid syntax
If you want to concatenate variables or a variable and a literal, use +
:
>>> prefix + 'thon'
'Python'
Strings can be indexed (subscripted), with the first character having index 0. There is no separate character type; a character is simply a string of size one:
>>> word = 'Python'
>>> word[0] # character in position 0
'P'
>>> word[5] # character in position 5
'n'
Indices may also be negative numbers, to start counting from the right:
>>> word[-1] # last character
'n'
>>> word[-2] # second-last character
'o'
>>> word[-6]
'P'
Note that since -0 is the same as 0, negative indices start from -1.
In addition to indexing, slicing is also supported. While indexing is used to obtain individual characters, slicing allows you to obtain a substring:
>>> word[0:2] # characters from position 0 (included) to 2 (excluded)
'Py'
>>> word[2:5] # characters from position 2 (included) to 5 (excluded)
'tho'
Slice indices have useful defaults; an omitted first index defaults to zero, an omitted second index defaults to the size of the string being sliced.
>>> word[:2] # character from the beginning to position 2 (excluded)
'Py'
>>> word[4:] # characters from position 4 (included) to the end
'on'
>>> word[-2:] # characters from the second-last (included) to the end
'on'
Note how the start is always included, and the end always excluded. This
makes sure that s[:i] + s[i:]
is always equal to s
:
>>> word[:2] + word[2:]
'Python'
>>> word[:4] + word[4:]
'Python'
One way to remember how slices work is to think of the indices as pointing between characters, with the left edge of the first character numbered 0. Then the right edge of the last character of a string of n characters has index n, for example:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
The first row of numbers gives the position of the indices 0…6 in the string; the second row gives the corresponding negative indices. The slice from i to j consists of all characters between the edges labeled i and j, respectively.
For non-negative indices, the length of a slice is the difference of the
indices, if both are within bounds. For example, the length of word[1:3]
is
2.
Attempting to use an index that is too large will result in an error:
>>> word[42] # the word only has 6 characters
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
However, out of range slice indexes are handled gracefully when used for slicing:
>>> word[4:42]
'on'
>>> word[42:]
''
Python strings cannot be changed — they are immutable. Therefore, assigning to an indexed position in the string results in an error:
>>> word[0] = 'J'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> word[2:] = 'py'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
If you need a different string, you should create a new one:
>>> 'J' + word[1:]
'Jython'
>>> word[:2] + 'py'
'Pypy'
The built-in function len()
returns the length of a string:
>>> s = 'supercalifragilisticexpialidocious'
>>> len(s)
34
See also
- Text Sequence Type — str
Strings are examples of sequence types, and support the common operations supported by such types.
- String Methods
Strings support a large number of methods for basic transformations and searching.
- f-strings
String literals that have embedded expressions.
- Format String Syntax
Information about string formatting with
str.format()
.- printf-style String Formatting
The old formatting operations invoked when strings are the left operand of the
%
operator are described in more detail here.
3.1.3. Lists¶
Python knows a number of compound data types, used to group together other values. The most versatile is the list, which can be written as a list of comma-separated values (items) between square brackets. Lists might contain items of different types, but usually the items all have the same type.
>>> squares = [1, 4, 9, 16, 25]
>>> squares
[1, 4, 9, 16, 25]
Like strings (and all other built-in sequence types), lists can be indexed and sliced:
>>> squares[0] # indexing returns the item
1
>>> squares[-1]
25
>>> squares[-3:] # slicing returns a new list
[9, 16, 25]
Lists also support operations like concatenation:
>>> squares + [36, 49, 64, 81, 100]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Unlike strings, which are immutable, lists are a mutable type, i.e. it is possible to change their content:
>>> cubes = [1, 8, 27, 65, 125] # something's wrong here
>>> 4 ** 3 # the cube of 4 is 64, not 65!
64
>>> cubes[3] = 64 # replace the wrong value
>>> cubes
[1, 8, 27, 64, 125]
You can also add new items at the end of the list, by using
the list.append()
method (we will see more about methods later):
>>> cubes.append(216) # add the cube of 6
>>> cubes.append(7 ** 3) # and the cube of 7
>>> cubes
[1, 8, 27, 64, 125, 216, 343]
Simple assignment in Python never copies data. When you assign a list to a variable, the variable refers to the existing list. Any changes you make to the list through one variable will be seen through all other variables that refer to it.:
>>> rgb = ["Red", "Green", "Blue"]
>>> rgba = rgb
>>> id(rgb) == id(rgba) # they reference the same object
True
>>> rgba.append("Alph")
>>> rgb
["Red", "Green", "Blue", "Alph"]
All slice operations return a new list containing the requested elements. This means that the following slice returns a shallow copy of the list:
>>> correct_rgba = rgba[:]
>>> correct_rgba[-1] = "Alpha"
>>> correct_rgba
["Red", "Green", "Blue", "Alpha"]
>>> rgba
["Red", "Green", "Blue", "Alph"]
Assignment to slices is also possible, and this can even change the size of the list or clear it entirely:
>>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> letters
['a', 'b', 'c', 'd', 'e', 'f', 'g']
>>> # replace some values
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a', 'b', 'C', 'D', 'E', 'f', 'g']
>>> # now remove them
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
>>> # clear the list by replacing all the elements with an empty list
>>> letters[:] = []
>>> letters
[]
The built-in function len()
also applies to lists:
>>> letters = ['a', 'b', 'c', 'd']
>>> len(letters)
4
It is possible to nest lists (create lists containing other lists), for example:
>>> a = ['a', 'b', 'c']
>>> n = [1, 2, 3]
>>> x = [a, n]
>>> x
[['a', 'b', 'c'], [1, 2, 3]]
>>> x[0]
['a', 'b', 'c']
>>> x[0][1]
'b'
3.2. First Steps Towards Programming¶
Of course, we can use Python for more complicated tasks than adding two and two together. For instance, we can write an initial sub-sequence of the Fibonacci series as follows:
>>> # Fibonacci series:
>>> # the sum of two elements defines the next
>>> a, b = 0, 1
>>> while a < 10:
... print(a)
... a, b = b, a+b
...
0
1
1
2
3
5
8
This example introduces several new features.
The first line contains a multiple assignment: the variables
a
andb
simultaneously get the new values 0 and 1. On the last line this is used again, demonstrating that the expressions on the right-hand side are all evaluated first before any of the assignments take place. The right-hand side expressions are evaluated from the left to the right.The
while
loop executes as long as the condition (here:a < 10
) remains true. In Python, like in C, any non-zero integer value is true; zero is false. The condition may also be a string or list value, in fact any sequence; anything with a non-zero length is true, empty sequences are false. The test used in the example is a simple comparison. The standard comparison operators are written the same as in C:<
(less than),>
(greater than),==
(equal to),<=
(less than or equal to),>=
(greater than or equal to) and!=
(not equal to).The body of the loop is indented: indentation is Python’s way of grouping statements. At the interactive prompt, you have to type a tab or space(s) for each indented line. In practice you will prepare more complicated input for Python with a text editor; all decent text editors have an auto-indent facility. When a compound statement is entered interactively, it must be followed by a blank line to indicate completion (since the parser cannot guess when you have typed the last line). Note that each line within a basic block must be indented by the same amount.
The
print()
function writes the value of the argument(s) it is given. It differs from just writing the expression you want to write (as we did earlier in the calculator examples) in the way it handles multiple arguments, floating-point quantities, and strings. Strings are printed without quotes, and a space is inserted between items, so you can format things nicely, like this:>>> i = 256*256 >>> print('The value of i is', i) The value of i is 65536
The keyword argument end can be used to avoid the newline after the output, or end the output with a different string:
>>> a, b = 0, 1 >>> while a < 1000: ... print(a, end=',') ... a, b = b, a+b ... 0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,
Footnotes

File
, line
, in
:
File
, line
:
File
, line
:
File
, line
, in
:
File
, line
, in
:
File
, line
, in
:


Debugging C API extensions and CPython Internals with GDB¶
This document explains how the Python GDB extension, python-gdb.py
, can
be used with the GDB debugger to debug CPython extensions and the
CPython interpreter itself.
When debugging low-level problems such as crashes or deadlocks, a low-level debugger, such as GDB, is useful to diagnose and correct the issue. By default, GDB (or any of its front-ends) doesn’t support high-level information specific to the CPython interpreter.
The python-gdb.py
extension adds CPython interpreter information to GDB.
The extension helps introspect the stack of currently executing Python functions.
Given a Python object represented by a PyObject* pointer,
the extension surfaces the type and value of the object.
Developers who are working on CPython extensions or tinkering with parts
of CPython that are written in C can use this document to learn how to use the
python-gdb.py
extension with GDB.
Note
This document assumes that you are familiar with the basics of GDB and the CPython C API. It consolidates guidance from the devguide and the Python wiki.
Prerequisites¶
You need to have:
GDB 7 or later. (For earlier versions of GDB, see
Misc/gdbinit
in the sources of Python 3.11 or earlier.)GDB-compatible debugging information for Python and any extension you are debugging.
The
python-gdb.py
extension.
The extension is built with Python, but might be distributed separately or not at all. Below, we include tips for a few common systems as examples. Note that even if the instructions match your system, they might be outdated.
Setup with Python built from source¶
When you build CPython from source, debugging information should be available,
and the build should add a python-gdb.py
file to the root directory of
your repository.
To activate support, you must add the directory containing python-gdb.py
to GDB’s “auto-load-safe-path”.
If you haven’t done this, recent versions of GDB will print out a warning
with instructions on how to do this.
Note
If you do not see instructions for your version of GDB, put this in your
configuration file (~/.gdbinit
or ~/.config/gdb/gdbinit
):
add-auto-load-safe-path /path/to/cpython
You can also add multiple paths, separated by :
.
Setup for Python from a Linux distro¶
Most Linux systems provide debug information for the system Python
in a package called python-debuginfo
, python-dbg
or similar.
For example:
Fedora:
sudo dnf install gdb sudo dnf debuginfo-install python3
Ubuntu:
sudo apt install gdb python3-dbg
On several recent Linux systems, GDB can download debugging symbols
automatically using debuginfod.
However, this will not install the python-gdb.py
extension;
you generally do need to install the debug info package separately.
Using the Debug build and Development mode¶
For easier debugging, you might want to:
Use a debug build of Python. (When building from source, use
configure --with-pydebug
. On Linux distros, install and run a package likepython-debug
orpython-dbg
, if available.)Use the runtime development mode (
-X dev
).
Both enable extra assertions and disable some optimizations. Sometimes this hides the bug you are trying to find, but in most cases they make the process easier.
Using the python-gdb
extension¶
When the extension is loaded, it provides two main features: pretty printers for Python values, and additional commands.
Pretty-printers¶
This is what a GDB backtrace looks like (truncated) when this extension is enabled:
#0 0x000000000041a6b1 in PyObject_Malloc (nbytes=Cannot access memory at address 0x7fffff7fefe8
) at Objects/obmalloc.c:748
#1 0x000000000041b7c0 in _PyObject_DebugMallocApi (id=111 'o', nbytes=24) at Objects/obmalloc.c:1445
#2 0x000000000041b717 in _PyObject_DebugMalloc (nbytes=24) at Objects/obmalloc.c:1412
#3 0x000000000044060a in _PyUnicode_New (length=11) at Objects/unicodeobject.c:346
#4 0x00000000004466aa in PyUnicodeUCS2_DecodeUTF8Stateful (s=0x5c2b8d "__lltrace__", size=11, errors=0x0, consumed=
0x0) at Objects/unicodeobject.c:2531
#5 0x0000000000446647 in PyUnicodeUCS2_DecodeUTF8 (s=0x5c2b8d "__lltrace__", size=11, errors=0x0)
at Objects/unicodeobject.c:2495
#6 0x0000000000440d1b in PyUnicodeUCS2_FromStringAndSize (u=0x5c2b8d "__lltrace__", size=11)
at Objects/unicodeobject.c:551
#7 0x0000000000440d94 in PyUnicodeUCS2_FromString (u=0x5c2b8d "__lltrace__") at Objects/unicodeobject.c:569
#8 0x0000000000584abd in PyDict_GetItemString (v=
{'Yuck': <type at remote 0xad4730>, '__builtins__': <module at remote 0x7ffff7fd5ee8>, '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', '__package__': None, 'y': <Yuck(i=0) at remote 0xaacd80>, 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__cached__': None, '__name__': '__main__', 'z': <Yuck(i=0) at remote 0xaace60>, '__doc__': None}, key=
0x5c2b8d "__lltrace__") at Objects/dictobject.c:2171
Notice how the dictionary argument to PyDict_GetItemString
is displayed
as its repr()
, rather than an opaque PyObject *
pointer.
The extension works by supplying a custom printing routine for values of type
PyObject *
. If you need to access lower-level details of an object, then
cast the value to a pointer of the appropriate type. For example:
(gdb) p globals
$1 = {'__builtins__': <module at remote 0x7ffff7fb1868>, '__name__':
'__main__', 'ctypes': <module at remote 0x7ffff7f14360>, '__doc__': None,
'__package__': None}
(gdb) p *(PyDictObject*)globals
$2 = {ob_refcnt = 3, ob_type = 0x3dbdf85820, ma_fill = 5, ma_used = 5,
ma_mask = 7, ma_table = 0x63d0f8, ma_lookup = 0x3dbdc7ea70
<lookdict_string>, ma_smalltable = {{me_hash = 7065186196740147912,
me_key = '__builtins__', me_value = <module at remote 0x7ffff7fb1868>},
{me_hash = -368181376027291943, me_key = '__name__',
me_value ='__main__'}, {me_hash = 0, me_key = 0x0, me_value = 0x0},
{me_hash = 0, me_key = 0x0, me_value = 0x0},
{me_hash = -9177857982131165996, me_key = 'ctypes',
me_value = <module at remote 0x7ffff7f14360>},
{me_hash = -8518757509529533123, me_key = '__doc__', me_value = None},
{me_hash = 0, me_key = 0x0, me_value = 0x0}, {
me_hash = 6614918939584953775, me_key = '__package__', me_value = None}}}
Note that the pretty-printers do not actually call repr()
.
For basic types, they try to match its result closely.
An area that can be confusing is that the custom printer for some types look a
lot like GDB’s built-in printer for standard types. For example, the
pretty-printer for a Python int
(PyLongObject*)
gives a representation that is not distinguishable from one of a
regular machine-level integer:
(gdb) p some_machine_integer
$3 = 42
(gdb) p some_python_integer
$4 = 42
The internal structure can be revealed with a cast to PyLongObject*:
(gdb) p *(PyLongObject*)some_python_integer
$5 = {ob_base = {ob_base = {ob_refcnt = 8, ob_type = 0x3dad39f5e0}, ob_size = 1},
ob_digit = {42}}
A similar confusion can arise with the str
type, where the output looks a
lot like gdb’s built-in printer for char *
:
(gdb) p ptr_to_python_str
$6 = '__builtins__'
The pretty-printer for str
instances defaults to using single-quotes (as
does Python’s repr
for strings) whereas the standard printer for char *
values uses double-quotes and contains a hexadecimal address:
(gdb) p ptr_to_char_star
$7 = 0x6d72c0 "hello world"
Again, the implementation details can be revealed with a cast to PyUnicodeObject*:
(gdb) p *(PyUnicodeObject*)$6
$8 = {ob_base = {ob_refcnt = 33, ob_type = 0x3dad3a95a0}, length = 12,
str = 0x7ffff2128500, hash = 7065186196740147912, state = 1, defenc = 0x0}
py-list
¶
The extension adds a
py-list
command, which lists the Python source code (if any) for the current frame in the selected thread. The current line is marked with a “>”:(gdb) py-list 901 if options.profile: 902 options.profile = False 903 profile_me() 904 return 905 >906 u = UI() 907 if not u.quit: 908 try: 909 gtk.main() 910 except KeyboardInterrupt: 911 # properly quit on a keyboard interrupt...Use
py-list START
to list at a different line number within the Python source, andpy-list START,END
to list a specific range of lines within the Python source.
py-up
and py-down
¶
The
py-up
andpy-down
commands are analogous to GDB’s regularup
anddown
commands, but try to move at the level of CPython frames, rather than C frames.GDB is not always able to read the relevant frame information, depending on the optimization level with which CPython was compiled. Internally, the commands look for C frames that are executing the default frame evaluation function (that is, the core bytecode interpreter loop within CPython) and look up the value of the related
PyFrameObject *
.They emit the frame number (at the C level) within the thread.
For example:
(gdb) py-up #37 Frame 0x9420b04, for file /usr/lib/python2.6/site-packages/ gnome_sudoku/main.py, line 906, in start_game () u = UI() (gdb) py-up #40 Frame 0x948e82c, for file /usr/lib/python2.6/site-packages/ gnome_sudoku/gnome_sudoku.py, line 22, in start_game(main=<module at remote 0xb771b7f4>) main.start_game() (gdb) py-up Unable to find an older python frameso we’re at the top of the Python stack.
The frame numbers correspond to those displayed by GDB’s standard
backtrace
command. The command skips C frames which are not executing Python code.Going back down:
(gdb) py-down #37 Frame 0x9420b04, for file /usr/lib/python2.6/site-packages/gnome_sudoku/main.py, line 906, in start_game () u = UI() (gdb) py-down #34 (unable to read python frame information) (gdb) py-down #23 (unable to read python frame information) (gdb) py-down #19 (unable to read python frame information) (gdb) py-down #14 Frame 0x99262ac, for file /usr/lib/python2.6/site-packages/gnome_sudoku/game_selector.py, line 201, in run_swallowed_dialog (self=<NewOrSavedGameSelector(new_game_model=<gtk.ListStore at remote 0x98fab44>, puzzle=None, saved_games=[{'gsd.auto_fills': 0, 'tracking': {}, 'trackers': {}, 'notes': [], 'saved_at': 1270084485, 'game': '7 8 0 0 0 0 0 5 6 0 0 9 0 8 0 1 0 0 0 4 6 0 0 0 0 7 0 6 5 0 0 0 4 7 9 2 0 0 0 9 0 1 0 0 0 3 9 7 6 0 0 0 1 8 0 6 0 0 0 0 2 8 0 0 0 5 0 4 0 6 0 0 2 1 0 0 0 0 0 4 5\n7 8 0 0 0 0 0 5 6 0 0 9 0 8 0 1 0 0 0 4 6 0 0 0 0 7 0 6 5 1 8 3 4 7 9 2 0 0 0 9 0 1 0 0 0 3 9 7 6 0 0 0 1 8 0 6 0 0 0 0 2 8 0 0 0 5 0 4 0 6 0 0 2 1 0 0 0 0 0 4 5', 'gsd.impossible_hints': 0, 'timer.__absolute_start_time__': <float at remote 0x984b474>, 'gsd.hints': 0, 'timer.active_time': <float at remote 0x984b494>, 'timer.total_time': <float at remote 0x984b464>}], dialog=<gtk.Dialog at remote 0x98faaa4>, saved_game_model=<gtk.ListStore at remote 0x98fad24>, sudoku_maker=<SudokuMaker(terminated=False, played=[], batch_siz...(truncated) swallower.run_dialog(self.dialog) (gdb) py-down #11 Frame 0x9aead74, for file /usr/lib/python2.6/site-packages/gnome_sudoku/dialog_swallower.py, line 48, in run_dialog (self=<SwappableArea(running=<gtk.Dialog at remote 0x98faaa4>, main_page=0) at remote 0x98fa6e4>, d=<gtk.Dialog at remote 0x98faaa4>) gtk.main() (gdb) py-down #8 (unable to read python frame information) (gdb) py-down Unable to find a newer python frameand we’re at the bottom of the Python stack.
Note that in Python 3.12 and newer, the same C stack frame can be used for multiple Python stack frames. This means that
py-up
andpy-down
may move multiple Python frames at once. For example:(gdb) py-up #6 Frame 0x7ffff7fb62b0, for file /tmp/rec.py, line 5, in recursive_function (n=0) time.sleep(5) #6 Frame 0x7ffff7fb6240, for file /tmp/rec.py, line 7, in recursive_function (n=1) recursive_function(n-1) #6 Frame 0x7ffff7fb61d0, for file /tmp/rec.py, line 7, in recursive_function (n=2) recursive_function(n-1) #6 Frame 0x7ffff7fb6160, for file /tmp/rec.py, line 7, in recursive_function (n=3) recursive_function(n-1) #6 Frame 0x7ffff7fb60f0, for file /tmp/rec.py, line 7, in recursive_function (n=4) recursive_function(n-1) #6 Frame 0x7ffff7fb6080, for file /tmp/rec.py, line 7, in recursive_function (n=5) recursive_function(n-1) #6 Frame 0x7ffff7fb6020, for file /tmp/rec.py, line 9, in <module> () recursive_function(5) (gdb) py-up Unable to find an older python frame
py-bt
¶
The
py-bt
command attempts to display a Python-level backtrace of the current thread.For example:
(gdb) py-bt #8 (unable to read python frame information) #11 Frame 0x9aead74, for file /usr/lib/python2.6/site-packages/gnome_sudoku/dialog_swallower.py, line 48, in run_dialog (self=<SwappableArea(running=<gtk.Dialog at remote 0x98faaa4>, main_page=0) at remote 0x98fa6e4>, d=<gtk.Dialog at remote 0x98faaa4>) gtk.main() #14 Frame 0x99262ac, for file /usr/lib/python2.6/site-packages/gnome_sudoku/game_selector.py, line 201, in run_swallowed_dialog (self=<NewOrSavedGameSelector(new_game_model=<gtk.ListStore at remote 0x98fab44>, puzzle=None, saved_games=[{'gsd.auto_fills': 0, 'tracking': {}, 'trackers': {}, 'notes': [], 'saved_at': 1270084485, 'game': '7 8 0 0 0 0 0 5 6 0 0 9 0 8 0 1 0 0 0 4 6 0 0 0 0 7 0 6 5 0 0 0 4 7 9 2 0 0 0 9 0 1 0 0 0 3 9 7 6 0 0 0 1 8 0 6 0 0 0 0 2 8 0 0 0 5 0 4 0 6 0 0 2 1 0 0 0 0 0 4 5\n7 8 0 0 0 0 0 5 6 0 0 9 0 8 0 1 0 0 0 4 6 0 0 0 0 7 0 6 5 1 8 3 4 7 9 2 0 0 0 9 0 1 0 0 0 3 9 7 6 0 0 0 1 8 0 6 0 0 0 0 2 8 0 0 0 5 0 4 0 6 0 0 2 1 0 0 0 0 0 4 5', 'gsd.impossible_hints': 0, 'timer.__absolute_start_time__': <float at remote 0x984b474>, 'gsd.hints': 0, 'timer.active_time': <float at remote 0x984b494>, 'timer.total_time': <float at remote 0x984b464>}], dialog=<gtk.Dialog at remote 0x98faaa4>, saved_game_model=<gtk.ListStore at remote 0x98fad24>, sudoku_maker=<SudokuMaker(terminated=False, played=[], batch_siz...(truncated) swallower.run_dialog(self.dialog) #19 (unable to read python frame information) #23 (unable to read python frame information) #34 (unable to read python frame information) #37 Frame 0x9420b04, for file /usr/lib/python2.6/site-packages/gnome_sudoku/main.py, line 906, in start_game () u = UI() #40 Frame 0x948e82c, for file /usr/lib/python2.6/site-packages/gnome_sudoku/gnome_sudoku.py, line 22, in start_game (main=<module at remote 0xb771b7f4>) main.start_game()The frame numbers correspond to those displayed by GDB’s standard
backtrace
command.
py-print
¶
The
py-print
command looks up a Python name and tries to print it. It looks in locals within the current thread, then globals, then finally builtins:(gdb) py-print self local 'self' = <SwappableArea(running=<gtk.Dialog at remote 0x98faaa4>, main_page=0) at remote 0x98fa6e4> (gdb) py-print __name__ global '__name__' = 'gnome_sudoku.dialog_swallower' (gdb) py-print len builtin 'len' = <built-in function len> (gdb) py-print scarlet_pimpernel 'scarlet_pimpernel' not foundIf the current C frame corresponds to multiple Python frames,
py-print
only considers the first one.
py-locals
¶
The
py-locals
command looks up all Python locals within the current Python frame in the selected thread, and prints their representations:(gdb) py-locals self = <SwappableArea(running=<gtk.Dialog at remote 0x98faaa4>, main_page=0) at remote 0x98fa6e4> d = <gtk.Dialog at remote 0x98faaa4>If the current C frame corresponds to multiple Python frames, locals from all of them will be shown:
(gdb) py-locals Locals for recursive_function n = 0 Locals for recursive_function n = 1 Locals for recursive_function n = 2 Locals for recursive_function n = 3 Locals for recursive_function n = 4 Locals for recursive_function n = 5 Locals for <module>
Use with GDB commands¶
The extension commands complement GDB’s built-in commands.
For example, you can use a frame numbers shown by py-bt
with the frame
command to go a specific frame within the selected thread, like this:
(gdb) py-bt
(output snipped)
#68 Frame 0xaa4560, for file Lib/test/regrtest.py, line 1548, in <module> ()
main()
(gdb) frame 68
#68 0x00000000004cd1e6 in PyEval_EvalFrameEx (f=Frame 0xaa4560, for file Lib/test/regrtest.py, line 1548, in <module> (), throwflag=0) at Python/ceval.c:2665
2665 x = call_function(&sp, oparg);
(gdb) py-list
1543 # Run the tests in a context manager that temporary changes the CWD to a
1544 # temporary and writable directory. If it's not possible to create or
1545 # change the CWD, the original CWD will be used. The original CWD is
1546 # available from test_support.SAVEDCWD.
1547 with test_support.temp_cwd(TESTCWD, quiet=True):
>1548 main()
The info threads
command will give you a list of the threads within the
process, and you can use the thread
command to select a different one:
(gdb) info threads
105 Thread 0x7fffefa18710 (LWP 10260) sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:86
104 Thread 0x7fffdf5fe710 (LWP 10259) sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:86
* 1 Thread 0x7ffff7fe2700 (LWP 10145) 0x00000038e46d73e3 in select () at ../sysdeps/unix/syscall-template.S:82
You can use thread apply all COMMAND
or (t a a COMMAND
for short) to run
a command on all threads. With py-bt
, this lets you see what every
thread is doing at the Python level:
(gdb) t a a py-bt
Thread 105 (Thread 0x7fffefa18710 (LWP 10260)):
#5 Frame 0x7fffd00019d0, for file /home/david/coding/python-svn/Lib/threading.py, line 155, in _acquire_restore (self=<_RLock(_Verbose__verbose=False, _RLock__owner=140737354016512, _RLock__block=<thread.lock at remote 0x858770>, _RLock__count=1) at remote 0xd7ff40>, count_owner=(1, 140737213728528), count=1, owner=140737213728528)
self.__block.acquire()
#8 Frame 0x7fffac001640, for file /home/david/coding/python-svn/Lib/threading.py, line 269, in wait (self=<_Condition(_Condition__lock=<_RLock(_Verbose__verbose=False, _RLock__owner=140737354016512, _RLock__block=<thread.lock at remote 0x858770>, _RLock__count=1) at remote 0xd7ff40>, acquire=<instancemethod at remote 0xd80260>, _is_owned=<instancemethod at remote 0xd80160>, _release_save=<instancemethod at remote 0xd803e0>, release=<instancemethod at remote 0xd802e0>, _acquire_restore=<instancemethod at remote 0xd7ee60>, _Verbose__verbose=False, _Condition__waiters=[]) at remote 0xd7fd10>, timeout=None, waiter=<thread.lock at remote 0x858a90>, saved_state=(1, 140737213728528))
self._acquire_restore(saved_state)
#12 Frame 0x7fffb8001a10, for file /home/david/coding/python-svn/Lib/test/lock_tests.py, line 348, in f ()
cond.wait()
#16 Frame 0x7fffb8001c40, for file /home/david/coding/python-svn/Lib/test/lock_tests.py, line 37, in task (tid=140737213728528)
f()
Thread 104 (Thread 0x7fffdf5fe710 (LWP 10259)):
#5 Frame 0x7fffe4001580, for file /home/david/coding/python-svn/Lib/threading.py, line 155, in _acquire_restore (self=<_RLock(_Verbose__verbose=False, _RLock__owner=140737354016512, _RLock__block=<thread.lock at remote 0x858770>, _RLock__count=1) at remote 0xd7ff40>, count_owner=(1, 140736940992272), count=1, owner=140736940992272)
self.__block.acquire()
#8 Frame 0x7fffc8002090, for file /home/david/coding/python-svn/Lib/threading.py, line 269, in wait (self=<_Condition(_Condition__lock=<_RLock(_Verbose__verbose=False, _RLock__owner=140737354016512, _RLock__block=<thread.lock at remote 0x858770>, _RLock__count=1) at remote 0xd7ff40>, acquire=<instancemethod at remote 0xd80260>, _is_owned=<instancemethod at remote 0xd80160>, _release_save=<instancemethod at remote 0xd803e0>, release=<instancemethod at remote 0xd802e0>, _acquire_restore=<instancemethod at remote 0xd7ee60>, _Verbose__verbose=False, _Condition__waiters=[]) at remote 0xd7fd10>, timeout=None, waiter=<thread.lock at remote 0x858860>, saved_state=(1, 140736940992272))
self._acquire_restore(saved_state)
#12 Frame 0x7fffac001c90, for file /home/david/coding/python-svn/Lib/test/lock_tests.py, line 348, in f ()
cond.wait()
#16 Frame 0x7fffac0011c0, for file /home/david/coding/python-svn/Lib/test/lock_tests.py, line 37, in task (tid=140736940992272)
f()
Thread 1 (Thread 0x7ffff7fe2700 (LWP 10145)):
#5 Frame 0xcb5380, for file /home/david/coding/python-svn/Lib/test/lock_tests.py, line 16, in _wait ()
time.sleep(0.01)
#8 Frame 0x7fffd00024a0, for file /home/david/coding/python-svn/Lib/test/lock_tests.py, line 378, in _check_notify (self=<ConditionTests(_testMethodName='test_notify', _resultForDoCleanups=<TestResult(_original_stdout=<cStringIO.StringO at remote 0xc191e0>, skipped=[], _mirrorOutput=False, testsRun=39, buffer=False, _original_stderr=<file at remote 0x7ffff7fc6340>, _stdout_buffer=<cStringIO.StringO at remote 0xc9c7f8>, _stderr_buffer=<cStringIO.StringO at remote 0xc9c790>, _moduleSetUpFailed=False, expectedFailures=[], errors=[], _previousTestClass=<type at remote 0x928310>, unexpectedSuccesses=[], failures=[], shouldStop=False, failfast=False) at remote 0xc185a0>, _threads=(0,), _cleanups=[], _type_equality_funcs={<type at remote 0x7eba00>: <instancemethod at remote 0xd750e0>, <type at remote 0x7e7820>: <instancemethod at remote 0xd75160>, <type at remote 0x7e30e0>: <instancemethod at remote 0xd75060>, <type at remote 0x7e7d20>: <instancemethod at remote 0xd751e0>, <type at remote 0x7f19e0...(truncated)
_wait()


— The group database

grp
— The group database¶
This module provides access to the Unix group database. It is available on all Unix versions.
Availability: Unix, not WASI, not Android, not iOS.
Group database entries are reported as a tuple-like object, whose attributes
correspond to the members of the group
structure (Attribute field below, see
<grp.h>
):
Index |
Attribute |
Meaning |
|---|---|---|
0 |
gr_name |
the name of the group |
1 |
gr_passwd |
the (encrypted) group password; often empty |
2 |
gr_gid |
the numerical group ID |
3 |
gr_mem |
all the group member’s user names |
The gid is an integer, name and password are strings, and the member list is a
list of strings. (Note that most users are not explicitly listed as members of
the group they are in according to the password database. Check both databases
to get complete membership information. Also note that a gr_name
that
starts with a +
or -
is likely to be a YP/NIS reference and may not be
accessible via getgrnam()
or getgrgid()
.)
It defines the following items:
- grp.getgrgid(id)¶
Return the group database entry for the given numeric group ID.
KeyError
is raised if the entry asked for cannot be found.Changed in version 3.10:
TypeError
is raised for non-integer arguments like floats or strings.
- grp.getgrnam(name)¶
Return the group database entry for the given group name.
KeyError
is raised if the entry asked for cannot be found.
- grp.getgrall()¶
Return a list of all available group entries, in arbitrary order.
See also
- Module
pwd
An interface to the user database, similar to this.


Defining Extension Types: Tutorial

2. Defining Extension Types: Tutorial¶
Python allows the writer of a C extension module to define new types that
can be manipulated from Python code, much like the built-in str
and list
types. The code for all extension types follows a
pattern, but there are some details that you need to understand before you
can get started. This document is a gentle introduction to the topic.
2.1. The Basics¶
The CPython runtime sees all Python objects as variables of type
PyObject*, which serves as a “base type” for all Python objects.
The PyObject
structure itself only contains the object’s
reference count and a pointer to the object’s “type object”.
This is where the action is; the type object determines which (C) functions
get called by the interpreter when, for instance, an attribute gets looked up
on an object, a method called, or it is multiplied by another object. These
C functions are called “type methods”.
So, if you want to define a new extension type, you need to create a new type object.
This sort of thing can only be explained by example, so here’s a minimal, but
complete, module that defines a new type named Custom
inside a C
extension module custom
:
Note
What we’re showing here is the traditional way of defining static
extension types. It should be adequate for most uses. The C API also
allows defining heap-allocated extension types using the
PyType_FromSpec()
function, which isn’t covered in this tutorial.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
} CustomObject;
static PyTypeObject CustomType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom.Custom",
.tp_doc = PyDoc_STR("Custom objects"),
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_new = PyType_GenericNew,
};
static int
custom_module_exec(PyObject *m)
{
if (PyType_Ready(&CustomType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot custom_module_slots[] = {
{Py_mod_exec, custom_module_exec},
// Just use this while using static types
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
{0, NULL}
};
static PyModuleDef custom_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "custom",
.m_doc = "Example module that creates an extension type.",
.m_size = 0,
.m_slots = custom_module_slots,
};
PyMODINIT_FUNC
PyInit_custom(void)
{
return PyModuleDef_Init(&custom_module);
}
Now that’s quite a bit to take in at once, but hopefully bits will seem familiar from the previous chapter. This file defines three things:
What a
Custom
object contains: this is theCustomObject
struct, which is allocated once for eachCustom
instance.How the
Custom
type behaves: this is theCustomType
struct, which defines a set of flags and function pointers that the interpreter inspects when specific operations are requested.How to define and execute the
custom
module: this is thePyInit_custom
function and the associatedcustom_module
struct for defining the module, and thecustom_module_exec
function to set up a fresh module object.
The first bit is:
typedef struct {
PyObject_HEAD
} CustomObject;
This is what a Custom object will contain. PyObject_HEAD
is mandatory
at the start of each object struct and defines a field called ob_base
of type PyObject
, containing a pointer to a type object and a
reference count (these can be accessed using the macros Py_TYPE
and Py_REFCNT
respectively). The reason for the macro is to
abstract away the layout and to enable additional fields in debug builds.
Note
There is no semicolon above after the PyObject_HEAD
macro.
Be wary of adding one by accident: some compilers will complain.
Of course, objects generally store additional data besides the standard
PyObject_HEAD
boilerplate; for example, here is the definition for
standard Python floats:
typedef struct {
PyObject_HEAD
double ob_fval;
} PyFloatObject;
The second bit is the definition of the type object.
static PyTypeObject CustomType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom.Custom",
.tp_doc = PyDoc_STR("Custom objects"),
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_new = PyType_GenericNew,
};
Note
We recommend using C99-style designated initializers as above, to
avoid listing all the PyTypeObject
fields that you don’t care
about and also to avoid caring about the fields’ declaration order.
The actual definition of PyTypeObject
in object.h
has
many more fields than the definition above. The
remaining fields will be filled with zeros by the C compiler, and it’s
common practice to not specify them explicitly unless you need them.
We’re going to pick it apart, one field at a time:
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
This line is mandatory boilerplate to initialize the ob_base
field mentioned above.
.tp_name = "custom.Custom",
The name of our type. This will appear in the default textual representation of our objects and in some error messages, for example:
>>> "" + custom.Custom()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "custom.Custom") to str
Note that the name is a dotted name that includes both the module name and the
name of the type within the module. The module in this case is custom
and
the type is Custom
, so we set the type name to custom.Custom
.
Using the real dotted import path is important to make your type compatible
with the pydoc
and pickle
modules.
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
This is so that Python knows how much memory to allocate when creating
new Custom
instances. tp_itemsize
is
only used for variable-sized objects and should otherwise be zero.
Note
If you want your type to be subclassable from Python, and your type has the same
tp_basicsize
as its base type, you may have problems with multiple
inheritance. A Python subclass of your type will have to list your type first
in its __bases__
, or else it will not be able to call your type’s
__new__()
method without getting an error. You can avoid this problem by
ensuring that your type has a larger value for tp_basicsize
than its
base type does. Most of the time, this will be true anyway, because either your
base type will be object
, or else you will be adding data members to
your base type, and therefore increasing its size.
We set the class flags to Py_TPFLAGS_DEFAULT
.
.tp_flags = Py_TPFLAGS_DEFAULT,
All types should include this constant in their flags. It enables all of the members defined until at least Python 3.3. If you need further members, you will need to OR the corresponding flags.
We provide a doc string for the type in tp_doc
.
.tp_doc = PyDoc_STR("Custom objects"),
To enable object creation, we have to provide a tp_new
handler. This is the equivalent of the Python method __new__()
, but
has to be specified explicitly. In this case, we can just use the default
implementation provided by the API function PyType_GenericNew()
.
.tp_new = PyType_GenericNew,
Everything else in the file should be familiar, except for some code in
custom_module_exec()
:
if (PyType_Ready(&CustomType) < 0) {
return -1;
}
This initializes the Custom
type, filling in a number of members
to the appropriate default values, including ob_type
that we initially
set to NULL
.
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
return -1;
}
This adds the type to the module dictionary. This allows us to create
Custom
instances by calling the Custom
class:
>>> import custom
>>> mycustom = custom.Custom()
That’s it! All that remains is to build it; put the above code in a file called
custom.c
,
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "custom"
version = "1"
in a file called pyproject.toml
, and
from setuptools import Extension, setup
setup(ext_modules=[Extension("custom", ["custom.c"])])
in a file called setup.py
; then typing
$ python -m pip install .
in a shell should produce a file custom.so
in a subdirectory
and install it; now fire up Python — you should be able to import custom
and play around with Custom
objects.
That wasn’t so hard, was it?
Of course, the current Custom type is pretty uninteresting. It has no data and doesn’t do anything. It can’t even be subclassed.
2.2. Adding data and methods to the Basic example¶
Let’s extend the basic example to add some data and methods. Let’s also make
the type usable as a base class. We’ll create a new module, custom2
that
adds these capabilities:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stddef.h> /* for offsetof() */
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
static void
Custom_dealloc(PyObject *op)
{
CustomObject *self = (CustomObject *) op;
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free(self);
}
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
self->number = 0;
}
return (PyObject *) self;
}
static int
Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
Py_XSETREF(self->first, Py_NewRef(first));
}
if (last) {
Py_XSETREF(self->last, Py_NewRef(last));
}
return 0;
}
static PyMemberDef Custom_members[] = {
{"first", Py_T_OBJECT_EX, offsetof(CustomObject, first), 0,
"first name"},
{"last", Py_T_OBJECT_EX, offsetof(CustomObject, last), 0,
"last name"},
{"number", Py_T_INT, offsetof(CustomObject, number), 0,
"custom number"},
{NULL} /* Sentinel */
};
static PyObject *
Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
{
CustomObject *self = (CustomObject *) op;
if (self->first == NULL) {
PyErr_SetString(PyExc_AttributeError, "first");
return NULL;
}
if (self->last == NULL) {
PyErr_SetString(PyExc_AttributeError, "last");
return NULL;
}
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
static PyMethodDef Custom_methods[] = {
{"name", Custom_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
};
static PyTypeObject CustomType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom2.Custom",
.tp_doc = PyDoc_STR("Custom objects"),
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_new = Custom_new,
.tp_init = Custom_init,
.tp_dealloc = Custom_dealloc,
.tp_members = Custom_members,
.tp_methods = Custom_methods,
};
static int
custom_module_exec(PyObject *m)
{
if (PyType_Ready(&CustomType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot custom_module_slots[] = {
{Py_mod_exec, custom_module_exec},
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
{0, NULL}
};
static PyModuleDef custom_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "custom2",
.m_doc = "Example module that creates an extension type.",
.m_size = 0,
.m_slots = custom_module_slots,
};
PyMODINIT_FUNC
PyInit_custom2(void)
{
return PyModuleDef_Init(&custom_module);
}
This version of the module has a number of changes.
The Custom
type now has three data attributes in its C struct,
first, last, and number. The first and last variables are Python
strings containing first and last names. The number attribute is a C integer.
The object structure is updated accordingly:
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
Because we now have data to manage, we have to be more careful about object allocation and deallocation. At a minimum, we need a deallocation method:
static void
Custom_dealloc(PyObject *op)
{
CustomObject *self = (CustomObject *) op;
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free(self);
}
which is assigned to the tp_dealloc
member:
.tp_dealloc = Custom_dealloc,
This method first clears the reference counts of the two Python attributes.
Py_XDECREF()
correctly handles the case where its argument is
NULL
(which might happen here if tp_new
failed midway). It then
calls the tp_free
member of the object’s type
(computed by Py_TYPE(self)
) to free the object’s memory. Note that
the object’s type might not be CustomType
, because the object may
be an instance of a subclass.
Note
The explicit cast to CustomObject *
above is needed because we defined
Custom_dealloc
to take a PyObject *
argument, as the tp_dealloc
function pointer expects to receive a PyObject *
argument.
By assigning to the tp_dealloc
slot of a type, we declare
that it can only be called with instances of our CustomObject
class, so the cast to (CustomObject *)
is safe.
This is object-oriented polymorphism, in C!
In existing code, or in previous versions of this tutorial,
you might see similar functions take a pointer to the subtype
object structure (CustomObject*
) directly, like this:
Custom_dealloc(CustomObject *self)
{
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free((PyObject *) self);
}
...
.tp_dealloc = (destructor) Custom_dealloc,
This does the same thing on all architectures that CPython supports, but according to the C standard, it invokes undefined behavior.
We want to make sure that the first and last names are initialized to empty
strings, so we provide a tp_new
implementation:
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = PyUnicode_FromString("");
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = PyUnicode_FromString("");
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
self->number = 0;
}
return (PyObject *) self;
}
and install it in the tp_new
member:
.tp_new = Custom_new,
The tp_new
handler is responsible for creating (as opposed to initializing)
objects of the type. It is exposed in Python as the __new__()
method.
It is not required to define a tp_new
member, and indeed many extension
types will simply reuse PyType_GenericNew()
as done in the first
version of the Custom
type above. In this case, we use the tp_new
handler to initialize the first
and last
attributes to non-NULL
default values.
tp_new
is passed the type being instantiated (not necessarily CustomType
,
if a subclass is instantiated) and any arguments passed when the type was
called, and is expected to return the instance created. tp_new
handlers
always accept positional and keyword arguments, but they often ignore the
arguments, leaving the argument handling to initializer (a.k.a. tp_init
in C or __init__
in Python) methods.
Note
tp_new
shouldn’t call tp_init
explicitly, as the interpreter
will do it itself.
The tp_new
implementation calls the tp_alloc
slot to allocate memory:
self = (CustomObject *) type->tp_alloc(type, 0);
Since memory allocation may fail, we must check the tp_alloc
result against NULL
before proceeding.
Note
We didn’t fill the tp_alloc
slot ourselves. Rather
PyType_Ready()
fills it for us by inheriting it from our base class,
which is object
by default. Most types use the default allocation
strategy.
Note
If you are creating a co-operative tp_new
(one
that calls a base type’s tp_new
or __new__()
),
you must not try to determine what method to call using method resolution
order at runtime. Always statically determine what type you are going to
call, and call its tp_new
directly, or via
type->tp_base->tp_new
. If you do not do this, Python subclasses of your
type that also inherit from other Python-defined classes may not work correctly.
(Specifically, you may not be able to create instances of such subclasses
without getting a TypeError
.)
We also define an initialization function which accepts arguments to provide initial values for our instance:
static int
Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_XDECREF(tmp);
}
if (last) {
tmp = self->last;
Py_INCREF(last);
self->last = last;
Py_XDECREF(tmp);
}
return 0;
}
by filling the tp_init
slot.
.tp_init = Custom_init,
The tp_init
slot is exposed in Python as the
__init__()
method. It is used to initialize an object after it’s
created. Initializers always accept positional and keyword arguments,
and they should return either 0
on success or -1
on error.
Unlike the tp_new
handler, there is no guarantee that tp_init
is called at all (for example, the pickle
module by default
doesn’t call __init__()
on unpickled instances). It can also be
called multiple times. Anyone can call the __init__()
method on
our objects. For this reason, we have to be extra careful when assigning
the new attribute values. We might be tempted, for example to assign the
first
member like this:
if (first) {
Py_XDECREF(self->first);
Py_INCREF(first);
self->first = first;
}
But this would be risky. Our type doesn’t restrict the type of the
first
member, so it could be any kind of object. It could have a
destructor that causes code to be executed that tries to access the
first
member; or that destructor could detach the
thread state and let arbitrary code run in other
threads that accesses and modifies our object.
To be paranoid and protect ourselves against this possibility, we almost always reassign members before decrementing their reference counts. When don’t we have to do this?
when we absolutely know that the reference count is greater than 1;
when we know that deallocation of the object [1] will neither detach the thread state nor cause any calls back into our type’s code;
when decrementing a reference count in a
tp_dealloc
handler on a type which doesn’t support cyclic garbage collection [2].
We want to expose our instance variables as attributes. There are a number of ways to do that. The simplest way is to define member definitions:
static PyMemberDef Custom_members[] = {
{"first", Py_T_OBJECT_EX, offsetof(CustomObject, first), 0,
"first name"},
{"last", Py_T_OBJECT_EX, offsetof(CustomObject, last), 0,
"last name"},
{"number", Py_T_INT, offsetof(CustomObject, number), 0,
"custom number"},
{NULL} /* Sentinel */
};
and put the definitions in the tp_members
slot:
.tp_members = Custom_members,
Each member definition has a member name, type, offset, access flags and documentation string. See the Generic Attribute Management section below for details.
A disadvantage of this approach is that it doesn’t provide a way to restrict the
types of objects that can be assigned to the Python attributes. We expect the
first and last names to be strings, but any Python objects can be assigned.
Further, the attributes can be deleted, setting the C pointers to NULL
. Even
though we can make sure the members are initialized to non-NULL
values, the
members can be set to NULL
if the attributes are deleted.
We define a single method, Custom.name()
, that outputs the objects name as the
concatenation of the first and last names.
static PyObject *
Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
{
CustomObject *self = (CustomObject *) op;
if (self->first == NULL) {
PyErr_SetString(PyExc_AttributeError, "first");
return NULL;
}
if (self->last == NULL) {
PyErr_SetString(PyExc_AttributeError, "last");
return NULL;
}
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
The method is implemented as a C function that takes a Custom
(or
Custom
subclass) instance as the first argument. Methods always take an
instance as the first argument. Methods often take positional and keyword
arguments as well, but in this case we don’t take any and don’t need to accept
a positional argument tuple or keyword argument dictionary. This method is
equivalent to the Python method:
def name(self):
return "%s %s" % (self.first, self.last)
Note that we have to check for the possibility that our first
and
last
members are NULL
. This is because they can be deleted, in which
case they are set to NULL
. It would be better to prevent deletion of these
attributes and to restrict the attribute values to be strings. We’ll see how to
do that in the next section.
Now that we’ve defined the method, we need to create an array of method definitions:
static PyMethodDef Custom_methods[] = {
{"name", Custom_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
};
(note that we used the METH_NOARGS
flag to indicate that the method
is expecting no arguments other than self)
and assign it to the tp_methods
slot:
.tp_methods = Custom_methods,
Finally, we’ll make our type usable as a base class for subclassing. We’ve
written our methods carefully so far so that they don’t make any assumptions
about the type of the object being created or used, so all we need to do is
to add the Py_TPFLAGS_BASETYPE
to our class flag definition:
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
We rename PyInit_custom()
to PyInit_custom2()
, update the
module name in the PyModuleDef
struct, and update the full class
name in the PyTypeObject
struct.
Finally, we update our setup.py
file to include the new module,
from setuptools import Extension, setup
setup(ext_modules=[
Extension("custom", ["custom.c"]),
Extension("custom2", ["custom2.c"]),
])
and then we re-install so that we can import custom2
:
$ python -m pip install .
2.3. Providing finer control over data attributes¶
In this section, we’ll provide finer control over how the first
and
last
attributes are set in the Custom
example. In the previous
version of our module, the instance variables first
and last
could be set to non-string values or even deleted. We want to make sure that
these attributes always contain strings.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stddef.h> /* for offsetof() */
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
static void
Custom_dealloc(PyObject *op)
{
CustomObject *self = (CustomObject *) op;
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free(self);
}
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
self->number = 0;
}
return (PyObject *) self;
}
static int
Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
Py_SETREF(self->first, Py_NewRef(first));
}
if (last) {
Py_SETREF(self->last, Py_NewRef(last));
}
return 0;
}
static PyMemberDef Custom_members[] = {
{"number", Py_T_INT, offsetof(CustomObject, number), 0,
"custom number"},
{NULL} /* Sentinel */
};
static PyObject *
Custom_getfirst(PyObject *op, void *closure)
{
CustomObject *self = (CustomObject *) op;
return Py_NewRef(self->first);
}
static int
Custom_setfirst(PyObject *op, PyObject *value, void *closure)
{
CustomObject *self = (CustomObject *) op;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string");
return -1;
}
Py_SETREF(self->first, Py_NewRef(value));
return 0;
}
static PyObject *
Custom_getlast(PyObject *op, void *closure)
{
CustomObject *self = (CustomObject *) op;
return Py_NewRef(self->last);
}
static int
Custom_setlast(PyObject *op, PyObject *value, void *closure)
{
CustomObject *self = (CustomObject *) op;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The last attribute value must be a string");
return -1;
}
Py_SETREF(self->last, Py_NewRef(value));
return 0;
}
static PyGetSetDef Custom_getsetters[] = {
{"first", Custom_getfirst, Custom_setfirst,
"first name", NULL},
{"last", Custom_getlast, Custom_setlast,
"last name", NULL},
{NULL} /* Sentinel */
};
static PyObject *
Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
{
CustomObject *self = (CustomObject *) op;
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
static PyMethodDef Custom_methods[] = {
{"name", Custom_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
};
static PyTypeObject CustomType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom3.Custom",
.tp_doc = PyDoc_STR("Custom objects"),
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_new = Custom_new,
.tp_init = Custom_init,
.tp_dealloc = Custom_dealloc,
.tp_members = Custom_members,
.tp_methods = Custom_methods,
.tp_getset = Custom_getsetters,
};
static int
custom_module_exec(PyObject *m)
{
if (PyType_Ready(&CustomType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot custom_module_slots[] = {
{Py_mod_exec, custom_module_exec},
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
{0, NULL}
};
static PyModuleDef custom_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "custom3",
.m_doc = "Example module that creates an extension type.",
.m_size = 0,
.m_slots = custom_module_slots,
};
PyMODINIT_FUNC
PyInit_custom3(void)
{
return PyModuleDef_Init(&custom_module);
}
To provide greater control, over the first
and last
attributes,
we’ll use custom getter and setter functions. Here are the functions for
getting and setting the first
attribute:
static PyObject *
Custom_getfirst(PyObject *op, void *closure)
{
CustomObject *self = (CustomObject *) op;
Py_INCREF(self->first);
return self->first;
}
static int
Custom_setfirst(PyObject *op, PyObject *value, void *closure)
{
CustomObject *self = (CustomObject *) op;
PyObject *tmp;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string");
return -1;
}
tmp = self->first;
Py_INCREF(value);
self->first = value;
Py_DECREF(tmp);
return 0;
}
The getter function is passed a Custom
object and a “closure”, which is
a void pointer. In this case, the closure is ignored. (The closure supports an
advanced usage in which definition data is passed to the getter and setter. This
could, for example, be used to allow a single set of getter and setter functions
that decide the attribute to get or set based on data in the closure.)
The setter function is passed the Custom
object, the new value, and the
closure. The new value may be NULL
, in which case the attribute is being
deleted. In our setter, we raise an error if the attribute is deleted or if its
new value is not a string.
We create an array of PyGetSetDef
structures:
static PyGetSetDef Custom_getsetters[] = {
{"first", Custom_getfirst, Custom_setfirst,
"first name", NULL},
{"last", Custom_getlast, Custom_setlast,
"last name", NULL},
{NULL} /* Sentinel */
};
and register it in the tp_getset
slot:
.tp_getset = Custom_getsetters,
The last item in a PyGetSetDef
structure is the “closure” mentioned
above. In this case, we aren’t using a closure, so we just pass NULL
.
We also remove the member definitions for these attributes:
static PyMemberDef Custom_members[] = {
{"number", Py_T_INT, offsetof(CustomObject, number), 0,
"custom number"},
{NULL} /* Sentinel */
};
We also need to update the tp_init
handler to only
allow strings [3] to be passed:
static int
Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_DECREF(tmp);
}
if (last) {
tmp = self->last;
Py_INCREF(last);
self->last = last;
Py_DECREF(tmp);
}
return 0;
}
With these changes, we can assure that the first
and last
members are
never NULL
so we can remove checks for NULL
values in almost all cases.
This means that most of the Py_XDECREF()
calls can be converted to
Py_DECREF()
calls. The only place we can’t change these calls is in
the tp_dealloc
implementation, where there is the possibility that the
initialization of these members failed in tp_new
.
We also rename the module initialization function and module name in the
initialization function, as we did before, and we add an extra definition to the
setup.py
file.
2.4. Supporting cyclic garbage collection¶
Python has a cyclic garbage collector (GC) that can identify unneeded objects even when their reference counts are not zero. This can happen when objects are involved in cycles. For example, consider:
>>> l = []
>>> l.append(l)
>>> del l
In this example, we create a list that contains itself. When we delete it, it still has a reference from itself. Its reference count doesn’t drop to zero. Fortunately, Python’s cyclic garbage collector will eventually figure out that the list is garbage and free it.
In the second version of the Custom
example, we allowed any kind of
object to be stored in the first
or last
attributes [4].
Besides, in the second and third versions, we allowed subclassing
Custom
, and subclasses may add arbitrary attributes. For any of
those two reasons, Custom
objects can participate in cycles:
>>> import custom3
>>> class Derived(custom3.Custom): pass
...
>>> n = Derived()
>>> n.some_attribute = n
To allow a Custom
instance participating in a reference cycle to
be properly detected and collected by the cyclic GC, our Custom
type
needs to fill two additional slots and to enable a flag that enables these slots:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stddef.h> /* for offsetof() */
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
static int
Custom_traverse(PyObject *op, visitproc visit, void *arg)
{
CustomObject *self = (CustomObject *) op;
Py_VISIT(self->first);
Py_VISIT(self->last);
return 0;
}
static int
Custom_clear(PyObject *op)
{
CustomObject *self = (CustomObject *) op;
Py_CLEAR(self->first);
Py_CLEAR(self->last);
return 0;
}
static void
Custom_dealloc(PyObject *op)
{
PyObject_GC_UnTrack(op);
(void)Custom_clear(op);
Py_TYPE(op)->tp_free(op);
}
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
self->number = 0;
}
return (PyObject *) self;
}
static int
Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
Py_SETREF(self->first, Py_NewRef(first));
}
if (last) {
Py_SETREF(self->last, Py_NewRef(last));
}
return 0;
}
static PyMemberDef Custom_members[] = {
{"number", Py_T_INT, offsetof(CustomObject, number), 0,
"custom number"},
{NULL} /* Sentinel */
};
static PyObject *
Custom_getfirst(PyObject *op, void *closure)
{
CustomObject *self = (CustomObject *) op;
return Py_NewRef(self->first);
}
static int
Custom_setfirst(PyObject *op, PyObject *value, void *closure)
{
CustomObject *self = (CustomObject *) op;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string");
return -1;
}
Py_XSETREF(self->first, Py_NewRef(value));
return 0;
}
static PyObject *
Custom_getlast(PyObject *op, void *closure)
{
CustomObject *self = (CustomObject *) op;
return Py_NewRef(self->last);
}
static int
Custom_setlast(PyObject *op, PyObject *value, void *closure)
{
CustomObject *self = (CustomObject *) op;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The last attribute value must be a string");
return -1;
}
Py_XSETREF(self->last, Py_NewRef(value));
return 0;
}
static PyGetSetDef Custom_getsetters[] = {
{"first", Custom_getfirst, Custom_setfirst,
"first name", NULL},
{"last", Custom_getlast, Custom_setlast,
"last name", NULL},
{NULL} /* Sentinel */
};
static PyObject *
Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
{
CustomObject *self = (CustomObject *) op;
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
static PyMethodDef Custom_methods[] = {
{"name", Custom_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
};
static PyTypeObject CustomType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom4.Custom",
.tp_doc = PyDoc_STR("Custom objects"),
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.tp_new = Custom_new,
.tp_init = Custom_init,
.tp_dealloc = Custom_dealloc,
.tp_traverse = Custom_traverse,
.tp_clear = Custom_clear,
.tp_members = Custom_members,
.tp_methods = Custom_methods,
.tp_getset = Custom_getsetters,
};
static int
custom_module_exec(PyObject *m)
{
if (PyType_Ready(&CustomType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot custom_module_slots[] = {
{Py_mod_exec, custom_module_exec},
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
{0, NULL}
};
static PyModuleDef custom_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "custom4",
.m_doc = "Example module that creates an extension type.",
.m_size = 0,
.m_slots = custom_module_slots,
};
PyMODINIT_FUNC
PyInit_custom4(void)
{
return PyModuleDef_Init(&custom_module);
}
First, the traversal method lets the cyclic GC know about subobjects that could participate in cycles:
static int
Custom_traverse(PyObject *op, visitproc visit, void *arg)
{
CustomObject *self = (CustomObject *) op;
int vret;
if (self->first) {
vret = visit(self->first, arg);
if (vret != 0)
return vret;
}
if (self->last) {
vret = visit(self->last, arg);
if (vret != 0)
return vret;
}
return 0;
}
For each subobject that can participate in cycles, we need to call the
visit()
function, which is passed to the traversal method. The
visit()
function takes as arguments the subobject and the extra argument
arg passed to the traversal method. It returns an integer value that must be
returned if it is non-zero.
Python provides a Py_VISIT()
macro that automates calling visit
functions. With Py_VISIT()
, we can minimize the amount of boilerplate
in Custom_traverse
:
static int
Custom_traverse(PyObject *op, visitproc visit, void *arg)
{
CustomObject *self = (CustomObject *) op;
Py_VISIT(self->first);
Py_VISIT(self->last);
return 0;
}
Note
The tp_traverse
implementation must name its
arguments exactly visit and arg in order to use Py_VISIT()
.
Second, we need to provide a method for clearing any subobjects that can participate in cycles:
static int
Custom_clear(PyObject *op)
{
CustomObject *self = (CustomObject *) op;
Py_CLEAR(self->first);
Py_CLEAR(self->last);
return 0;
}
Notice the use of the Py_CLEAR()
macro. It is the recommended and safe
way to clear data attributes of arbitrary types while decrementing
their reference counts. If you were to call Py_XDECREF()
instead
on the attribute before setting it to NULL
, there is a possibility
that the attribute’s destructor would call back into code that reads the
attribute again (especially if there is a reference cycle).
Note
You could emulate Py_CLEAR()
by writing:
PyObject *tmp;
tmp = self->first;
self->first = NULL;
Py_XDECREF(tmp);
Nevertheless, it is much easier and less error-prone to always
use Py_CLEAR()
when deleting an attribute. Don’t
try to micro-optimize at the expense of robustness!
The deallocator Custom_dealloc
may call arbitrary code when clearing
attributes. It means the circular GC can be triggered inside the function.
Since the GC assumes reference count is not zero, we need to untrack the object
from the GC by calling PyObject_GC_UnTrack()
before clearing members.
Here is our reimplemented deallocator using PyObject_GC_UnTrack()
and Custom_clear
:
static void
Custom_dealloc(PyObject *op)
{
PyObject_GC_UnTrack(op);
(void)Custom_clear(op);
Py_TYPE(op)->tp_free(op);
}
Finally, we add the Py_TPFLAGS_HAVE_GC
flag to the class flags:
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
That’s pretty much it. If we had written custom tp_alloc
or
tp_free
handlers, we’d need to modify them for cyclic
garbage collection. Most extensions will use the versions automatically provided.
2.5. Subclassing other types¶
It is possible to create new extension types that are derived from existing
types. It is easiest to inherit from the built in types, since an extension can
easily use the PyTypeObject
it needs. It can be difficult to share
these PyTypeObject
structures between extension modules.
In this example we will create a SubList
type that inherits from the
built-in list
type. The new type will be completely compatible with
regular lists, but will have an additional increment()
method that
increases an internal counter:
>>> import sublist
>>> s = sublist.SubList(range(3))
>>> s.extend(s)
>>> print(len(s))
6
>>> print(s.increment())
1
>>> print(s.increment())
2
#define PY_SSIZE_T_CLEAN
#include <Python.h>
typedef struct {
PyListObject list;
int state;
} SubListObject;
static PyObject *
SubList_increment(PyObject *op, PyObject *Py_UNUSED(dummy))
{
SubListObject *self = (SubListObject *) op;
self->state++;
return PyLong_FromLong(self->state);
}
static PyMethodDef SubList_methods[] = {
{"increment", SubList_increment, METH_NOARGS,
PyDoc_STR("increment state counter")},
{NULL},
};
static int
SubList_init(PyObject *op, PyObject *args, PyObject *kwds)
{
SubListObject *self = (SubListObject *) op;
if (PyList_Type.tp_init(op, args, kwds) < 0)
return -1;
self->state = 0;
return 0;
}
static PyTypeObject SubListType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "sublist.SubList",
.tp_doc = PyDoc_STR("SubList objects"),
.tp_basicsize = sizeof(SubListObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_init = SubList_init,
.tp_methods = SubList_methods,
};
static int
sublist_module_exec(PyObject *m)
{
SubListType.tp_base = &PyList_Type;
if (PyType_Ready(&SubListType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "SubList", (PyObject *) &SubListType) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot sublist_module_slots[] = {
{Py_mod_exec, sublist_module_exec},
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
{0, NULL}
};
static PyModuleDef sublist_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "sublist",
.m_doc = "Example module that creates an extension type.",
.m_size = 0,
.m_slots = sublist_module_slots,
};
PyMODINIT_FUNC
PyInit_sublist(void)
{
return PyModuleDef_Init(&sublist_module);
}
As you can see, the source code closely resembles the Custom
examples in
previous sections. We will break down the main differences between them.
typedef struct {
PyListObject list;
int state;
} SubListObject;
The primary difference for derived type objects is that the base type’s
object structure must be the first value. The base type will already include
the PyObject_HEAD()
at the beginning of its structure.
When a Python object is a SubList
instance, its PyObject *
pointer
can be safely cast to both PyListObject *
and SubListObject *
:
static int
SubList_init(PyObject *op, PyObject *args, PyObject *kwds)
{
SubListObject *self = (SubListObject *) op;
if (PyList_Type.tp_init(op, args, kwds) < 0)
return -1;
self->state = 0;
return 0;
}
We see above how to call through to the __init__()
method of the base
type.
This pattern is important when writing a type with custom
tp_new
and tp_dealloc
members. The tp_new
handler should not actually
create the memory for the object with its tp_alloc
,
but let the base class handle it by calling its own tp_new
.
The PyTypeObject
struct supports a tp_base
specifying the type’s concrete base class. Due to cross-platform compiler
issues, you can’t fill that field directly with a reference to
PyList_Type
; it should be done in the Py_mod_exec
function:
static int
sublist_module_exec(PyObject *m)
{
SubListType.tp_base = &PyList_Type;
if (PyType_Ready(&SubListType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "SubList", (PyObject *) &SubListType) < 0) {
return -1;
}
return 0;
}
Before calling PyType_Ready()
, the type structure must have the
tp_base
slot filled in. When we are deriving an
existing type, it is not necessary to fill out the tp_alloc
slot with PyType_GenericNew()
– the allocation function from the base
type will be inherited.
After that, calling PyType_Ready()
and adding the type object to the
module is the same as with the basic Custom
examples.
Footnotes


: Iterators

email.iterators
: Iterators¶
Source code: Lib/email/iterators.py
Iterating over a message object tree is fairly easy with the
Message.walk
method. The
email.iterators
module provides some useful higher level iterations over
message object trees.
- email.iterators.body_line_iterator(msg, decode=False)¶
This iterates over all the payloads in all the subparts of msg, returning the string payloads line-by-line. It skips over all the subpart headers, and it skips over any subpart with a payload that isn’t a Python string. This is somewhat equivalent to reading the flat text representation of the message from a file using
readline()
, skipping over all the intervening headers.Optional decode is passed through to
Message.get_payload
.
- email.iterators.typed_subpart_iterator(msg, maintype='text', subtype=None)¶
This iterates over all the subparts of msg, returning only those subparts that match the MIME type specified by maintype and subtype.
Note that subtype is optional; if omitted, then subpart MIME type matching is done only with the main type. maintype is optional too; it defaults to text.
Thus, by default
typed_subpart_iterator()
returns each subpart that has a MIME type of text/*.
The following function has been added as a useful debugging tool. It should not be considered part of the supported public interface for the package.
- email.iterators._structure(msg, fp=None, level=0, include_default=False)¶
Prints an indented representation of the content types of the message object structure. For example:
>>> msg = email.message_from_file(somefile) >>> _structure(msg) multipart/mixed text/plain text/plain multipart/digest message/rfc822 text/plain message/rfc822 text/plain message/rfc822 text/plain message/rfc822 text/plain message/rfc822 text/plain text/plain
Optional fp is a file-like object to print the output to. It must be suitable for Python’s
print()
function. level is used internally. include_default, if true, prints the default type as well.


Codec registry and support functions

Codec registry and support functions¶
-
int PyCodec_Register(PyObject *search_function)¶
- Part of the Stable ABI.
Register a new codec search function.
As a side effect, this tries to load the
encodings
package, if not yet done, to make sure that it is always first in the list of search functions.
-
int PyCodec_Unregister(PyObject *search_function)¶
- Part of the Stable ABI since version 3.10.
Unregister a codec search function and clear the registry’s cache. If the search function is not registered, do nothing. Return 0 on success. Raise an exception and return -1 on error.
Added in version 3.10.
-
int PyCodec_KnownEncoding(const char *encoding)¶
- Part of the Stable ABI.
Return
1
or0
depending on whether there is a registered codec for the given encoding. This function always succeeds.
-
PyObject *PyCodec_Encode(PyObject *object, const char *encoding, const char *errors)¶
- Return value: New reference. Part of the Stable ABI.
Generic codec based encoding API.
object is passed through the encoder function found for the given encoding using the error handling method defined by errors. errors may be
NULL
to use the default method defined for the codec. Raises aLookupError
if no encoder can be found.
-
PyObject *PyCodec_Decode(PyObject *object, const char *encoding, const char *errors)¶
- Return value: New reference. Part of the Stable ABI.
Generic codec based decoding API.
object is passed through the decoder function found for the given encoding using the error handling method defined by errors. errors may be
NULL
to use the default method defined for the codec. Raises aLookupError
if no decoder can be found.
Codec lookup API¶
In the following functions, the encoding string is looked up converted to all
lower-case characters, which makes encodings looked up through this mechanism
effectively case-insensitive. If no codec is found, a KeyError
is set
and NULL
returned.
-
PyObject *PyCodec_Encoder(const char *encoding)¶
- Return value: New reference. Part of the Stable ABI.
Get an encoder function for the given encoding.
-
PyObject *PyCodec_Decoder(const char *encoding)¶
- Return value: New reference. Part of the Stable ABI.
Get a decoder function for the given encoding.
-
PyObject *PyCodec_IncrementalEncoder(const char *encoding, const char *errors)¶
- Return value: New reference. Part of the Stable ABI.
Get an
IncrementalEncoder
object for the given encoding.
-
PyObject *PyCodec_IncrementalDecoder(const char *encoding, const char *errors)¶
- Return value: New reference. Part of the Stable ABI.
Get an
IncrementalDecoder
object for the given encoding.
-
PyObject *PyCodec_StreamReader(const char *encoding, PyObject *stream, const char *errors)¶
- Return value: New reference. Part of the Stable ABI.
Get a
StreamReader
factory function for the given encoding.
-
PyObject *PyCodec_StreamWriter(const char *encoding, PyObject *stream, const char *errors)¶
- Return value: New reference. Part of the Stable ABI.
Get a
StreamWriter
factory function for the given encoding.
Registry API for Unicode encoding error handlers¶
-
int PyCodec_RegisterError(const char *name, PyObject *error)¶
- Part of the Stable ABI.
Register the error handling callback function error under the given name. This callback function will be called by a codec when it encounters unencodable characters/undecodable bytes and name is specified as the error parameter in the call to the encode/decode function.
The callback gets a single argument, an instance of
UnicodeEncodeError
,UnicodeDecodeError
orUnicodeTranslateError
that holds information about the problematic sequence of characters or bytes and their offset in the original string (see Unicode Exception Objects for functions to extract this information). The callback must either raise the given exception, or return a two-item tuple containing the replacement for the problematic sequence, and an integer giving the offset in the original string at which encoding/decoding should be resumed.Return
0
on success,-1
on error.
-
PyObject *PyCodec_LookupError(const char *name)¶
- Return value: New reference. Part of the Stable ABI.
Lookup the error handling callback function registered under name. As a special case
NULL
can be passed, in which case the error handling callback for “strict” will be returned.
-
PyObject *PyCodec_StrictErrors(PyObject *exc)¶
- Return value: Always NULL. Part of the Stable ABI.
Raise exc as an exception.
-
PyObject *PyCodec_IgnoreErrors(PyObject *exc)¶
- Return value: New reference. Part of the Stable ABI.
Ignore the unicode error, skipping the faulty input.
-
PyObject *PyCodec_ReplaceErrors(PyObject *exc)¶
- Return value: New reference. Part of the Stable ABI.
Replace the unicode encode error with
?
orU+FFFD
.
-
PyObject *PyCodec_XMLCharRefReplaceErrors(PyObject *exc)¶
- Return value: New reference. Part of the Stable ABI.
Replace the unicode encode error with XML character references.
-
PyObject *PyCodec_BackslashReplaceErrors(PyObject *exc)¶
- Return value: New reference. Part of the Stable ABI.
Replace the unicode encode error with backslash escapes (
\x
,\u
and\U
).
-
PyObject *PyCodec_NameReplaceErrors(PyObject *exc)¶
- Return value: New reference. Part of the Stable ABI since version 3.7.
Replace the unicode encode error with
\N{...}
escapes.Added in version 3.5.
Codec utility variables¶
-
const char *Py_hexdigits¶
A string constant containing the lowercase hexadecimal digits:
"0123456789abcdef"
.Added in version 3.3.


— Python module browser support

pyclbr
— Python module browser support¶
Source code: Lib/pyclbr.py
The pyclbr
module provides limited information about the
functions, classes, and methods defined in a Python-coded module. The
information is sufficient to implement a module browser. The
information is extracted from the Python source code rather than by
importing the module, so this module is safe to use with untrusted code.
This restriction makes it impossible to use this module with modules not
implemented in Python, including all standard and optional extension
modules.
- pyclbr.readmodule(module, path=None)¶
Return a dictionary mapping module-level class names to class descriptors. If possible, descriptors for imported base classes are included. Parameter module is a string with the name of the module to read; it may be the name of a module within a package. If given, path is a sequence of directory paths prepended to
sys.path
, which is used to locate the module source code.This function is the original interface and is only kept for back compatibility. It returns a filtered version of the following.
- pyclbr.readmodule_ex(module, path=None)¶
Return a dictionary-based tree containing a function or class descriptors for each function and class defined in the module with a
def
orclass
statement. The returned dictionary maps module-level function and class names to their descriptors. Nested objects are entered into the children dictionary of their parent. As with readmodule, module names the module to be read and path is prepended to sys.path. If the module being read is a package, the returned dictionary has a key'__path__'
whose value is a list containing the package search path.
Added in version 3.7: Descriptors for nested definitions. They are accessed through the new children attribute. Each has a new parent attribute.
The descriptors returned by these functions are instances of Function and Class classes. Users are not expected to create instances of these classes.
Function Objects¶
- class pyclbr.Function¶
Class
Function
instances describe functions defined by def statements. They have the following attributes:- file¶
Name of the file in which the function is defined.
- module¶
The name of the module defining the function described.
- name¶
The name of the function.
- lineno¶
The line number in the file where the definition starts.
- parent¶
For top-level functions,
None
. For nested functions, the parent.Added in version 3.7.
- children¶
A
dictionary
mapping names to descriptors for nested functions and classes.Added in version 3.7.
Class Objects¶
- class pyclbr.Class¶
Class
Class
instances describe classes defined by class statements. They have the same attributes asFunctions
and two more.- file¶
Name of the file in which the class is defined.
- module¶
The name of the module defining the class described.
- name¶
The name of the class.
- lineno¶
The line number in the file where the definition starts.
- parent¶
For top-level classes,
None
. For nested classes, the parent.Added in version 3.7.
- children¶
A dictionary mapping names to descriptors for nested functions and classes.
Added in version 3.7.
- super¶
A list of
Class
objects which describe the immediate base classes of the class being described. Classes which are named as superclasses but which are not discoverable byreadmodule_ex()
are listed as a string with the class name instead of asClass
objects.
- methods¶
A
dictionary
mapping method names to line numbers. This can be derived from the newerchildren
dictionary, but remains for back-compatibility.


Monitoring C API

Monitoring C API¶
Added in version 3.13.
An extension may need to interact with the event monitoring system. Subscribing
to events and registering callbacks can be done via the Python API exposed in
sys.monitoring
.
Generating Execution Events¶
The functions below make it possible for an extension to fire monitoring
events as it emulates the execution of Python code. Each of these functions
accepts a PyMonitoringState
struct which contains concise information
about the activation state of events, as well as the event arguments, which
include a PyObject*
representing the code object, the instruction offset
and sometimes additional, event-specific arguments (see sys.monitoring
for details about the signatures of the different event callbacks).
The codelike
argument should be an instance of types.CodeType
or of a type that emulates it.
The VM disables tracing when firing an event, so there is no need for user code to do that.
Monitoring functions should not be called with an exception set, except those listed below as working with the current exception.
-
type PyMonitoringState¶
Representation of the state of an event type. It is allocated by the user while its contents are maintained by the monitoring API functions described below.
All of the functions below return 0 on success and -1 (with an exception set) on error.
See sys.monitoring
for descriptions of the events.
-
int PyMonitoring_FirePyStartEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)¶
Fire a
PY_START
event.
-
int PyMonitoring_FirePyResumeEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)¶
Fire a
PY_RESUME
event.
-
int PyMonitoring_FirePyReturnEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *retval)¶
Fire a
PY_RETURN
event.
-
int PyMonitoring_FirePyYieldEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *retval)¶
Fire a
PY_YIELD
event.
-
int PyMonitoring_FireCallEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *callable, PyObject *arg0)¶
Fire a
CALL
event.
-
int PyMonitoring_FireLineEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, int lineno)¶
Fire a
LINE
event.
-
int PyMonitoring_FireJumpEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *target_offset)¶
Fire a
JUMP
event.
-
int PyMonitoring_FireBranchLeftEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *target_offset)¶
Fire a
BRANCH_LEFT
event.
-
int PyMonitoring_FireBranchRightEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *target_offset)¶
Fire a
BRANCH_RIGHT
event.
-
int PyMonitoring_FireCReturnEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *retval)¶
Fire a
C_RETURN
event.
-
int PyMonitoring_FirePyThrowEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)¶
Fire a
PY_THROW
event with the current exception (as returned byPyErr_GetRaisedException()
).
-
int PyMonitoring_FireRaiseEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)¶
Fire a
RAISE
event with the current exception (as returned byPyErr_GetRaisedException()
).
-
int PyMonitoring_FireCRaiseEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)¶
Fire a
C_RAISE
event with the current exception (as returned byPyErr_GetRaisedException()
).
-
int PyMonitoring_FireReraiseEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)¶
Fire a
RERAISE
event with the current exception (as returned byPyErr_GetRaisedException()
).
-
int PyMonitoring_FireExceptionHandledEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)¶
Fire an
EXCEPTION_HANDLED
event with the current exception (as returned byPyErr_GetRaisedException()
).
-
int PyMonitoring_FirePyUnwindEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)¶
Fire a
PY_UNWIND
event with the current exception (as returned byPyErr_GetRaisedException()
).
-
int PyMonitoring_FireStopIterationEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *value)¶
Fire a
STOP_ITERATION
event. Ifvalue
is an instance ofStopIteration
, it is used. Otherwise, a newStopIteration
instance is created withvalue
as its argument.
Managing the Monitoring State¶
Monitoring states can be managed with the help of monitoring scopes. A scope would typically correspond to a Python function.
-
int PyMonitoring_EnterScope(PyMonitoringState *state_array, uint64_t *version, const uint8_t *event_types, Py_ssize_t length)¶
Enter a monitored scope.
event_types
is an array of the event IDs for events that may be fired from the scope. For example, the ID of aPY_START
event is the valuePY_MONITORING_EVENT_PY_START
, which is numerically equal to the base-2 logarithm ofsys.monitoring.events.PY_START
.state_array
is an array with a monitoring state entry for each event inevent_types
, it is allocated by the user but populated byPyMonitoring_EnterScope()
with information about the activation state of the event. The size ofevent_types
(and hence also ofstate_array
) is given inlength
.The
version
argument is a pointer to a value which should be allocated by the user together withstate_array
and initialized to 0, and then set only byPyMonitoring_EnterScope()
itself. It allows this function to determine whether event states have changed since the previous call, and to return quickly if they have not.The scopes referred to here are lexical scopes: a function, class or method.
PyMonitoring_EnterScope()
should be called whenever the lexical scope is entered. Scopes can be reentered, reusing the same state_array and version, in situations like when emulating a recursive Python function. When a code-like’s execution is paused, such as when emulating a generator, the scope needs to be exited and re-entered.The macros for event_types are:
Macro
Event
-
PY_MONITORING_EVENT_BRANCH_LEFT¶
-
PY_MONITORING_EVENT_BRANCH_RIGHT¶
-
PY_MONITORING_EVENT_CALL¶
-
PY_MONITORING_EVENT_C_RAISE¶
-
PY_MONITORING_EVENT_C_RETURN¶
-
PY_MONITORING_EVENT_EXCEPTION_HANDLED¶
-
PY_MONITORING_EVENT_INSTRUCTION¶
-
PY_MONITORING_EVENT_JUMP¶
-
PY_MONITORING_EVENT_LINE¶
-
PY_MONITORING_EVENT_PY_RESUME¶
-
PY_MONITORING_EVENT_PY_RETURN¶
-
PY_MONITORING_EVENT_PY_START¶
-
PY_MONITORING_EVENT_PY_THROW¶
-
PY_MONITORING_EVENT_PY_UNWIND¶
-
PY_MONITORING_EVENT_PY_YIELD¶
-
PY_MONITORING_EVENT_RAISE¶
-
PY_MONITORING_EVENT_RERAISE¶
-
PY_MONITORING_EVENT_STOP_ITERATION¶
-
PY_MONITORING_EVENT_BRANCH_LEFT¶
-
int PyMonitoring_ExitScope(void)¶
Exit the last scope that was entered with
PyMonitoring_EnterScope()
.
-
int PY_MONITORING_IS_INSTRUMENTED_EVENT(uint8_t ev)¶
Return true if the event corresponding to the event ID ev is a local event.
Added in version 3.13.
Deprecated since version 3.14: This function is soft deprecated.