Dấu hoa thị trong các đối số chức năng?


240

Dấu hoa thị trần trong các đối số của hàm làm gì?

Khi tôi nhìn vào mô-đun dưa chua , tôi thấy điều này:

pickle.dump(obj, file, protocol=None, *, fix_imports=True)

Tôi biết về một dấu sao đơn và kép trước các đối số (đối với số lượng đối số thay đổi), nhưng điều này không có gì trước. Và tôi khá chắc chắn rằng điều này không liên quan gì đến dưa chua. Đó có lẽ chỉ là một ví dụ về điều này xảy ra. Tôi chỉ biết tên của nó khi tôi gửi nó cho người phiên dịch:

>>> def func(*):
...     pass
...
  File "<stdin>", line 1
SyntaxError: named arguments must follow bare *

Nếu có vấn đề, tôi đang dùng python 3.3.0.


Câu trả lời:


220

Bare *được sử dụng để buộc người gọi sử dụng các đối số được đặt tên - vì vậy bạn không thể xác định hàm với* tư cách là một đối số khi bạn không có đối số từ khóa sau.

Xem câu trả lời này hoặc tài liệu Python 3 để biết thêm chi tiết.


3
Lưu ý rằng tất cả các đối số vị trí (không tên), bao gồm *args, phải xảy ra trước khi trần *.
BallpointBen

4
Cũng lưu ý rằng có một loại đối tác, /, đánh dấu sự kết thúc của các đối số chỉ theo vị trí ( stackoverflow.com/questions/28243832/ trộm ).
Stephen

2
@BallpointBen: *thay thế *argsvà ngược lại; chúng không thể cùng tồn tại trong một chữ ký. Đó là lý do họ chọn *; trước đây, *argslà cách duy nhất để buộc các đối số hoàn toàn theo vị trí và nó đánh dấu sự kết thúc của các đối số có thể được truyền theo vị trí (vì nó thu thập tất cả các đối số vị trí còn lại, chúng có thể đạt được các đối số được đặt tên sau). *có nghĩa là cùng một "đối số vị trí không thể vượt ra khỏi đây", nhưng thiếu tên có nghĩa là "nhưng tôi sẽ không chấp nhận chúng, bởi vì tôi đã chọn không cung cấp một nơi để đặt chúng".
ShadowRanger

70

Trong khi câu trả lời ban đầu trả lời hoàn toàn câu hỏi, chỉ cần thêm một chút thông tin liên quan. Các hành vi cho dấu hoa thị duy nhất xuất phát từ PEP-3102. Trích dẫn phần liên quan:

The second syntactical change is to allow the argument name to
be omitted for a varargs argument. The meaning of this is to
allow for keyword-only arguments for functions that would not
otherwise take a varargs argument:

    def compare(a, b, *, key=None):
        ...

Trong tiếng Anh đơn giản, điều đó có nghĩa là để truyền giá trị cho khóa, bạn sẽ cần phải vượt qua nó một cách rõ ràng key="value".


Oh, điều đó làm cho mọi thứ rõ ràng hơn nhiều. Vì vậy, thực sự có một đối số * cũng giống như có một đối số tranh luận *, nhưng vì bạn không đặt tên cho nó bất cứ điều gì, nên tác dụng duy nhất của nó là có thể lặng lẽ nuốt chửng tất cả các đối số vị trí còn lại, để buộc các đối số còn lại là từ khóa -chỉ có.
Stephen

11
@Stephen Tôi cũng nghĩ ban đầu, tác dụng của trần *là để ngấu nghiến những lý lẽ vị trí còn lại, nhưng đó không phải là trường hợp. Vượt qua các đối số vị trí bổ sung hơn hàm mong đợi, sẽ xảy ra lỗi loại này:foo() takes exactly 1 positional argument (2 given)
Ajay M

18
def func(*, a, b):
    print(a)
    print(b)

func("gg") # TypeError: func() takes 0 positional arguments but 1 was given
func(a="gg") # TypeError: func() missing 1 required keyword-only argument: 'b'
func(a="aa", b="bb", c="cc") # TypeError: func() got an unexpected keyword argument 'c'
func(a="aa", b="bb", "cc") # SyntaxError: positional argument follows keyword argument
func(a="aa", b="bb") # aa, bb

ví dụ trên với ** kwargs

def func(*, a, b, **kwargs):
    print(a)
    print(b)
    print(kwargs)

func(a="aa",b="bb", c="cc") # aa, bb, {'c': 'cc'}

5

Về mặt ngữ nghĩa, nó có nghĩa là các đối số theo sau nó chỉ là từ khóa, vì vậy bạn sẽ gặp lỗi nếu bạn cố gắng cung cấp một đối số mà không chỉ định tên của nó. Ví dụ:

>>> def f(a, *, b):
...     return a + b
...
>>> f(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 2 were given
>>> f(1, b=2)
3

Thực tế, nó có nghĩa là bạn phải gọi hàm bằng một đối số từ khóa. Nó thường được thực hiện khi khó có thể hiểu được mục đích của đối số mà không có gợi ý được đưa ra bởi tên của đối số.

So sánh ví dụ sorted(nums, reverse=True)so với nếu bạn đã viết sorted(nums, True). Cái sau sẽ dễ đọc hơn nhiều, vì vậy các nhà phát triển Python đã chọn làm cho bạn viết nó theo cách trước đây.


4

Giả sử bạn có chức năng:

def sum(a,key=5):
    return a + key 

Bạn có thể gọi hàm này theo 2 cách:

sum(1,2) hoặc là sum(1,key=2)

Giả sử bạn muốn chức năng sum chỉ được gọi bằng cách sử dụng đối số từ khóa.

Bạn thêm * vào danh sách tham số hàm để đánh dấu kết thúc của các đối số vị trí.

Vì vậy, hàm được định nghĩa là:

def sum(a,*,key=5):
    return a + key 

có thể được gọi chỉ bằng cách sử dụng sum(1,key=2)


-1

Tôi đã tìm thấy đường dẫn sau để thể rất hữu ích để giải thích *, *args**kwargs:

https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/

Về cơ bản, ngoài các câu trả lời ở trên, tôi đã học được từ trang web trên (tín dụng: https://pythontips.com/author/yasoob008/ ) như sau:

Với chức năng trình diễn được xác định đầu tiên bên dưới, có hai ví dụ, một với *argsvà một với**kwargs

def test_args_kwargs(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

# first with *args
>>> args = ("two", 3,5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5

# now with **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two","arg1":5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3

Vì vậy, *argscho phép bạn tự động xây dựng một danh sách các đối số sẽ được thực hiện theo thứ tự mà chúng được cho ăn, trong khi đó**kwargs có thể cho phép truyền các đối số NAMED và có thể được xử lý bởi NAME (không phân biệt thứ tự chúng được cung cấp) .

Trang web tiếp tục, lưu ý rằng thứ tự chính xác của các đối số phải là:

some_func(fargs,*args,**kwargs)

2
Câu trả lời này gần như không có gì để làm với câu hỏi. Nó thậm chí còn sử dụng một phiên bản python lỗi thời không có tính năng này.
Antti Haapala
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.