Python'da bir zincirleme yöntem çizgisi nasıl kırılır?


139

Aşağıdaki kodun bir satırı var (adlandırma kuralları için suçlama, onlar benim değil):

subkeyword = Session.query(
    Subkeyword.subkeyword_id, Subkeyword.subkeyword_word
).filter_by(
    subkeyword_company_id=self.e_company_id
).filter_by(
    subkeyword_word=subkeyword_word
).filter_by(
    subkeyword_active=True
).one()

Nasıl göründüğünü sevmiyorum (çok okunabilir değil), ancak bu durumda satırları 79 karakterle sınırlamak için daha iyi bir fikrim yok. Onu kırmanın daha iyi bir yolu var mı (tercihen ters eğik çizgi olmadan)?

Yanıtlar:


257

Ek parantez kullanabilirsiniz:

subkeyword = (
        Session.query(Subkeyword.subkeyword_id, Subkeyword.subkeyword_word)
        .filter_by(subkeyword_company_id=self.e_company_id)
        .filter_by(subkeyword_word=subkeyword_word)
        .filter_by(subkeyword_active=True)
        .one()
    )

Ben de en çok hoşuma gidiyor. Daha fazla kod eklemez ve ters eğik çizgi içermez.
Juliusz Gonera

22
Buradaki ekstra girintiyi neyin haklı kıldığından emin değil; Bu çözümün sadece bir kez girintili asılı çizgiler ve sondaki parantez hiç olmadığı kadar iyi olduğunu düşünüyorum.
Carl Meyer

4
Bence burada çift girintiler yararlıdır çünkü normal girintili bloktan görsel olarak farklıdır. Diğer kodlarla çevrili olduğunda, bu, sarılı tek bir satır olduğunu daha açık hale getirir.
sth

1
Parens kullanımı açısından en iyi cevap. Başka bir cevapta Shanimal tarafından yapılan bir yorumda belirtildiği gibi, parantez üzerinden zımni satır devamının kullanılması aslında PEP 8'in devam karakteri ile tercih edilir ``
kevlarr

Ters eğik çizgileri tercih ederim. Parantez tüm durumlar için bir ipucu değildir. Örnek olarak, atama işleci ile çalışmaz. Bu zincirdeki çizgileri kırmak istediğinizi düşünün:foo.set_default('bar', {}).set_default('spam', {}).set_default('eggs', {})['lol'] = 'yeah'
loutre

56

Bu, parantez açmak için bir satır devam karakterinin tercih edildiği bir durumdur. Bu stil gereksinimi, yöntem adları uzadıkça ve yöntemler bağımsız değişken almaya başladığında daha belirgin hale gelir:

subkeyword = Session.query(Subkeyword.subkeyword_id, Subkeyword.subkeyword_word) \
                    .filter_by(subkeyword_company_id=self.e_company_id)          \
                    .filter_by(subkeyword_word=subkeyword_word)                  \
                    .filter_by(subkeyword_active=True)                           \
                    .one()

PEP 8, hem pratik hem de güzel için bir sağduyu ölçüsü ve gözle yorumlanmayı amaçlamaktadır. Çirkin veya okunması zor kodlarla sonuçlanan PEP 8 yönergelerini mutlu bir şekilde ihlal edin.

Bununla birlikte, kendinizi sık sık PEP 8 ile orantılı bulursanız, beyaz alan seçiminizi aşan okunabilirlik sorunlarının olduğunu gösteren bir işaret olabilir :-)


2
Ters eğik çizgiler için +1 ve bu özel durumda zincirleme filtrelerin hizalanması. Bu durum ayrıca Django doğar ve en okunabilir bu şekilde - ama herhangi ben parantez ifadeler gibi hissediyorum diğer durum üstündür (muzdarip değil "benim ters eğik çizgiden sonra orada boşluk nedir?" Sorunu). Bununla birlikte, ifadeyi parantez içine almak aynı etkiyi elde etmek için kullanılabilir - ancak sizi pırıltı bulduğum Python'u okumanın ortasında Lisp okuma moduna sokar.
zxq9

11
Bu çözümün "yöntem adları uzadıkça ve yöntemler bağımsız değişkenler almaya başladığında" ya "dış parantez içinde sarın" ya da "her açık parantezden sonra ve her bir parantezden önce satır sonundan" nasıl daha iyi başa çıkabildiğini görmüyorum. çözümleri. Aslında, (en azından burada gösterildiği gibi) her asma hattı için çok daha derin bir girinti gerektirdiğinden, işlemede daha kötüdür.
Carl Meyer

1
Filtre çağrıları için çok fazla girinti. Burada bir sekme veya 4 boşluk yeterli olurdu. Ayrıca `` ... Bu boşluk tuşunu kaç saniye basılı tuttunuz? Genellikle, yarının yokmuş gibi boşluk tuşuna basmanızı gerektiren tüm yollara karşıyım.
Zelphir Kaltstahl

2
fwiw, PEP8, "Uzun satırları kaydırmanın tercih edilen yolu, Python'un parantez, parantez ve parantez içindeki zımni satır devamını kullanmaktır. Uzun çizgiler, parantez içindeki ifadeler sarılarak birden çok satır üzerinden kesilebilir. Bunlar, ters eğik çizgi kullanılmasına tercih edilmelidir hat devamı için. " - Python.org Bu ters eğik uygun olabilir ne zaman görüşmek üzere gider
shanimal

PEP8'e harika referans! Burada her ayar bileziği ile bir can sıkıcı sorun .filterçağrıları değiştirmek eğer ki subkeywordüzere sub_keyword, artık girintilemesini düzeltmek zorunda her satırda değişken adını değiştirdi sırf. Stil aslında sürdürülebilirliği engellediğinde iyi değil ...
kevlarr

15

Kişisel seçimim:

subkeyword = Session.query (
    Subkeyword.subkeyword_id,
    Subkeyword.subkeyword_word,
).tarafından filtre(
    subkeyword_company_id = self.e_company_id,
    subkeyword_word = subkeyword_word,
    subkeyword_active = Doğru,
).bir()

1
Kabul edilen birkaç parametre olup olmadığını kabul ediyorum, ancak 0 veya 1 parametre yaygın olduğunda çirkin görünüyor. Örneğin: gist.github.com/andybak/b23b6ad9a68c7e1b794d
Andy Baker

1
Evet, bu tarzın dejenere vakaları var (her tarzda olduğu gibi). Bütün açık parensleri kırmazdım. Bunların hiçbiri beni mutlu etmiyor, ancak işte bazı durumlar: gist.github.com/pkoch/8098c76614765750f769
pkoch

12

Sadece ara sonucu / nesneyi saklayın ve bir sonraki yöntemi çağırın, örn.

q = Session.query(Subkeyword.subkeyword_id, Subkeyword.subkeyword_word)
q = q.filter_by(subkeyword_company_id=self.e_company_id)
q = q.filter_by(subkeyword_word=subkeyword_word)
q = q.filter_by(subkeyword_active=True)
subkeyword = q.one()

10
Bu bir sorgu gibi bir şey için iyi çalışır, ancak genel bir desen olarak, o kadar emin değilim. Örneğin, Güzel Çorba'da zincirleme yaparken team_members = soup.find(class_='section team').find_all('ul').find_all('li'), her .find(...)aramadaki dönüş değeri team_membershenüz anlamına uymuyor .
Taylor Edmiston

1
@TaylorEdmiston Kısmen elde edilen sonuçlar için farklı isimler olabilir. Böyle bir şey section = soup.find(class_='section team')ve team_members = section.find_all('ul').find_all('li').
Jeyekomon

4

Python Dil Referansına Göre
Ters eğik çizgi kullanabilirsiniz.
Veya basitçe kırın. Bir parantez eşleştirilmezse, python bunu bir satır olarak kabul etmez. Ve bu şartlar altında, aşağıdaki çizgilerin girintisi önemli değildir.


4

Başkaları tarafından sağlanandan biraz farklı bir çözüm ama benim favorim çünkü bazen şık meta programlamaya yol açıyor.

base = [Subkeyword.subkeyword_id, Subkeyword_word]
search = {
    'subkeyword_company_id':self.e_company_id,
    'subkeyword_word':subkeyword_word,
    'subkeyword_active':True,
    }
subkeyword = Session.query(*base).filter_by(**search).one()

Bu, arama oluşturmak için güzel bir tekniktir. Karmaşık sorgu formunuzdan (veya kullanıcının aradığı şeyle ilgili dize tabanlı kesintilerden) madencilik için bir koşul listesi gözden geçirin, ardından sözlüğü filtreye dönüştürün.


1

SQLAlchemy kullanılıyor gibi görünüyor, eğer doğruysa, sqlalchemy.orm.query.Query.filter_by()yöntem birden fazla anahtar kelime argümanı alır, böylece şöyle yazabilirsiniz:

subkeyword = Session.query(Subkeyword.subkeyword_id,
                           Subkeyword.subkeyword_word) \
                    .filter_by(subkeyword_company_id=self.e_company_id,
                               subkeyword_word=subkeyword_word,
                               subkeyword_active=True) \
                    .one()

Ama daha iyi olurdu:

subkeyword = Session.query(Subkeyword.subkeyword_id,
                           Subkeyword.subkeyword_word)
subkeyword = subkeyword.filter_by(subkeyword_company_id=self.e_company_id,
                                  subkeyword_word=subkeyword_word,
                                  subkeyword_active=True)
subkeuword = subkeyword.one()

SQLAlchemy filter_by () ipucu için +1. Bu örnek için iyi, ancak genellikle sadece 1 koşulu kabul eden filter () kullanıyorum.
Juliusz Gonera

1

Ben iki blok ve bir blok tarafından ifade, bu gibi argüman girintili gibi:

for image_pathname in image_directory.iterdir():
    image = cv2.imread(str(image_pathname))
    input_image = np.resize(
            image, (height, width, 3)
        ).transpose((2,0,1)).reshape(1, 3, height, width)
    net.forward_all(data=input_image)
    segmentation_index = net.blobs[
            'argmax'
        ].data.squeeze().transpose(1,2,0).astype(np.uint8)
    segmentation = np.empty(segmentation_index.shape, dtype=np.uint8)
    cv2.LUT(segmentation_index, label_colours, segmentation)
    prediction_pathname = prediction_directory / image_pathname.name
    cv2.imwrite(str(prediction_pathname), segmentation)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.