Cara yang lebih elegan untuk mendeklarasikan beberapa variabel secara bersamaan

140

Untuk mendeklarasikan beberapa variabel pada "waktu yang sama" saya akan lakukan:

a, b = True, False

Tetapi jika saya harus mendeklarasikan lebih banyak variabel, ternyata semakin tidak elegan:

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True ,True , True, True

Apakah ada cara yang lebih baik / elegan / nyaman untuk melakukan ini?

Ini harus sangat mendasar, tetapi jika saya menggunakan daftar atau tuple untuk menyimpan variabel, bagaimana saya harus mendekati sehingga saya akan sangat membantu karena:

aList = [a,b]

Tidak valid, saya harus melakukan:

a, b = True, True

Atau apa yang saya lewatkan?

Trufa
sumber
Gunakan daftar untuk menyimpan nilai-nilai itu? Sebuah kamus? A (bernama) tuple?
Jeff Mercado
@ Chris: Saya sudah sampai di sana. :)
Jeff Mercado
@ JeffM: mungkin tapi saya tidak tahu bagaimana melakukannya tampaknya mereka harus didefinisikan agar menjadi milik daftar (saya mungkin salah tentu saja)
Trufa
3
@ Trufa: Jika Anda akan mendeklarasikan bahwa banyak variabel untuk menyimpan nilai, itu sudah merupakan tanda Anda harus mempertimbangkan alternatif penyimpanan lain IMHO.
Jeff Mercado
1
@ user470379 - Saya agak berasumsi bahwa nama-nama itu hanya untuk kode contoh, dan Trufa tidak menggunakan nama-nama itu dalam kode aslinya.
Chris Lutz

Jawaban:

52

Seperti yang disarankan orang lain, tidak mungkin menggunakan 10 variabel lokal yang berbeda dengan nilai Boolean adalah cara terbaik untuk menulis rutinitas Anda (terutama jika mereka benar-benar memiliki nama satu huruf :)

Bergantung pada apa yang Anda lakukan, mungkin masuk akal untuk menggunakan kamus saja. Misalnya, jika Anda ingin mengatur nilai preset Boolean untuk satu set flag satu huruf, Anda bisa melakukan ini:

>>> flags = dict.fromkeys(["a", "b", "c"], True)
>>> flags.update(dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Jika Anda suka, Anda juga bisa melakukannya dengan satu pernyataan tugas:

>>> flags = dict(dict.fromkeys(["a", "b", "c"], True),
...              **dict.fromkeys(["d", "e"], False))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Parameter kedua untuk dicttidak sepenuhnya dirancang untuk ini: itu benar-benar dimaksudkan untuk memungkinkan Anda untuk menimpa setiap elemen kamus menggunakan argumen kata kunci sepertid=False . Kode di atas meledakkan hasil ekspresi berikut **ke dalam serangkaian argumen kata kunci yang diteruskan ke fungsi yang dipanggil. Ini tentu saja merupakan cara yang andal untuk membuat kamus, dan orang-orang tampaknya paling tidak menerima idiom ini, tetapi saya curiga bahwa beberapa orang mungkin menganggapnya Unpythonic. </disclaimer>


Namun pendekatan lain, yang mungkin paling intuitif jika Anda akan sering menggunakan pola ini, adalah mendefinisikan data Anda sebagai daftar nilai bendera ( True, False) yang dipetakan ke nama bendera (string karakter tunggal). Anda kemudian mengubah definisi data ini menjadi kamus terbalik yang memetakan nama bendera ke nilai bendera. Ini dapat dilakukan dengan cukup ringkas dengan pemahaman daftar bersarang, tetapi inilah implementasi yang sangat mudah dibaca:

>>> def invert_dict(inverted_dict):
...     elements = inverted_dict.iteritems()
...     for flag_value, flag_names in elements:
...         for flag_name in flag_names:
...             yield flag_name, flag_value
... 
>>> flags = {True: ["a", "b", "c"], False: ["d", "e"]}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Fungsi tersebut invert_dictadalah fungsi generator . Ini menghasilkan , atau menghasilkan - yang berarti berulang kali mengembalikan nilai - pasangan kunci-nilai. Pasangan kunci-nilai tersebut adalah kebalikan dari isi dari dua elemen flagskamus awal . Mereka dimasukkan ke dictkonstruktor. Dalam hal inidict konstruktor bekerja secara berbeda dari atas karena diberi makan iterator daripada kamus sebagai argumennya.


Menggambar pada komentar @Chris Lutz: Jika Anda benar-benar akan menggunakan ini untuk nilai-nilai karakter tunggal, Anda dapat melakukannya

>>> flags = {True: 'abc', False: 'de'}
>>> flags = dict(invert_dict(flags))
>>> print flags
{'a': True, 'c': True, 'b': True, 'e': False, 'd': False}

Ini bekerja karena Python string adalah iterable , yang berarti bahwa mereka dapat dipindahkan melalui nilai dengan nilai. Dalam kasus string, nilainya adalah karakter individu dalam string. Jadi ketika mereka ditafsirkan sebagai iterables, seperti dalam kasus ini di mana mereka digunakan dalam for for loop, ['a', 'b', 'c']dan 'abc'secara efektif setara. Contoh lain adalah ketika mereka diteruskan ke fungsi yang membutuhkan iterable, seperti tuple.

Saya pribadi tidak akan melakukan ini karena tidak membaca secara intuitif: ketika saya melihat string, saya berharap itu akan digunakan sebagai nilai tunggal daripada sebagai daftar. Jadi saya melihat baris pertama dan berpikir, "Oke, jadi ada bendera Benar dan bendera Salah." Jadi, meskipun itu suatu kemungkinan, saya pikir itu bukan jalan yang harus ditempuh. Sisi baiknya, mungkin membantu menjelaskan konsep iterables dan iterator dengan lebih jelas.


Menentukan fungsi invert_dict sedemikian rupa sehingga benar-benar mengembalikan kamus juga bukan ide yang buruk; Saya kebanyakan hanya tidak melakukan itu karena tidak benar-benar membantu menjelaskan cara kerja rutin.


Tampaknya Python 2.7 memiliki pemahaman kamus, yang akan membuat cara yang sangat ringkas untuk mengimplementasikan fungsi itu. Ini dibiarkan sebagai latihan untuk pembaca, karena saya tidak menginstal Python 2.7 :)

Anda juga dapat menggabungkan beberapa fungsi dari modul itertools yang selalu serbaguna . Seperti yang mereka katakan, Ada Lebih dari Satu Cara Untuk Melakukannya . Tunggu, orang Python tidak mengatakan itu. Ya, memang benar dalam beberapa kasus. Saya kira Guido telah memberikan kepada kami pemahaman kamus sehingga akan ada Satu Cara Jelas untuk melakukan ini.

intuisi
sumber
1
Catatan yang ['a', 'b', 'c']dapat disingkat menjadi list('abc'), yang menginspirasi def truth_values(trues, falses): d = dict.from_keys(list(trues), True); d.update(dict.from_keys(list(falses), False)); return ddigunakan sebagaivalues = truth_values("abc", "de")
Chris Lutz
Terima kasih banyak, ini sepertinya jawaban yang sangat komprehensif, saya akan memberikan pandangan yang baik dan bereksperimen dengan apa yang Anda prosa, apa yang Anda katakan, sementara itu mungkin benar, itu tidak wajar untuk mungkin jadi saya harus membaca sedikit dan bermain-main sampai saya sepenuhnya mendapatkan apa yang Anda maksudkan secara khusus karena kamus yang merupakan salah satu kelemahan saya dalam python belum. Terima kasih banyak, saya akan kembali :)
Trufa
5
@intuited Saya terperangah dengan jawaban Anda: Anda mendefinisikan masalah lain daripada OP dan Anda senang melakukan jawaban panjang untuk masalah lain ini. Dia tidak ingin mengaitkan string dan nilai dalam kamus, dia ingin membuat objek dengan pengidentifikasi dan nilai untuk masing-masing.
eyquem
5
@eyquem: Jawaban panjangnya buruk? Dokter, sembuhkan dirimu!
John Machin
5
Ini tidak menjawab pertanyaan, dan itu menggurui. Lihat jawaban di bawah ini
kodu
225
a, b, c, d, e, g, h, i, j = (True,)*9
f = False
Shariq
sumber
21
@Imray Notasi koma Trailing (d,)membuat tupel satu item, yang merupakan tipe urutan. Jenis urutan mendukung penambahan dan perkalian, di antara operasi lainnya.
duozmo
36
Trik yang elegan, tetapi berhati-hatilah dalam menggunakan ini pada elemen yang bisa berubah seperti daftar. Misalnya a, b, c = ([],)*3tidak membuat 3 daftar instance tetapi membuat a, bdan cmenunjuk ke instance yang sama.
Zac
5
Saya bertanya-tanya banyak waktu saya saya buang / habiskan mencoba membuat kode python saya uber pythonic?
SARose
3
@Zac untuk melakukannya dengan benar, gunakan a, b, c = ([] for i in range(3)). sumber . Untuk konsistensi, Anda juga bisa menggunakan varian itu untuk jawaban ini, yaitu a,b,c,d,e,g,h,i,j = (True for i in range(9)) f=(False i in range(1)),.
Novice C
Ini adalah contoh mengapa saya suka python, Hanya menggunakannya baru-baru ini .. Saya ingin memulai lebih awal .. Tapi pengembangan web bervariasi tergantung pada proyek.
Marah 84
52

Gunakan daftar / kamus atau tentukan kelas Anda sendiri untuk merangkum hal-hal yang Anda tetapkan, tetapi jika Anda membutuhkan semua variabel itu, Anda dapat melakukannya:

a = b = c = d = e = g = h = i = j = True
f = False
yan
sumber
1
vars tidak akan disetel ke True & False saja.
N 1.1
1
@ N1.1: Saya tidak mengerti apa yang Anda maksud dengan itu.
Trufa
@ Trufa Jika mereka disetel ke True / False saja, cara yang disarankan adalah sempurna, tetapi bagaimana jika variabel diatur ke hal-hal yang berbeda?
N 1.1
@ N1.1: Ohh, saya mengerti maksud Anda, terima kasih atas klarifikasi! Dalam hal ini, mereka semua bodoh tetapi itu baik untuk diketahui. Terima kasih
Trufa
5
Untuk penjelasan mengapa ini adalah pola yang berbahaya (walaupun contohnya bekerja), bacalah di Notorious BIG
duozmo
10

Ini adalah penjabaran dari @ Jeff M dan komentar saya.

Ketika Anda melakukan ini:

a, b = c, d

Ini bekerja dengan pengemasan dan pembongkaran tuple. Anda dapat memisahkan langkah-langkah pengemasan dan pembongkaran:

_ = c, d
a, b = _

Baris pertama menciptakan tuple yang disebut _yang memiliki dua elemen, yang pertama dengan nilai cdan yang kedua dengan nilai d. Baris kedua membongkar _tuple ke dalam variabel adan b. Ini memecah satu garis besar Anda:

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True, True, True, True

Ke dalam dua baris yang lebih kecil:

_ = True, True, True, True, True, False, True, True, True, True
a, b, c, d, e, f, g, h, i, j = _

Ini akan memberi Anda hasil yang sama persis seperti baris pertama (termasuk pengecualian yang sama jika Anda menambahkan nilai atau variabel ke satu bagian tetapi lupa untuk memperbarui yang lain). Namun, dalam kasus khusus ini, jawaban yan mungkin adalah yang terbaik.

Jika Anda memiliki daftar nilai, Anda masih dapat membukanya. Anda hanya perlu mengubahnya menjadi tuple terlebih dahulu. Misalnya, berikut ini akan menetapkan nilai antara 0 dan 9 untuk masing-masing amelalui j, masing-masing:

a, b, c, d, e, f, g, h, i, j = tuple(range(10))

EDIT: Trik rapi untuk menetapkan semuanya sebagai true kecuali elemen 5 (variabel f):

a, b, c, d, e, f, g, h, i, j = tuple(x != 5 for x in range(10))
Chris Lutz
sumber
Saya tidak tahu yang terakhir itu mungkin, saya pasti akan mencobanya, itu memang trik yang rapi dan mungkin berguna!
Trufa
5

Ketika orang-orang menyarankan "gunakan daftar atau tuple atau struktur data lainnya", apa yang mereka katakan adalah bahwa, ketika Anda memiliki banyak nilai berbeda yang Anda pedulikan, menamai semuanya secara terpisah sebagai variabel lokal mungkin bukan cara terbaik untuk melakukan sesuatu.

Sebagai gantinya, Anda mungkin ingin mengumpulkan mereka bersama-sama menjadi struktur data yang lebih besar yang dapat disimpan dalam satu variabel lokal.

intuited menunjukkan bagaimana Anda dapat menggunakan kamus untuk ini, dan Chris Lutz menunjukkan bagaimana menggunakan tuple untuk penyimpanan sementara sebelum membongkar ke dalam variabel yang terpisah, tetapi opsi lain untuk dipertimbangkan adalah menggunakan collections.namedtuple untuk menggabungkan nilai-nilai lebih permanen.

Jadi, Anda mungkin melakukan sesuatu seperti:

# Define the attributes of our named tuple
from collections import namedtuple
DataHolder = namedtuple("DataHolder", "a b c d e f g")

# Store our data
data = DataHolder(True, True, True, True, True, False, True)

# Retrieve our data
print(data)
print(data.a, data.f)

Kode asli semoga akan menggunakan nama yang lebih bermakna daripada "DataHolder" dan huruf-huruf alfabet, tentu saja.

ncoghlan
sumber
Terima kasih atas jawaban Anda, saya akan memeriksa ini sebagai opsi, masalahnya adalah ( untuk kasus khusus ini ) mungkin tidak berguna untuk memiliki dan struktur yang tidak berubah. Saya akan berkomentar nanti bagaimana ini terjadi, sekali lagi terima kasih banyak!
Trufa
Anda dapat melakukan hal yang sama dengan kelas biasa - definisi DataHolderhanya mendapat sedikit lebih banyak kata.
ncoghlan
4

Sebenarnya apa masalahnya?

Jika Anda benar-benar membutuhkan atau menginginkan 10 a , b , c , d , e , f , g , h , i , j , tidak akan ada kemungkinan lain, pada suatu waktu atau lain, untuk menulis a dan menulis b dan menulis c . ....

Jika nilainya berbeda, Anda wajib menulis sebagai contoh

a = 12
b= 'sun'
c = A() #(where A is a class)
d = range(1,102,5)
e = (line in filehandler if line.rstrip())
f = 0,12358
g = True
h = random.choice
i = re.compile('^(!=  ab).+?<span>')
j = [78,89,90,0]

artinya mendefinisikan "variabel" secara individual.

Atau, menggunakan tulisan lain, tidak perlu menggunakan _:

a,b,c,d,e,f,g,h,i,j =\
12,'sun',A(),range(1,102,5),\
(line for line in filehandler if line.rstrip()),\
0.12358,True,random.choice,\
re.compile('^(!=  ab).+?<span>'),[78,89,90,0]

atau

a,b,c,d,e,f,g,h,i,j =\
(12,'sun',A(),range(1,102,5),
 (line for line in filehandler if line.rstrip()),
 0.12358,True,random.choice,
 re.compile('^(!=  ab).+?<span>'),[78,89,90,0])

.

Jika beberapa dari mereka harus memiliki nilai yang sama, adalah masalah yang terlalu lama untuk ditulis

a, b, c, d, e, f, g, h, i, j = True, True, True, True, True, False, True ,True , True, True 

?

Maka Anda dapat menulis:

a=b=c=d=e=g=h=i=k=j=True
f = False

.

Saya tidak mengerti apa sebenarnya masalah Anda. Jika Anda ingin menulis kode, Anda wajib menggunakan karakter yang diperlukan oleh penulisan instruksi dan definisi. Apa lagi ?

Saya ingin tahu apakah pertanyaan Anda bukanlah pertanda bahwa Anda salah memahami sesuatu.

Ketika seseorang menulis a = 10, seseorang tidak membuat variabel dalam arti "potongan memori yang nilainya dapat berubah". Instruksi ini:

  • baik memicu penciptaan objek tipe integerdan nilai 10 dan pengikatan nama 'a' dengan objek ini di namespace saat ini

  • atau menetapkan ulang nama 'a' di namespace ke objek 10 (karena 'a' sebelumnya diikat ke objek lain)

Saya mengatakan itu karena saya tidak melihat utilitas untuk mendefinisikan 10 pengidentifikasi a, b, c ... menunjuk ke False or True. Jika nilai-nilai ini tidak berubah selama eksekusi, mengapa 10 pengidentifikasi? Dan jika mereka berubah, mengapa mendefinisikan pengidentifikasi terlebih dahulu?, Mereka akan dibuat saat dibutuhkan jika tidak ditentukan sebelumnya

Pertanyaan Anda tampak aneh bagi saya

eyquem
sumber
2

Sepertinya Anda mendekati masalah Anda dengan cara yang salah dengan saya.

Tulis ulang kode Anda untuk menggunakan tuple atau menulis kelas untuk menyimpan semua data.

richo
sumber
Terima kasih untuk Anda, bisakah Anda mengatakan itu tanpa melihat sekilas kode :) Saya mengerti bahwa ini tidak ideal, dan saya mungkin harus memformat ulang tetapi jawaban Anda tidak benar-benar menyelesaikan pertanyaan. Saya mengerti maksud Anda.
Trufa
1
Saya dapat mengatakan bahwa itu terdengar seperti itu, ya. Seperti apa bunyinya. Refactoring kemungkinan akan menyelesaikan masalah Anda. Masalah Anda adalah masalah gaya, bukan masalah fungsional sehingga sulit untuk menawarkan selain metadvice.
richo
1

Saya suka jawaban terpilih teratas; Namun, ia memiliki masalah dengan daftar seperti yang ditunjukkan.

  >> a, b = ([0]*5,)*2
  >> print b
  [0, 0, 0, 0, 0]
  >> a[0] = 1
  >> print b
  [1, 0, 0, 0, 0]

Ini dibahas dengan sangat terperinci (di sini) , tetapi intinya adalah itu adan bmerupakan objek yang sama dengan a is bpengembalianTrue (sama untuk id(a) == id(b)). Karenanya, jika Anda mengubah indeks, Anda mengubah indeks keduanya adan b, karena keduanya ditautkan. Untuk mengatasi ini Anda dapat melakukan (sumber)

>> a, b = ([0]*5 for i in range(2))
>> print b
[0, 0, 0, 0, 0]
>> a[0] = 1
>> print b
[0, 0, 0, 0, 0]

Ini kemudian dapat digunakan sebagai varian dari jawaban teratas, yang memiliki hasil intuitif "yang diinginkan"

>> a, b, c, d, e, g, h, i = (True for i in range(9))
>> f = (False for i in range(1)) #to be pedantic
Novice C
sumber
1

Dalam kasus Anda, saya akan menggunakan YAML.

Itu adalah standar yang elegan dan profesional untuk berurusan dengan banyak parameter. Nilai-nilai tersebut diambil dari file terpisah. Anda dapat melihat beberapa info di tautan ini:

https://keleshev.com/yaml-quick-introduction

Tetapi lebih mudah untuk Google itu, karena ini adalah standar, ada ratusan info tentang itu, Anda dapat menemukan apa yang paling cocok dengan pemahaman Anda. ;)

Salam Hormat.

Henrique LR
sumber
Hai Henrique, selamat datang di SO, terima kasih atas jawaban Anda! Pastikan untuk membaca tulisan jawaban sebelum menjawab pertanyaan Anda berikutnya!
Diggy.
0

Seperti JavaScript, Anda juga dapat menggunakan banyak pernyataan dalam satu baris dengan pythona = 1; b = "Hello World"; c += 3

Isaac Frost
sumber