[] và {} so với list () và dict (), cái nào tốt hơn?


113

Tôi hiểu rằng cả hai về cơ bản đều giống nhau, nhưng về phong cách, cái nào tốt hơn (nhiều Pythonic hơn) để sử dụng để tạo một danh sách trống hoặc dict?

Câu trả lời:


197

Về tốc độ, nó không phải là đối thủ cho các danh sách / khu vực trống:

>>> from timeit import timeit
>>> timeit("[]")
0.040084982867934334
>>> timeit("list()")
0.17704233359267718
>>> timeit("{}")
0.033620194745424214
>>> timeit("dict()")
0.1821558326547077

và không trống:

>>> timeit("[1,2,3]")
0.24316302770330367
>>> timeit("list((1,2,3))")
0.44744206316727286
>>> timeit("list(foo)", setup="foo=(1,2,3)")
0.446036018543964
>>> timeit("{'a':1, 'b':2, 'c':3}")
0.20868602015059423
>>> timeit("dict(a=1, b=2, c=3)")
0.47635635255323905
>>> timeit("dict(bar)", setup="bar=[('a', 1), ('b', 2), ('c', 3)]")
0.9028228448029267

Ngoài ra, việc sử dụng ký hiệu trong ngoặc cho phép bạn sử dụng danh sách và khả năng hiểu từ điển, điều này có thể đủ lý do.


4
Đọc hiểu chính tả và liệt kê cũng có thể được thực hiện bằng cách sử dụng tên tiếng Anh. Ví dụ:list(i for i in range(10) if i % 2)
Zags

4
có lý do gì khiến {} và [] nhanh hơn nhiều không? Tôi nghĩ họ chỉ đơn giản là bí danh.
Justin D.

Thời gian dường như không cung cấp thời gian chính xác. Theo điểm chuẩn, có vẻ như mất ~ 200ms, chậm hơn so với các cuộc gọi http bình thường. Hãy thử chạy dict () bình thường trong shell và sau đó chạy timeit ("dict ()"), bạn sẽ thấy sự khác biệt rõ ràng trong quá trình thực thi.
piyush

2
@piyush Trên thực tế, timeit()hàm báo cáo tổng thời gian để thực hiện một số lần lặp được chỉ định, 1000000theo mặc định. Vì vậy, các ví dụ trên là số giây để chạy đoạn mã một triệu lần. Ví dụ: timeit('dict()', number=1) // -> 4.0531158447265625e-06(một lần lặp) trong khi timeit('dict()') // -> 0.12412905693054199(một triệu lần lặp)
Greg Haskins

@GregHaskins vì vậy trong trường hợp đó, tôi không thấy ai nên lo lắng về việc sử dụng dict () hoặc {}, trừ khi lặp qua một triệu bản ghi và sử dụng dict () trong vòng lặp.
piyush

37

Theo ý kiến ​​của tôi []{}đây là cách dễ đọc và hấp dẫn nhất để tạo danh sách / phân số trống.

Hãy cảnh giác với set()'s, ví dụ:

this_set = {5}
some_other_set = {}

Có thể gây nhầm lẫn. Đầu tiên tạo một tập hợp với một phần tử, thứ hai tạo một dict rỗng chứ không phải một tập hợp.


4
{}luôn tạo ra một mệnh đề trống. {1,2,3}tạo một tập hợp trong 2.7+ nhưng là lỗi cú pháp trong 2.6và các phiên bản cũ hơn.
ThiefMaster

1
lấy làm tiếc? đó là một biến có tên some_epic_settrỏ đến một dictđối tượng rỗng ... nó không phải là một tập hợp rỗng. Đối với một bộ trống bạn cần sử dụng set().
6502

2
@ 6502: Thật vậy, nhưng đó là một cạm bẫy phổ biến {5}tạo ra một tập hợp có một phần tử 5{}là một mệnh đề trống.
orlp

1
Wow, thật khó hiểu. Tuy nhiên, nó không phải là mức độ khó hiểu của Fractal of Bad Design. :-)
Giáo sư Falken

4
@EnderLook: Trên thực tế, với việc giải nén tổng quát , bạn có thể sử dụng {*()}để tạo trống setvới cú pháp theo nghĩa đen. Tôi gọi nó là nhà điều hành khỉ một mắt. :-)
ShadowRanger

17

Các đen dict có thể là một nhỏ chút nhanh hơn như bytecode của nó là ngắn hơn:

In [1]: import dis
In [2]: a = lambda: {}
In [3]: b = lambda: dict()

In [4]: dis.dis(a)
  1           0 BUILD_MAP                0
              3 RETURN_VALUE

In [5]: dis.dis(b)
  1           0 LOAD_GLOBAL              0 (dict)
              3 CALL_FUNCTION            0
              6 RETURN_VALUE

Tương tự áp dụng cho listvs[]


8
Điều này giả định rằng BUILD_MAP và LOAD_GLOBAL là thời gian không đổi và mất cùng một khoảng thời gian. Bất thường. thời gian đưa ra ước tính tốt hơn nhiều.
Jamie Pate

Nhiều khả năng, CALL_FUNCTIONcần ít nhất nhiều thời gian như BUILD_MAP(chức năng được gọi về cơ bản là như vậy BUILD_MAP) và LOAD_GLOBALmất chỉ là chi phí bổ sung.
chepner

3

IMHO, sử dụng list()dict()làm cho Python của bạn trông giống như C. Ugh.


3

Trong trường hợp khác biệt giữa [] và list (), có một cạm bẫy mà tôi chưa thấy ai khác chỉ ra. Nếu bạn sử dụng từ điển làm thành viên của danh sách, cả hai sẽ cho kết quả hoàn toàn khác nhau:

In [1]: foo_dict = {"1":"foo", "2":"bar"}

In [2]: [foo_dict]
Out [2]: [{'1': 'foo', '2': 'bar'}]

In [3]: list(foo_dict)
Out [3]: ['1', '2'] 

Bạn có thể nhận được kết quả tương tự như [foo_dict]bằng cách sử dụng list((foo_dict,)). Các list()phương pháp có một iterable như nó chỉ tham số và lặp trên nó để thêm các yếu tố vào danh sách. Điều này sẽ gây ra một cạm bẫy tương tự bằng cách làm điều list(some_list)đó sẽ làm phẳng danh sách.
sotrh

1

list () và [] hoạt động khác nhau:

>>> def a(p=None):
...     print(id(p))
... 
>>> for r in range(3):
...     a([])
... 
139969725291904
139969725291904
139969725291904
>>> for r in range(3):
...     a(list())
... 
139969725367296
139969725367552
139969725367616

list () luôn tạo đối tượng mới trong heap, nhưng [] có thể sử dụng lại ô nhớ vì nhiều lý do.


0

có một sự khác biệt về hành vi giữa [] và list () như ví dụ dưới đây cho thấy. chúng ta cần sử dụng list () nếu chúng ta muốn có danh sách các số được trả về, nếu không chúng ta nhận được một đối tượng bản đồ! Không chắc chắn làm thế nào để giải thích nó mặc dù.

sth = [(1,2), (3,4),(5,6)]
sth2 = map(lambda x: x[1], sth) 
print(sth2) # print returns object <map object at 0x000001AB34C1D9B0>

sth2 = [map(lambda x: x[1], sth)]
print(sth2) # print returns object <map object at 0x000001AB34C1D9B0>
type(sth2) # list 
type(sth2[0]) # map

sth2 = list(map(lambda x: x[1], sth))
print(sth2) #[2, 4, 6]
type(sth2) # list
type(sth2[0]) # int

đây dường như là giải thích về hành vi bằng cách sử dụng ví dụ về hàm range () >>> print (range (10)) # range (0, 10) range () hoạt động giống như một danh sách, nhưng nó không phải là một danh sách. Nó là một đối tượng trả về các mục liên tiếp của một chuỗi khi bạn lặp lại nó, nó không thực sự tạo danh sách, tiết kiệm không gian. một đối tượng như vậy có thể lặp lại, nghĩa là, thích hợp làm mục tiêu cho các hàm và cấu trúc mong đợi thứ gì đó mà từ đó chúng có thể có được các mục liên tiếp cho đến khi nguồn cung cấp cạn kiệt. Hàm list () tạo danh sách từ các tệp lặp: >>> list (range (5)) # [0, 1, 2, 3, 4]
sebtac

1
hậu quả là [] lưu trữ đối tượng có thể lặp lại; list () tạo danh sách từ cùng một danh sách có thể lặp lại
sebtac

0

Cặp dấu ngoặc vuông biểu thị một trong các đối tượng danh sách hoặc một chỉ số con của chỉ mục, my_List [x].

Một cặp ngoặc nhọn biểu thị một đối tượng từ điển.

a_list = ['bật', 'tắt', 1, 2]

a_dict = {on: 1, off: 2}


-5

Nó chủ yếu là vấn đề lựa chọn trong hầu hết thời gian. Đó là một vấn đề của sở thích.

Tuy nhiên, lưu ý rằng nếu bạn có các phím số, ví dụ như bạn không thể thực hiện:

mydict = dict(1="foo", 2="bar")

Bạn phải làm:

mydict = {"1":"foo", "2":"bar"}

7
Điều này là sai ... bạn cần phải làm mydict = {1:"foo", 2:"bar"}(không có dấu ngoặc kép cho các phím).
6502

8
Nó không chỉ đơn giản là "sai". Các khóa là chuỗi / int tùy thuộc vào việc bạn có trích dẫn chúng hay không.
ThiefMaster
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.