How to indent Python list-comprehensions?

前端 未结 7 1259
失恋的感觉
失恋的感觉 2021-01-30 06:17

List comprehensions can be useful in certain situations, but they can also be rather horrible to read.. As a slightly exaggerated example, how would you indent the following?

相关标签:
7条回答
  • 2021-01-30 06:45

    You should not use a list comprehension for that.

    List comprehensions are an awesome feature, but they are meant to be shortcuts, not regular code.

    For such a long snippet, you should use ordinary blocs :

    allUuids = []
    for x in self.db.query(schema.allPostsUuid).execute(timeout = 20) :
        if x.type == "post" and x.deleted is not False :
            allUuids.append(x.id)
    

    Exactly the same behavior, much more readable. Guido would be proud of you :-)

    0 讨论(0)
  • 2021-01-30 06:53
    allUuids = [x.id 
                for x in self.db.query(schema.allPostsUuid).execute(timeout = 20) 
                if x.type == "post" and x.deleted is not False]
    
    0 讨论(0)
  • 2021-01-30 06:54

    Where I work, our coding guidelines would have us do something like this:

    all_posts_uuid_query = self.db.query(schema.allPostsUuid)
    all_posts_uuid_list = all_posts_uuid_query.execute(timeout=20)
    all_uuid_list = [
        x.id 
        for x in all_posts_uuid_list 
        if (
            x.type == "post" 
            and 
            not x.deleted  # <-- if you don't care about NULLs / None
        )
    ]
    
    0 讨论(0)
  • 2021-01-30 06:58

    For me that's too much. Maybe it's just a terrible example, since "type" and "deleted" would clearly be part of the db query.

    I tend to think that if a list comprehension spans multiple lines it probably shouldn't be a list comprehension. Having said that, I usually just split the thing at "if" like other people have and will answer here.

    0 讨论(0)
  • 2021-01-30 06:58

    How about:

    allUuids = [x.id for x in self.db.query(schema.allPostsUuid).execute(timeout = 20) 
                       if (x.type == "post" and x.deleted is not False)]
    

    Generally, long lines can be avoided by pre-computing subexpressions into variables, which might add a minuscule performance cost:

    query_ids = self.db.query(schema.allPostsUuid).execute(timeout = 20)
    allUuids = [x.id for x in query_ids
                       if (x.type == "post" and x.deleted is not False)]
    

    By the way, isn't 'is not False' kind-of superfluous ? Are you worried about differentiating between None and False ? Because otherwise, it suffices to leave the condition as only: if (x.type == "post" and x.deleted)

    0 讨论(0)
  • 2021-01-30 06:59

    If you're set on a comprehension orestis's answer is good.

    For more complex comprehensions like that I'd suggest using a generator with yield:

    allUuids = list(self.get_all_uuids())
    
    
    def get_all_uuids(self):
        for x in self.db.query(schema.allPostsUuid).execute(timeout = 20):
            if x.type == "post" and x.deleted is not False:
                yield x.id
    
    0 讨论(0)
提交回复
热议问题