Bagaimana cara memecahkan garis metode dirantai dalam Python?

138

Saya memiliki baris kode berikut (jangan salahkan untuk konvensi penamaan, mereka bukan milik saya):

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

Saya tidak suka seperti apa kelihatannya (tidak terlalu mudah dibaca) tapi saya tidak punya ide yang lebih baik untuk membatasi garis hingga 79 karakter dalam situasi ini. Apakah ada cara yang lebih baik untuk memecahkannya (lebih disukai tanpa garis miring terbalik)?

Juliusz Gonera
sumber

Jawaban:

256

Anda bisa menggunakan tanda kurung tambahan:

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()
    )
sth
sumber
Saya juga suka yang terbaik. Tidak menambahkan kode lagi dan itu tanpa garis miring terbalik.
Juliusz Gonera
22
Tidak yakin apa yang membenarkan lekukan ekstra di sini; Saya pikir solusi ini berbunyi dengan baik dengan garis menggantung indentasi sekali dan paren trailing tidak sama sekali.
Carl Meyer
4
Menurut saya indentasi ganda berguna di sini karena secara visual berbeda dari blok indentasi normal. Ketika dikelilingi oleh kode lain ini membuatnya lebih jelas bahwa itu adalah satu baris yang dibungkus.
sth
1
Jawaban terbaik, dalam hal menggunakan parens. Seperti yang disebutkan dalam komentar oleh Shanimal dalam jawaban lain, menggunakan kelanjutan garis tersirat melalui tanda kurung sebenarnya PEP 8 disukai vs karakter kelanjutan ``
kevlarr
Saya lebih suka garis miring terbalik. Parenthesis bukan petunjuk untuk semua situasi. Sebagai contoh, ini tidak bekerja dengan operator penugasan. Bayangkan Anda ingin memecah garis dalam rantai ini:foo.set_default('bar', {}).set_default('spam', {}).set_default('eggs', {})['lol'] = 'yeah'
loutre
56

Ini adalah kasus di mana karakter kelanjutan garis lebih disukai untuk membuka tanda kurung. Kebutuhan akan gaya ini menjadi lebih jelas ketika nama metode menjadi lebih panjang dan ketika metode mulai mengambil argumen:

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 bermaksud untuk ditafsirkan dengan ukuran akal sehat dan mata untuk yang praktis dan yang indah. Dengan senang hati melanggar pedoman PEP 8 yang menghasilkan kode yang jelek atau sulit dibaca.

Yang sedang berkata, jika Anda sering menemukan diri Anda berselisih dengan PEP 8, itu mungkin merupakan tanda bahwa ada masalah keterbacaan yang melampaui pilihan spasi putih Anda :-)

Raymond Hettinger
sumber
2
+1 pada garis miring terbalik dan meluruskan filter berantai dalam kasus khusus ini. Situasi ini muncul di Django juga dan paling mudah dibaca dengan cara ini - tetapi dalam setiap situasi lain saya merasa seperti frase kurung unggul (tidak menderita dari "ada spasi setelah backslash saya?" Masalah). Yang mengatakan, tanda kurung frase dapat digunakan untuk mencapai efek yang sama - tetapi menempatkan Anda dalam mode membaca Lisp di tengah membaca Python, yang saya temukan menggelegar.
zxq9
11
Saya tidak melihat bagaimana solusi ini lebih baik untuk mengatasi "karena nama metode menjadi lebih panjang dan ketika metode mulai mengambil argumen" daripada "bungkus dalam paren luar" atau "break-line setelah setiap paren terbuka dan sebelum setiap paren dekat" solusi. Sebenarnya lebih buruk dalam menangani itu, karena (setidaknya seperti yang ditunjukkan di sini) itu memerlukan indentasi yang jauh lebih dalam untuk setiap garis yang menggantung.
Carl Meyer
1
Terlalu banyak indentasi untuk panggilan filter. Satu tab atau 4 spasi sudah cukup di sini. Juga pelurusan `` ... Berapa detik yang Anda tahan tombol spasi itu? Secara umum saya menentang semua cara, yang mengharuskan Anda untuk memalu tombol ruang seperti tidak ada hari esok.
Zelphir Kaltstahl
2
fwiw, PEP8 berbunyi "Cara yang disukai untuk membungkus garis panjang adalah dengan menggunakan kelanjutan garis tersirat Python di dalam tanda kurung, tanda kurung dan kawat gigi. Garis panjang dapat dipecah pada beberapa baris dengan membungkus ekspresi dalam tanda kurung. Ini harus digunakan dalam preferensi untuk menggunakan backslash untuk kelanjutan garis. " - Python.org Selanjutnya untuk membahas kapan backslash mungkin tepat
Shanimal
Referensi hebat untuk PEP8! Masalah mengganggu di sini dengan menyelaraskan semua .filterpanggilan adalah bahwa jika Anda mengubah subkeywordke sub_keyword, Anda sekarang harus memperbaiki lekukan dari setiap baris hanya karena Anda mengubah nama variabel. Tidak bagus ketika gaya sebenarnya menghalangi perawatan ...
kevlarr
15

Pilihan pribadi saya adalah:

subkeyword = Session.query (
    Subkeyword.subkeyword_id,
    Subkeyword.subkeyword_word,
) .filter_by (
    subkeyword_company_id = self.e_company_id,
    subkeyword_word = subkeyword_word,
    subkeyword_active = Benar,
).satu()
pkoch
sumber
1
Saya setuju jika ada beberapa parameter yang diteruskan tetapi terlihat jelek ketika 0 atau 1 parameter umum. Misalnya: gist.github.com/andybak/b23b6ad9a68c7e1b794d
Andy Baker
1
Ya, gaya itu memiliki kasus yang merosot (seperti gaya apa pun). Saya tidak akan mematahkan semua parens terbuka. Tidak ada yang membuat saya bahagia, tetapi ada beberapa kasus: gist.github.com/pkoch/8098c76614765750f769
pkoch
12

Simpan saja hasil / objek antara dan aktifkan metode selanjutnya, mis

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()
Ivo van der Wijk
sumber
10
Ini berfungsi baik untuk sesuatu seperti kueri tetapi sebagai pola umum, saya tidak begitu yakin. Misalnya, ketika chaining di Beautiful Soup suka team_members = soup.find(class_='section team').find_all('ul').find_all('li'), nilai balik dari setiap .find(...)panggilan belum sesuai dengan arti team_members.
Taylor Edmiston
1
@TaylorEdmiston Anda dapat memiliki nama yang berbeda untuk hasil sebagian saja. Sesuatu seperti section = soup.find(class_='section team')dan team_members = section.find_all('ul').find_all('li').
Jeyekomon
4

Menurut Referensi Bahasa Python
Anda dapat menggunakan backslash.
Atau cukup hancurkan saja. Jika braket tidak dipasangkan, python tidak akan memperlakukan itu sebagai garis. Dan di bawah keadaan seperti itu, lekukan kalimat berikut tidak masalah.

Haozhun
sumber
4

Ini sedikit solusi yang berbeda dari yang disediakan oleh orang lain tetapi favorit saya karena itu mengarah pada pemrograman yang bagus kadang-kadang.

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

Ini adalah teknik yang bagus untuk membangun pencarian. Buka daftar persyaratan untuk menambang dari formulir kueri kompleks Anda (atau deduksi berbasis string tentang apa yang dicari pengguna), lalu cukup ledarkan kamus ke dalam filter.

Nirni St. Sigurðsson
sumber
1

Anda tampaknya menggunakan SQLAlchemy, jika itu benar, sqlalchemy.orm.query.Query.filter_by()metode mengambil beberapa argumen kata kunci, sehingga Anda dapat menulis seperti:

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

Tetapi akan lebih baik:

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()
minhee
sumber
+1 untuk petunjuk SQLAlchemy filter_by (). Ini bagus untuk contoh ini, tetapi saya sering menggunakan filter () sebagai gantinya hanya menerima 1 kondisi.
Juliusz Gonera
1

Saya suka membuat indentasi argumen dengan dua blok, dan pernyataan dengan satu blok, seperti ini:

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)
acgtyrant
sumber