Why a generator object is obtained instead of a li

2020-02-15 09:22发布

问题:

Using Python 3.4, I have the following JSON

mylist = [
        {
          "mdata": [
                    {
                      "url" : "http://fake1001/Standard",
                      "fmt" : "Standard"
                    },                            
                    {
                      "url" : "http://fake1001/Thumb",
                      "fmt" : "Thumb"
                    }                                      
                    ]
        },
        {
          "mdata": [
                    {
                      "url" : "http://fake1002/Standard",
                      "fmt" : "Standard"
                    },                            
                    {
                      "url" : "http://fake1002/Large",
                      "fmt" : "Large"
                    }                                      
                    ]
        },
        {
          "mdata": [
                    {
                      "url" : "http://fake1003/Thumb",
                      "fmt" : "Thumb"
                    },                            
                    {
                      "url" : "http://fake1003/Large",
                      "fmt" : "Large"
                    }                                      
                    ]
        }          
      ]

I want to put all urls of items with a "Standard" format into a list:

urls = []

for m in mylist:
  for md in m["mdata"]:
    if md["fmt"] == "Standard":
      urls.append(md["url"])

print(urls)

I get the following result:

['http://fake1001/Standard', 'http://fake1002/Standard']

Now, I tried using list comprehension to do the same task:

urls2 = []
urls2.append(md["url"] for m in mylist for md in m["mdata"] if md["fmt"] == "Standard")

print(urls2)

However, I get a generator object instead:

[<generator object <genexpr> at 0x000000000860F510>]

To get the urls, I can call next() on the generator object:

print(next(urls2[0]))
print(next(urls2[0]))

Which gives me this:

http://fake1001/Standard
http://fake1002/Standard

What I want to know is why the list comprehension gives a generator object, and if there is any way to avoid that?

回答1:

The syntax for a generator expression is:

(i for i in range(10))

You can optionally leave the braces off for functions that take iterables:

sum(i for i in range(10))

You're probably used to the more common list comprehension:

[i for i in range(10)]

To get a list from a generator simply exahust it with list(). In your case:

urls2.append(list(md["url"] for m in mylist for md in m["mdata"] if md["fmt"] == "Standard"))

Or use a list comprehension instead:

urls2.append([md["url"] for m in mylist for md in m["mdata"] if md["fmt"] == "Standard"])