Dấu hoa thị trong lệnh gọi hàm


111

Tôi đang sử dụng itertools.chain để "san bằng" danh sách các danh sách theo cách này:

uniqueCrossTabs = list(itertools.chain(*uniqueCrossTabs))

điều này khác với câu nói:

uniqueCrossTabs = list(itertools.chain(uniqueCrossTabs))

8
Hãy xem giải nén danh sách đối số trong tài liệu Python để biết thêm thông tin.
Kai

8
bạn cũng nên kiểm tra **toán tử - nó làm điều tương tự *nhưng với các đối số từ khóa.
Sean Vieira

Câu trả lời:


181

* là toán tử "splat": Nó nhận một danh sách làm đầu vào và mở rộng nó thành các đối số vị trí thực tế trong lệnh gọi hàm.

Vì vậy, nếu uniqueCrossTabs[ [ 1, 2 ], [ 3, 4 ] ], thì itertools.chain(*uniqueCrossTabs)cũng giống như nóiitertools.chain([ 1, 2 ], [ 3, 4 ])

Điều này rõ ràng là khác với việc chỉ đi qua uniqueCrossTabs. Trong trường hợp của bạn, bạn có một danh sách các danh sách mà bạn muốn san bằng; những gì itertools.chain()thực hiện là trả về một trình lặp qua việc nối tất cả các đối số vị trí mà bạn truyền cho nó, trong đó mỗi đối số vị trí có thể lặp lại theo đúng nghĩa của nó.

Nói cách khác, bạn muốn chuyển từng danh sách vào uniqueCrossTabslàm đối số chain(), điều này sẽ chuỗi chúng lại với nhau, nhưng bạn không có danh sách trong các biến riêng biệt, vì vậy bạn sử dụng *toán tử để mở rộng danh sách thành một số đối số danh sách.

Như Jochen Ritzel đã chỉ ra trong các nhận xét, chain.from_iterable()hoạt động này phù hợp hơn với hoạt động này, vì nó giả định bắt đầu có một lần lặp lại các mục lặp. Sau đó, mã của bạn trở nên đơn giản:

uniqueCrossTabs = list(itertools.chain.from_iterable(uniqueCrossTabs))

9
@larsmans: Tôi nghĩ rằng thuật ngữ này phổ biến hơn trong thế giới Ruby, nhưng nó có vẻ được chấp nhận đối với Python, tôi cũng thích nó vì nó rất vui khi nói ;-)
Cameron vào

1
@larsmans: Thật thú vị! Tôi luôn nghĩ rằng nó đề cập đến hành động giải nén danh sách thành một danh sách đối số, không phải bản thân ký tự thực tế.
Cameron

1
Có thể chuỗi không phải là ví dụ tốt nhất vì không phải ai cũng coi chuỗi là chuỗi lặp. Btw: Thay vì chain(*it)tôi sẽ viết chain.from_iterable(it).
Jochen Ritzel

@Jochen: Bạn hoàn toàn đúng, tôi sẽ thay đổi nó để sử dụng số. Ngoài ra, tôi thậm chí không biết from_iterabletồn tại! Tôi sẽ thêm nó vào câu trả lời của tôi trong thời gian ngắn
Cameron

1
@Ramy: *chỉ để giải thích danh sách thành các đối số vị trí cho một hàm (vì vậy có, rất cụ thể). Bạn có thể làm for l in uniqueCrossTabs:để lặp lại chúng. Thật không may, thật khó để xem *tại nơi làm việc vì nó chỉ hoạt động khi bạn chuyển một danh sách cho một hàm (thay vì chuyển danh sách làm tham số đầu tiên, *khiến từng phần tử trong danh sách được truyền dưới dạng một tham số riêng biệt, lần lượt , như thể chúng đã được gõ ra được phân tách bằng dấu phẩy trong danh sách tham số)
Cameron vào

72

Nó chia chuỗi thành các đối số riêng biệt cho lệnh gọi hàm.

>>> def foo(a, b=None, c=None):
...   print a, b, c
... 
>>> foo([1, 2, 3])
[1, 2, 3] None None
>>> foo(*[1, 2, 3])
1 2 3
>>> def bar(*a):
...   print a
... 
>>> bar([1, 2, 3])
([1, 2, 3],)
>>> bar(*[1, 2, 3])
(1, 2, 3)

giải thích khoa học với các ví dụ. +1!
AruniRC

28

Chỉ là một cách thay thế để giải thích khái niệm / sử dụng nó.

import random

def arbitrary():
    return [x for x in range(1, random.randint(3,10))]

a, b, *rest = arbitrary()

# a = 1
# b = 2
# rest = [3,4,5]

3
này là rất quan trọng và không được đề cập ở những nơi khác
Gershom

1
Câu trả lời này không áp dụng cụ thể cho câu hỏi, nhưng là một ứng dụng quan trọng của dấu hoa thị (vì vậy tôi nghĩ là phù hợp với tiêu đề khá "sương mù"). Cùng một mạch, một ứng dụng quan trọng khác nằm trong định nghĩa hàm: def func(a, b, *args):Xem câu trả lời này để biết thêm thông tin.
ASL
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.