Cách thanh lịch hơn để khai báo nhiều biến cùng một lúc


140

Để khai báo nhiều biến cùng một lúc "tôi sẽ làm:

a, b = True, False

Nhưng nếu tôi phải khai báo nhiều biến hơn, nó sẽ trở nên kém thanh lịch hơn:

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

Có một cách tốt hơn / thanh lịch / thuận tiện để làm điều này?

Điều này phải rất cơ bản, nhưng nếu tôi đã sử dụng một danh sách hoặc một bộ dữ liệu để lưu trữ các biến, tôi sẽ phải tiếp cận như thế nào để tôi có thể hữu ích vì:

aList = [a,b]

Không hợp lệ, tôi sẽ phải làm:

a, b = True, True

Hay tôi còn thiếu gì?


Sử dụng một danh sách để lưu trữ những giá trị đó? Một cuốn từ điển? Một (tên) tuple?
Jeff Mercado

@Chris: Tôi đã đến đó. :)
Jeff Mercado

@JeffM: có thể nhưng tôi không biết làm thế nào mà dường như chúng phải được xác định để thuộc danh sách (dĩ nhiên tôi có thể sai)
Trufa

3
@Trufa: Nếu bạn định khai báo rằng có nhiều biến để lưu trữ giá trị, thì đó đã là một dấu hiệu bạn nên xem xét các phương án lưu trữ khác IMHO.
Jeff Mercado

1
@ user470379 - Tôi giả sử rằng các tên chỉ dành cho mã ví dụ và Trufa không sử dụng các tên đó trong mã thực của mình.
Chris Lutz

Câu trả lời:


52

Như những người khác đã đề xuất, không chắc rằng sử dụng 10 biến cục bộ khác nhau với các giá trị Boolean là cách tốt nhất để viết thói quen của bạn (đặc biệt nếu chúng thực sự có tên một chữ cái :)

Tùy thuộc vào những gì bạn đang làm, có thể có ý nghĩa khi sử dụng từ điển thay thế. Ví dụ: nếu bạn muốn thiết lập các giá trị đặt trước Boolean cho một tập hợp các cờ một chữ cái, bạn có thể làm điều này:

>>> 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}

Nếu bạn thích, bạn cũng có thể làm điều đó với một câu lệnh gán:

>>> 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}

Tham số thứ hai dictkhông hoàn toàn được thiết kế cho việc này: nó thực sự có nghĩa là cho phép bạn ghi đè các thành phần riêng lẻ của từ điển bằng cách sử dụng các đối số từ khóa như d=False. Đoạn mã trên thổi lên kết quả của biểu thức theo sau **thành một tập hợp các đối số từ khóa được truyền cho hàm được gọi. Đây chắc chắn là một cách đáng tin cậy để tạo từ điển và mọi người dường như ít nhất chấp nhận thành ngữ này, nhưng tôi nghi ngờ rằng một số người có thể coi nó là Unpythonic. </disclaimer>


Tuy nhiên, một cách tiếp cận khác, có khả năng trực quan nhất nếu bạn sẽ sử dụng mẫu này thường xuyên, là xác định dữ liệu của bạn dưới dạng danh sách các giá trị cờ ( True, False) được ánh xạ tới tên cờ (chuỗi ký tự đơn). Sau đó, bạn chuyển đổi định nghĩa dữ liệu này thành một từ điển đảo ngược để ánh xạ tên cờ thành giá trị cờ. Điều này có thể được thực hiện khá ngắn gọn với sự hiểu biết danh sách lồng nhau, nhưng đây là một triển khai rất dễ đọc:

>>> 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}

Hàm invert_dictnày là hàm tạo . Nó tạo ra , hoặc mang lại - có nghĩa là nó liên tục trả về các giá trị của - các cặp khóa-giá trị. Các cặp khóa-giá trị này là nghịch đảo của nội dung của hai yếu tố của flagstừ điển ban đầu . Chúng được đưa vào nhà dictxây dựng. Trong trường hợp này, hàm dicttạo hoạt động khác với ở trên vì nó được cung cấp một trình vòng lặp thay vì từ điển làm đối số.


Dựa trên nhận xét của @Chris Lutz: Nếu bạn thực sự sẽ sử dụng điều này cho các giá trị một ký tự, bạn thực sự có thể làm

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

Điều này hoạt động vì các chuỗi Python có thể lặp lại , có nghĩa là chúng có thể được di chuyển qua giá trị theo giá trị. Trong trường hợp của một chuỗi, các giá trị là các ký tự riêng lẻ trong chuỗi. Vì vậy, khi chúng được hiểu là các lần lặp, như trong trường hợp này, chúng đang được sử dụng trong một vòng lặp for ['a', 'b', 'c']'abc'tương đương một cách hiệu quả. Một ví dụ khác là khi chúng được chuyển đến một hàm có thể lặp lại, như thế tuple.

Cá nhân tôi sẽ không làm điều này bởi vì nó không đọc theo trực giác: khi tôi thấy một chuỗi, tôi hy vọng nó sẽ được sử dụng như một giá trị duy nhất chứ không phải là một danh sách. Vì vậy, tôi nhìn vào dòng đầu tiên và nghĩ "Được rồi, vậy có cờ Đúng và cờ Sai". Vì vậy, mặc dù đó là một khả năng, tôi không nghĩ rằng đó là cách để đi. Mặt khác, nó có thể giúp giải thích các khái niệm về iterables và iterators rõ ràng hơn.


Xác định chức năng invert_dictsao cho nó thực sự trả về một từ điển cũng không phải là một ý tưởng tồi; Tôi hầu như không làm điều đó bởi vì nó thực sự không giúp giải thích cách thức hoạt động của thói quen.


Rõ ràng Python 2.7 có khả năng hiểu từ điển, điều này sẽ tạo ra một cách cực kỳ ngắn gọn để thực hiện chức năng đó. Đây là một bài tập cho người đọc, vì tôi chưa cài đặt Python 2.7 :)

Bạn cũng có thể kết hợp một số chức năng từ mô đun itertools đa năng . Như họ nói, có nhiều cách để làm điều đó . Đợi đã, người Python không nói thế. Vâng, dù sao thì nó cũng đúng trong một số trường hợp. Tôi đoán rằng Guido đã cho chúng ta hiểu từ điển để có một cách rõ ràng để làm điều này.


1
Lưu ý rằng ['a', 'b', 'c']có thể rút ngắn thành list('abc'), mà truyền cảm hứng def truth_values(trues, falses): d = dict.from_keys(list(trues), True); d.update(dict.from_keys(list(falses), False)); return dđược sử dụng nhưvalues = truth_values("abc", "de")
Chris Lutz

Cảm ơn bạn rất nhiều, đây có vẻ như là một câu trả lời rất toàn diện, tôi sẽ xem xét kỹ và thử nghiệm những gì bạn văn xuôi, những gì bạn đang nói, trong khi nó có thể đúng, nó sẽ không tự nhiên nên tôi sẽ phải đọc một chút và chơi xung quanh cho đến khi tôi hoàn toàn hiểu ý bạn nói từ khi đó là một trong những điểm yếu của tôi về con trăn. Cảm ơn bạn rất nhiều, tôi sẽ trở lại :)
Trufa

5
@intuited Tôi rất bối rối trước câu trả lời của bạn: bạn xác định một vấn đề khác ngoài vấn đề của OP và bạn rất vui khi thực hiện một câu trả lời dài cho vấn đề khác này. Anh ta không muốn liên kết các chuỗi và các giá trị trong một từ điển, anh ta muốn tạo các đối tượng với một định danh và một giá trị cho mỗi từ.
mắt

5
@eyquem: Câu trả lời dài có tệ không? Thầy thuốc, hãy tự chữa lành!
John Machin

5
Điều này không trả lời câu hỏi, và nó bảo trợ. Xem câu trả lời dưới đây
kodu

225
a, b, c, d, e, g, h, i, j = (True,)*9
f = False

21
@Imray Trailing ký hiệu dấu phẩy (d,)tạo ra một bộ dữ liệu một mục, là một loại trình tự. Các loại trình tự hỗ trợ cộng và nhân, trong số các hoạt động khác.
duozmo

36
Thủ thuật tao nhã, nhưng lưu ý sử dụng điều này trên các yếu tố có thể thay đổi, chẳng hạn như danh sách. Ví dụ a, b, c = ([],)*3không tạo ra 3 trường hợp danh sách nhưng làm cho a, bctrỏ đến cùng một ví dụ.
Zac

5
Tôi tự hỏi nhiều thời gian của tôi tôi lãng phí / chi tiêu cố gắng để làm cho mã trăn của tôi uber pythonic?
SARose

3
@Zac để sử dụng chính xác a, b, c = ([] for i in range(3)). nguồn . Để thống nhất, bạn cũng có thể sử dụng một biến thể của câu trả lời này, nghĩa là , a,b,c,d,e,g,h,i,j = (True for i in range(9)) f=(False i in range(1)).
Novice C

Đây là một ví dụ về lý do tại sao tôi yêu python, Chỉ sử dụng nó gần đây .. Tôi muốn được bắt đầu sớm hơn .. Nhưng phát triển web không thay đổi tùy thuộc vào dự án.
Tức giận 84

52

Sử dụng danh sách / từ điển hoặc xác định lớp của riêng bạn để gói gọn những thứ bạn đang xác định, nhưng nếu bạn cần tất cả các biến đó, bạn có thể làm:

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

1
vars sẽ không được đặt thành True & false.
N 1.1

1
@ N1.1: Tôi không thể hiểu ý của bạn là gì.
Trufa

@Trufa Nếu chúng chỉ được đặt thành Đúng / Sai, cách được đề xuất là hoàn hảo, nhưng nếu các biến được đặt thành những thứ khác nhau thì sao?
N 1.1

@ N1.1: Ohh tôi hiểu ý của bạn, cảm ơn vì đã làm rõ! Trong trường hợp này, tất cả chúng đều là những kẻ ngốc nhưng thật tốt khi biết điều đó. Cảm ơn
Trufa

5
Để được giải thích lý do tại sao đây là một mô hình nguy hiểm (mặc dù ví dụ hoạt động), hãy đọc trên Notorious BIG
duozmo

10

Đây là một chi tiết về @ Jeff M 'và ý kiến ​​của tôi.

Khi bạn làm điều này:

a, b = c, d

Nó hoạt động với đóng gói tuple và giải nén. Bạn có thể tách các bước đóng gói và giải nén:

_ = c, d
a, b = _

Dòng đầu tiên tạo ra một tuple được gọi _có hai phần tử, phần tử đầu tiên có giá trị là cvà phần thứ hai có giá trị là d. Dòng thứ hai giải nén _bộ dữ liệu vào các biến ab. Điều này phá vỡ một dòng lớn của bạn:

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

Thành hai dòng nhỏ hơn:

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

Nó sẽ cung cấp cho bạn kết quả chính xác giống như dòng đầu tiên (bao gồm cùng một ngoại lệ nếu bạn thêm giá trị hoặc biến vào một phần nhưng quên cập nhật phần khác). Tuy nhiên, trong trường hợp cụ thể này, câu trả lời của yan có lẽ là tốt nhất.

Nếu bạn có một danh sách các giá trị, bạn vẫn có thể giải nén chúng. Bạn chỉ cần chuyển đổi nó thành một tuple đầu tiên. Ví dụ: phần sau đây sẽ gán giá trị từ 0 đến 9 cho mỗi athông qua j, tương ứng:

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

EDIT: Thủ thuật gọn gàng để gán tất cả chúng là đúng ngoại trừ phần tử 5 (biến f):

a, b, c, d, e, f, g, h, i, j = tuple(x != 5 for x in range(10))

Tôi không biết cái cuối cùng là có thể, tôi chắc chắn sẽ thử, nó thực sự là một mánh khóe gọn gàng và nó có thể có ích!
Trufa

5

Khi mọi người đề xuất "sử dụng danh sách hoặc bộ dữ liệu hoặc cấu trúc dữ liệu khác", điều họ nói là, khi bạn có nhiều giá trị khác nhau mà bạn quan tâm, đặt tên riêng cho chúng là các biến cục bộ có thể không phải là cách tốt nhất để làm những việc.

Thay vào đó, bạn có thể muốn tập hợp chúng lại với nhau thành một cấu trúc dữ liệu lớn hơn có thể được lưu trữ trong một biến cục bộ duy nhất.

Trực giác chỉ ra cách bạn có thể sử dụng từ điển cho việc này và Chris Lutz đã chỉ cho bạn cách sử dụng bộ dữ liệu để lưu trữ tạm thời trước khi giải nén thành các biến riêng biệt, nhưng một tùy chọn khác cần xem xét là sử dụng collections.namedtupleđể bó các giá trị lâu dài hơn.

Vì vậy, bạn có thể làm một cái gì đó như:

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

Mã thực sự hy vọng sẽ sử dụng tên có ý nghĩa hơn so với "DataHolder" và các chữ cái của bảng chữ cái, tất nhiên.


Cảm ơn câu trả lời của bạn, tôi sẽ kiểm tra xem đây là một tùy chọn, điều này là ( đối với trường hợp cụ thể này ) nó có thể không hữu ích khi có và cấu trúc bất biến. Tôi sẽ bình luận sau về cách này bật ra, một lần nữa cảm ơn nhiều!
Trufa

Bạn có thể làm điều tương tự với một lớp học bình thường - định nghĩa DataHolderchỉ cần dài dòng hơn một chút.
ncoghlan

4

Vấn đề là gì?

Nếu bạn thực sự cần hoặc muốn 10 a , b , c , d , e , f , g , h , i , j , sẽ không có khả năng nào khác, vào lúc này hay lúc khác, để viết a và viết b và viết c . ....

Nếu các giá trị là khác nhau, bạn sẽ có nghĩa vụ phải viết cho mẫu

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]

nghĩa là xác định "các biến" riêng lẻ.

Hoặc, sử dụng cách viết khác, không cần sử dụng _:

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]

hoặc là

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

.

Nếu một vài trong số chúng phải có cùng giá trị, thì vấn đề là quá dài để viết

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

?

Sau đó, bạn có thể viết:

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

.

Tôi không hiểu chính xác vấn đề của bạn là gì. Nếu bạn muốn viết mã, bạn bắt buộc phải sử dụng các ký tự được yêu cầu bằng cách viết các hướng dẫn và định nghĩa. Còn gì nữa không

Tôi tự hỏi nếu câu hỏi của bạn không phải là dấu hiệu cho thấy bạn hiểu sai điều gì đó.

Khi viết a = 10, người ta không tạo ra một biến theo nghĩa "khối bộ nhớ có giá trị có thể thay đổi". Hướng dẫn này:

  • hoặc kích hoạt việc tạo một đối tượng có kiểu integervà giá trị 10 và ràng buộc của tên 'a' với đối tượng này trong không gian tên hiện tại

  • hoặc gán lại tên 'a' trong không gian tên cho đối tượng 10 (vì 'a' trước đó đã được liên kết với một đối tượng khác)

Tôi nói vậy bởi vì tôi không thấy tiện ích để xác định 10 định danh a, b, c ... chỉ vào Sai hoặc Đúng. Nếu các giá trị này không thay đổi trong quá trình thực thi, tại sao 10 định danh? Và nếu chúng thay đổi, tại sao lại xác định mã định danh trước?, Chúng sẽ được tạo khi cần nếu không được xác định trước

Câu hỏi của bạn có vẻ kỳ lạ với tôi


2

Âm thanh như bạn đang tiếp cận vấn đề của bạn sai cách với tôi.

Viết lại mã của bạn để sử dụng một tuple hoặc viết một lớp để lưu trữ tất cả dữ liệu.


Cảm ơn bạn vì bạn có thể nói điều đó mà không cần nhìn thoáng qua mã :) Tôi hiểu rằng điều này không lý tưởng, và tôi có thể phải định dạng lại nhưng câu trả lời của bạn không thực sự giải quyết được câu hỏi. Tôi nhận được quan điểm của bạn mặc dù.
Trufa

1
Tôi có thể nói rằng nó nghe như vậy, vâng. Đó là những gì nó nghe như. Tái cấu trúc sẽ có khả năng giải quyết vấn đề của bạn. Vấn đề của bạn là một vấn đề về phong cách, không phải là vấn đề chức năng, vì vậy thật khó để cung cấp bất cứ điều gì khác ngoài việc khá phức tạp.
richo

1

Tôi thích câu trả lời bình chọn hàng đầu; tuy nhiên, nó có vấn đề với danh sách như được hiển thị.

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

Điều này được thảo luận rất chi tiết (ở đây) , nhưng ý chính là ablà cùng một đối tượng với a is btrả về True(tương tự cho id(a) == id(b)). Do đó, nếu bạn thay đổi một chỉ mục, bạn đang thay đổi chỉ mục của cả hai ab, vì chúng được liên kết. Để giải quyết điều này bạn có thể làm (nguồn)

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

Điều này sau đó có thể được sử dụng như một biến thể của câu trả lời hàng đầu, có kết quả trực quan "mong muốn"

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

1

Trong trường hợp của bạn, tôi sẽ sử dụng YAML.

Đó là một tiêu chuẩn thanh lịch và chuyên nghiệp để xử lý nhiều tham số. Các giá trị được tải từ một tệp riêng biệt. Bạn có thể thấy một số thông tin trong liên kết này:

https://keleshev.com/yaml-quick-int sinhtion

Nhưng nó dễ dàng hơn cho Google, vì nó là một tiêu chuẩn, có hàng trăm thông tin về nó, bạn có thể tìm thấy những gì phù hợp nhất với sự hiểu biết của bạn. ;)

Trân trọng.


Xin chào Henrique, chào mừng bạn đến với SO, cảm ơn bạn đã trả lời! Hãy chắc chắn đọc lên để viết một câu trả lời trước khi trả lời câu hỏi tiếp theo của bạn!
Đào.

0

Giống như JavaScript, bạn cũng có thể sử dụng nhiều câu lệnh trên một dòng trong pythona = 1; b = "Hello World"; c += 3

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.