Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iter for single value.... #751

Closed
jklymak opened this issue Jan 12, 2019 · 5 comments · Fixed by #891
Closed

iter for single value.... #751

jklymak opened this issue Jan 12, 2019 · 5 comments · Fixed by #891

Comments

@jklymak
Copy link

jklymak commented Jan 12, 2019

Perhaps related to #55, but I can't see where that was resolved...

I have the input to a function that can either be a single value or an array. I just want the first value of the array or the value. Note that this has to work with or without pint.

If I do

import pint

ureg = pint.UnitRegistry()
ureg.setup_matplotlib(True)

width = 0.25 * ureg.cm
print(np.iterable(width))
print(width[0])

I get:

True
Traceback (most recent call last):
  File "/Users/jklymak/pint/pint/quantity.py", line 1400, in __getitem__
    value = self._magnitude[key]
TypeError: 'float' object is not subscriptable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "testBar.py", line 13, in <module>
    print(width[0])
  File "/Users/jklymak/pint/pint/quantity.py", line 1404, in __getitem__
    "supports indexing".format(self._magnitude))
TypeError: Neither Quantity object nor its magnitude (0.25)supports indexing

Note that iter(width) also works fine...

So maybe I'm just missing something, but how do I check if width is a singleton?

@hgrecco
Copy link
Owner

hgrecco commented Jan 13, 2019

This because pint (currently) uses a single type for iterable and non-iterable object. Quantity does has a __iter__ method and a __getitem__ method which is implemented by dispatching to the underlying type. I think that iter just checks that these exists and therefore works. You should check the magnitude print(np.iterable(width.m))

@jklymak
Copy link
Author

jklymak commented Jan 14, 2019

Ok, but if I do

b = array(3)
iter(b)
<ipython-input-10-4e62f6ba0650> in <module>
----> 1 iter(b)

TypeError: iteration over a 0-d array

If I do the same with a pint object...

In [11]: a = 3 * ureg.cm

In [12]: iter(a)
Out[12]: <iterator at 0x116c39390>

I'd argue pint should do the same thing as numpy...

Agreed that a.m doesn't iterate, but we can't assume a has a method m. We assume that a is something like a list, or numpy array, or a singleton, and that generally works for pint except for the singleton.

@hgrecco
Copy link
Owner

hgrecco commented Jan 14, 2019

True. According to the iter docs

object must be a collection object which supports the
iteration protocol (the iter() method), or it must support the sequence
protocol (the getitem() method with integer arguments starting at 0).
If it does not support either of those protocols, TypeError is raised.

Therefore, I think that could be accomplished by doing for __getitem__ the same trick we do for __iter__ here: https://github.com/hgrecco/pint/blob/master/pint/quantity.py#L136

@crusaderky
Copy link
Contributor

The fix seems straightforward - just need to change __iter__ to return an iterator, as opposed to being an iterator function itself.

class Wrapper:
    def __init__(self, inner):
        self.inner = inner

    def __iter__(self):
        it_inner = iter(self.inner)

        def it_outer():
            for elem in it_inner:
                yield (elem, "wrapped")

        return it_outer()


a = Wrapper([1, 2])
print(iter(a))
print(list(iter(a)))
b = Wrapper(1)
iter(b)

Output:

<generator object Wrapper.__iter__.<locals>.it_outer at 0x7fcc4ffb2468>
[(1, 'wrapped'), (2, 'wrapped')]
Traceback (most recent call last):
  File "iter_wrap.py", line 20, in <module>
    iter(b)
  File "iter_wrap.py", line 6, in __iter__
    it_inner = iter(self.inner)
TypeError: 'int' object is not iterable

@jthielen
Copy link
Contributor

@crusaderky Thanks for catching that! I can't believe I missed that. I put in #891 with your suggested fix.

@bors bors bot closed this as completed in 6206100 Oct 28, 2019
@bors bors bot closed this as completed in #891 Oct 28, 2019
jthielen added a commit to jthielen/pint that referenced this issue Nov 23, 2019
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 a pull request may close this issue.

4 participants