Soru Python listesi kavraması nasıl girilir?


Listeyi anlamak bazı durumlarda yararlı olabilir, ancak okumak için oldukça korkunç olabilirler. Biraz abartılı bir örnek olarak, aşağıdakileri nasıl gireceksiniz?

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

49
2017-11-22 18:08


Menşei




Cevaplar:


Ne kadar uzun olduklarına bağlı. Onları şu şekilde yapılandırmaya eğilimliyim:

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

Bu şekilde her ifadenin kendi çizgisi vardır.

Herhangi bir çizgi çok büyük hale gelirse, bir lambda veya ifadeyle çıkarmayı severim:

transform = lambda x: x.id
results = self.db.query(schema.allPostsUuid).execute(timeout=20)
condition = lambda x: x.deleted is not False and ... and ...
[transform(x) for x in results if condition(x)]

Ve eğer bir lambda çok uzun olursa, bir işleve terfi edilir.


58
2017-11-22 18:19



Bunlar eşdeğer DEĞİLDİR - liste kavrama, herhangi bir işlev araması yapmak zorunda olmadığından, birçok kez daha hızlıdır. Uygun çeviri döngüler için kullanacaktır. - Claudiu
Performans isabeti hariç, bu çok okunabilir bir örnek! - Geo
Looplar işlev aramayı nasıl engeller? Ayrıca, liste kavramasındaki döngünün C dilinde uygulandığını ve bu nedenle düz olandan daha hızlı olduğuna dikkat edin. - orestis
Sadece bir not - birden çok kez "ve" yerine kullanmak yerine birden çok ifade kullanabilirsiniz. Komik, küçük bir sözdizimi gerçeği. - cdleary


Çalıştığım yerde, kodlama yönergelerimiz böyle bir şey yapmamızı isterdi:

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
    )
]

42
2017-11-22 19:29



Bu oldukça güzel. - Ali Afshar
Ben böyle yaparım - orip


Benim için bu çok fazla. Belki de bu sadece korkunç bir örnektir, çünkü "tip" ve "silinmiş" açıkça db sorgusunun bir parçası olacaktır.

Bir liste kavraması birden fazla çizgiye yayılıyorsa, muhtemelen liste kavraması olmamalı. Bunu söyledikten sonra, genellikle başka şeylerin olduğu gibi "eğer" diye bir şeyi bölüyorum ve burada cevaplayacağım.


5
2017-11-22 18:15





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

5
2017-11-22 19:32





Bunun için liste anlama kullanmamalısınız.

Anlamaların listesi harika bir özelliktir, ancak normal kod değil, kısayollar içindir.

Böyle uzun bir snippet için normal bloklar kullanmalısınız:

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)

Tam olarak aynı davranış, çok daha okunabilir. Guido seninle gurur duyardı :-)


5
2017-11-22 19:36



Bu adım adım adım inşa etmek zorunda olduğu gibi, bu biraz daha yavaş - Claudiu
Listedeki kavramanın tam olarak kaputun altında aynı olduğunu düşünüyorum. Bunun tek seferlik bir ifade olduğu için değil, çünkü bu bir zaman operasyonu ... - e-satis
e-statis: işlev aynıdır, ancak liste kavramaları önemli ölçüde daha hızlı olabilir - orip
Python kültüründe, genellikle hız üzerinden okunabilirliği seçersiniz. Python zaten hızlı bir dil değil ... - e-satis
Bu şekilde, değişken, fonksiyonel olmayan stil kullanılır. Ölümsüzlük, haritalama ve filtreleme açısından düşünmeyi sağlar. Bu kodda, liste değiştirilir ve okuyucu, daha sonra değiştirilebileceğini akılda tutmak zorundadır. Jeneratör fonksiyonunu daha iyi yapmak yieldbundan daha fazla veya yeni değişkenler ve fonksiyonlar tanıtmak. - George Sovetov


Nasıl hakkında:

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

Genel olarak, alt satırların ön-hesaplama alt-değişkenleri tarafından değişkenlere dönüştürülmesiyle uzun çizgiler önlenebilir, bu da küçük bir performans maliyeti ekleyebilir:

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)]

Bu arada, 'değilis not FalseBir çeşit gereksiz mi? Yok ile Yanlış arasında ayrım yapmaktan mı endişeleniyorsunuz? Aksi halde, durumu yalnızca şu şekilde bırakmak yeterlidir: if (x.type == "post" and x.deleted)


1
2017-11-22 18:10



İkincisi. Tüm dillerde genellikle 80'den fazla karakterden kaçınılmalıdır. - Piotr Lesnicki
Anlaştık, ancak Python'un sözdizimi kuralları genellikle daha uzun hatları teşvik eder / zorlar. Genel olarak beyaz boşluğun ele alınması, dil hakkındaki tek şikayetimdir. - Peter Rowell
Dikkatle seçilmiş değişkenler ve parantez ya da parantezleri olan satırları bölme ile, çok uzun hatlara başvurmak zorunda kalmamıştım (problem daha çok self.long_foo.very_long_bar.baz (....) kullanarak geçici olarak kullanıldı) - Piotr Lesnicki
"Bu arada" hakkında, tamamen gereksiz değil, örneğin x.deleted = None. - Ali Afshar


Eğer bir kavrayışa ayarlanmışsanız orestis'in cevabı iyidir.

Böyle daha karmaşık anlaşmalar için bir jeneratör kullanmayı öneririm 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

1
2017-12-16 14:18