[Bf-python] PySequence_Fast() usage

Yann Vernier yann at donkey.dyndns.org
Wed Jan 11 05:52:56 CET 2006


On Tue, 10 Jan 2006 19:50:50 -0800
Ken Hughes <khughes at pacific.edu> wrote:

> PySequence_Fast_GET_ITEM() seems better than PySequence_GetItem() or 
> PySequence_ITEM() since the latter two return new references.  But am
> I overlooking some possible non-list and non-tuple sequence that
> could be passed to Mesh, and would this be relying on an undocumented
> side-effect which might bite me later?

PySequence_Fast_GET_ITEM() is not valid to call without first using
PySequence_Fast(). However, as you noted PySequence_Fast() will return
a reference to the same object if it indeed is a tuple or list, so it
is a very cheap operation (reference count increase). If the sequence
was incompatible, however, it might build a tuple for you. In short,
if you're passed a list or tuple this method will be *very* cheap, but
if you're passed some other object that implements sequence protocol,
contains many items, and you're only interested in a few of the items,
the conversion to a fast sequence may be costly. Once you have your
fast sequence, you can be sure that reading it will not have side
effects, and all items are present. 

PySequence_ITEM() doesn't check that the object actually provides the
sequence protocol. This is the typical function to use if you're going
to fetch several items, but won't necessarily need to access them all
at once. The reference count increase will normally be a cheap
operation - the sequence had a reference - but there may be exceptions,
like C/Python types wrapping other data and generating their items
wrapped on the fly. PySequence_Fast() would cause *all* items to be
wrapped in one fell swoop in that case. Before calling PySequence_ITEM()
you must verify that the object implements sequence protocol using
PySequence_Check(), or you will segfault. 

PySequence_GetItem() is the careful variant of the bunch. Essentially
it does a PySequence_Check() and a PySequence_ITEM(), so it's
appropriate if you want to fetch only one or a few items from an
object. It cannot crash like PySequence_ITEM() would, but of course it
can still fail. Notably PySequence_Fast_GET_ITEM() can *not* fail
unless you cause python code to run. Also, PySequence_GetItem()
supports negative indices in the same way Python does. 

You must always be careful about side effects when dealing with
references, particularly borrowed ones. For instance, your argument
list is a tuple and your caller holds a reference to it, so it and its
direct children will not disappear on you - but the contents of a list
you've been passed as an argument may. The Python interpreter holds a
global lock when running C/Python modules, so you can know where such
side effects can occur - for instance, PySequence_GetItem() and
PySequence_ITEM() can cause side effects, as they call the object's
getitem method, but PySequence_Fast_GET_ITEM() cannot (that's what
PySequence_Fast() guarantees). However, PySequence_Fast_GET_ITEM()
doesn't give *you* the reference - it still belongs to the sequence -
so if it was a list in the first place, other side effects may render
your borrowed reference invalid! 

I hope that clears more up than it causes confusion..



More information about the Bf-python mailing list