A short way to create a single member list in Python?

Suppose I have some object x , which can be a single instance of a data type (e.g. float ) or it can be a list of float types.

Is there something that I can guarantee that x will be wrapped in a list, perhaps if it is a single list without checking its type or anything like that.

I would like something like list(x) just work whether x single or not, but that doesn't work, since singleton is not iterable.

Edit: see my answer below for some development.

At the same time, I don’t want to define my own function for building lists from plain ones, and I don’t want to do anything built-in either:

 from collections import Iterable y = [x] if not isinstance(x, Iterable) else list(x) 

If nothing more concise than this exists, it is OK. I'm looking for some clean way to do this, already built into the language.

I am sure that some might think that the isinstance approach isinstance clean and good, but I'm specifically looking for something more concise, which does not require me to write anything new before hand. I just can’t find anything when searching for pages in a document, and I'm not sure how to ask this question to a search engine.

+4
source share
3 answers

Here is the answer to a question that you did not ask, but perhaps you should have. I can only guess because you were not able to give the appropriate context.

How can I handle an argument passed to me that violates my interface?

You should not try. If I call sum(2) , I get correctly

TypeError: object 'int' is not iterable

because sum expected iterability, and I did not give it. If it bothers you that someone will call both

 my_function(2.2) my_function([2.2, 4.4]) 

The correct answer is to raise a TypeError, rather than trying to fix things for the caller, because as soon as you fix the first case, someone will call

 my_function([2.2, 'loretta']) 

Do you also cover this case? What if they give you a list with links? If you come from a strongly typed language background, there is a strong temptation to abuse Python to act like Java. This only gives bad Python code: you piled hacked over the defect.

And the "security type" is a bit of a concession, otherwise double sqrt(float) will not need to return domain errors, but it is. Should sqrt accept the absolute value of its argument? Masking errors in call signatures only ensure that no defects are detected, and then go back later when you receive an invalid argument that you did not expect.

+5
source

Reviewing this question after much more experience with Python, I came up with one solution, but it violates my then required property, not defining a function.

 def make_list_containing(*args): return list(args) 

Then make_list_containing(3) or make_list_containing('foo') behaves as you would expect (unlike the list constructor, which you need to modify to find out how to expect it).

It is still surprising to me that list as a constructor is synonymous with "convert to list type" and not "put in an instance of a list object".

I see how the polymorphic behavior of a constructor can be ambiguous in the case of single elements, which are also iterable, like strings. But nevertheless, why not support the "place on the list" behavior for indestructible singletons?

Another thing is that, at least for me, the approach that I am describing seems more consistent and more committed to least surprise.

With make_list_containing you know that you always get the list back and that it will contain the elements that were passed. As long as you transmit them in the format you want, this is exactly what you get out. Consider:

 In [34]: make_list_containing(*'foo') Out[34]: ['f', 'o', 'o'] In [35]: make_list_containing('foo') Out[35]: ['foo'] 

or

 In [40]: make_list_containing(*enumerate(range(3))) Out[40]: [(0, 0), (1, 1), (2, 2)] In [41]: make_list_containing(enumerate(range(3))) Out[41]: [<enumerate at 0x7f61a7f0fd70>] 

Now it seems to me more intuitive. Providing * is exactly how I should “de-iterate” the elements inside something as arguments. If I don't go out of my way to select this, then I should treat 'foo' as a singleton and plan to handle its elements or iterable myself inside the function call.

One thing that disappoints in this conversation is that just because this Python convention is old people seems to combine this with meaning, this is not surprising. But this is a narrow definition of surprise. Yes, when I start the translator, I am no longer "surprised" when list('foo') gives me ['f', 'o', 'o'] . But I'm still surprised that this language selection interface for the constructor is as important as list . This surprises me, because, it seems, he has more design flaws than strengths, and what was previously used to justify it consisted in some fixation of the smoothness of the syntax, and not in the clarity of thought.

At this point, he is moving too far into the zone of opinions, and I obviously agree that due to the overwhelming historical impulse this will not be changed in Python. But the spirit of my question still concerns this very legitimate moment. This is not a question of "laziness" or "just writing a wrapper function and moving on," as most comments seem to want it to be.

+1
source

I don't know anything like that built in. Your solution looks like the best option for me, although you can use the ABC sequence instead of Iterable.

0
source

All Articles