Skip to content

Conversation

@sayandipdutta
Copy link
Owner

No description provided.

Lib/operator.py Outdated
"""
__slots__ = ('_items', '_defaults')

def __init__(self, items, /, defaults = None):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No spaces around =: defaults=None

Lib/operator.py Outdated
__slots__ = ('_items', '_defaults')

def __init__(self, items, /, defaults = None):
self._items = tuple(items)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if not isinstance(items, tuple):
    items = tuple(items)
self._items = items

Lib/operator.py Outdated

def __init__(self, items, /, defaults = None):
self._items = tuple(items)
self._defaults = () if defaults is None else tuple(defaults)
Copy link

@dg-pb dg-pb Nov 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not cut it. E.g. if one sources itertools.repeat(None), this goes to infinite loop.

if defaults is None:
    defaults = ()
elif isinstance(defaults, (tuple, list)):
    defaults = defaults[:len(items)]
else:
    defaults = itl.islice(defaults, len(items))
if not isinstance(defaults, tuple):
    defaults = tuple(defaults)
self._defaults = defaults

Might need alternative to islice not use itertools if it is not a dependency. And maybe some simplification to above conditionals possible.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, probably need a test for infinite defaults iterator.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I had a version with a custom islice I forgot to update it. Thanks.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not cut it. E.g. if one sources itertools.repeat(None), this goes to infinite loop.

...
elif isinstance(defaults, (tuple, list)):
    defaults = defaults[:len(items)]
else:
    defaults = itl.islice(defaults, len(items))
...

Might need alternative to islice not use itertools if it is not a dependency. And maybe some simplification to above conditionals possible.

So you would expect extra defaults to get cut-off at creation time, even for sequences? That changes things in c implementation. Just to be clear, you'd expect itemtuplegetter([], defaults=(1, 2, 3)).defaults == (), right?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Behaviour of sequences need to be consistent with iterators. Otherwise it is a mess...

PyObject_HEAD
PyObject *items;
PyObject *defaults;
Py_ssize_t nitems;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getting a number of items in a tuple is very cheap in C, thus it is best to minimize class attributes, by not storing nitems and ndefaults.

Copy link

@dg-pb dg-pb Nov 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm.
It is ~2.5 ns, to be precise.
I see now that itemgetter does it, so maybe it makes sense keeping these.

nitems = PyTuple_GET_SIZE(items);

if (defaultitbl == Py_None) {
defaults = PyTuple_New(0);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This increments ref count.
Then below increments again:

itg->defaults = Py_NewRef(defaults);

itemtuplegetter_call_impl(itemtuplegetterobject *itg, PyObject *obj)
{
PyObject *result;
Py_ssize_t nitems=itg->nitems, ndefaults=itg->ndefaults;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick. would look nicer split into 2 lines


item = PyTuple_GET_ITEM(itg->items, i);
found = PyObject_GetItem(obj, item);
val = (found == NULL) ? PyTuple_GET_ITEM(itg->defaults, i) : found;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be clearer to do a statement instead of ternary.

Also, need to Py_INCREF in case of default

Lib/operator.py Outdated
ignored.
The returned callable has two read-only properties:
operator.itemtulegetter.items: a tuple containing items to fetch
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

itemtuPle
& one below

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants