Đối số bình thường so với đối số từ khóa


289

"Đối số từ khóa" khác với đối số thông thường như thế nào? Không thể tất cả các đối số được thông qua name=valuethay vì sử dụng cú pháp vị trí?


6
Bạn cũng có thể muốn đọc PEP 3102 - họ đang thu dọn một số nội dung này trong Python 3. Xem: python.org/dev/peps/pep-3102
Ben Hoyt

Và có hay không một giá trị mặc định không liên quan gì đến nó (ngoại trừ việc bạn có cần vượt qua một giá trị cho nó hay không), phải không?
mk12


@Ben Hoyt Đã thêm câu trả lời bên dưới bao gồm Python 3, các đối số từ khóa bắt buộc
Barshe Roussy

Câu trả lời:


346

Có hai khái niệm liên quan, cả hai đều được gọi là " đối số từ khóa ".

Về phía gọi, đó là những gì các nhà bình luận khác đã đề cập, bạn có khả năng chỉ định một số đối số chức năng theo tên. Bạn phải đề cập đến chúng sau tất cả các đối số không có tên ( đối số vị trí ) và phải có các giá trị mặc định cho bất kỳ tham số nào không được đề cập ở tất cả.

Khái niệm khác nằm ở phía định nghĩa hàm: bạn có thể định nghĩa một hàm lấy tham số theo tên - và thậm chí bạn không phải chỉ định những tên đó là gì. Đây là các đối số từ khóa thuần túy và không thể được thông qua vị trí. Cú pháp là

def my_function(arg1, arg2, **kwargs)

Bất kỳ đối số từ khóa nào bạn chuyển vào hàm này sẽ được đặt vào một từ điển có tên kwargs. Bạn có thể kiểm tra các khóa của từ điển này vào thời gian chạy, như thế này:

def my_function(**kwargs):
    print str(kwargs)

my_function(a=12, b="abc")

{'a': 12, 'b': 'abc'}

5
+1 và được chấp nhận: Bạn là người duy nhất nói về cả hai loại đối số từ khóa vị trí +, mọi người khác đều nghĩ tôi đang nói về thứ nhất hoặc thứ hai (nhưng chúng vẫn là những bài viết hay). Cảm ơn!
mk12

34
Từ ngữ không rõ ràng: Thông thường bạn nói về các đối số ở phía gọi trong khi các tham số ở phía được gọi.
glglgl

3
Tên tham số phải là kwargshoặc tôi có thể đổi tên thành sth. thích options( def my_fuction(arg1, arg2, **options))?
Bruce Sun

1
Tên có thể là bất cứ điều gì, mặc dù kwargslà quy ước khi không có tên thích hợp hơn
Matt Zimmerman

Tôi nghĩ rằng khái niệm thứ hai được giải thích ở đây về mặt kỹ thuật được gọi là Đối số từ khóa tùy ý.
Anshul Dahiya

188

Có một tính năng ngôn ngữ cuối cùng trong đó sự khác biệt là quan trọng. Hãy xem xét các chức năng sau:

def foo(*positional, **keywords):
    print "Positional:", positional
    print "Keywords:", keywords

Đối *positionalsố sẽ lưu trữ tất cả các đối số vị trí được truyền vào foo(), không giới hạn số lượng bạn có thể cung cấp.

>>> foo('one', 'two', 'three')
Positional: ('one', 'two', 'three')
Keywords: {}

Đối **keywordssố sẽ lưu trữ bất kỳ đối số từ khóa:

>>> foo(a='one', b='two', c='three')
Positional: ()
Keywords: {'a': 'one', 'c': 'three', 'b': 'two'}

Và tất nhiên, bạn có thể sử dụng cả hai cùng một lúc:

>>> foo('one','two',c='three',d='four')
Positional: ('one', 'two')
Keywords: {'c': 'three', 'd': 'four'}

Các tính năng này hiếm khi được sử dụng, nhưng đôi khi chúng rất hữu ích và điều quan trọng là phải biết đối số nào là vị trí hoặc từ khóa.


3
Câu trả lời tuyệt vời! Chỉ cần một lưu ý rằng các đối số vị trí cần thiết có thể được thông qua trước *positional**keywordsnếu chúng ta thay đổi định nghĩa hàm như thế nào def foo(arg1, *positional, **keywords):. Đây arg1là vị trí và bắt buộc. Xin lưu ý rằng vị trí trong câu trả lời có nghĩa là số lượng tùy chọn và số lượng đối số vị trí.
shaffooo

2
Có câu trả lời tốt. Lưu ý khác: Nếu bạn gọi chức năng của bạn foo(bar=True), bạn có thể nhận được các giá trị sử dụng bar = keywords.pop('bar')tương tự như bar = keywords.pop('bar', None). Đối với giá trị mặc định, sử dụngbar = keywords.pop('bar', False)
olibre

111

Sử dụng các đối số từ khóa là điều tương tự như các đối số bình thường ngoại trừ thứ tự không quan trọng. Ví dụ, hai hàm gọi dưới đây giống nhau:

def foo(bar, baz):
    pass

foo(1, 2)
foo(baz=2, bar=1)

3
Cảm ơn vì điều đó. Nó cực kỳ hữu ích khi tôi vừa có thể chỉ định một từ khóa arg là một đối số vị trí, vừa là một đối số vị trí như một đối số từ khóa.
Luke Davis

47

Đối số vị trí

Họ không có từ khóa trước họ. Thứ tự là quan trọng!

func(1,2,3, "foo")

Đối số từ khóa

Họ có từ khóa ở phía trước. Họ có thể theo thứ tự bất kỳ!

func(foo="bar", baz=5, hello=123)

func(baz=5, foo="bar", hello=123)

Bạn cũng nên biết rằng nếu bạn sử dụng các đối số mặc định và bỏ qua việc chèn các từ khóa, thì thứ tự sẽ có vấn đề!

def func(foo=1, baz=2, hello=3): ...
func("bar", 5, 123)

8
IMHO, ví dụ thứ 3 (đối số mặc định) không rõ ràng. Tôi nghĩ rằng bạn đang nói về những gì xảy ra khi một hoặc nhiều tham số khai báo giá trị mặc định và cuộc gọi sử dụng ký hiệu vị trí, nhưng cung cấp LESS hơn số lượng tham số được khai báo. Tuy nhiên, ví dụ của bạn có 3 khai báo và 3 trong cuộc gọi, vì vậy các giá trị mặc định hoàn toàn không có hiệu lực! Bạn có ý định bỏ qua arg thứ 3. ví dụ func("bar", 5)? Và sau đó nói rằng hellonhận được giá trị mặc định của nó 3.
ToolmakerSteve 16/12/13

25

Có hai cách để gán giá trị đối số cho các tham số hàm, cả hai đều được sử dụng.

  1. Theo vị trí. Đối số vị trí không có từ khóa và được chỉ định trước.

  2. Theo từ khóa. Đối số từ khóa có từ khóa và được chỉ định thứ hai, sau đối số vị trí.

Lưu ý rằng bạn có tùy chọn để sử dụng đối số vị trí.

Nếu bạn không sử dụng đối số vị trí, thì - có - mọi thứ bạn viết hóa ra là đối số từ khóa.

Khi bạn gọi một chức năng, bạn đưa ra quyết định sử dụng vị trí hoặc từ khóa hoặc hỗn hợp. Bạn có thể chọn làm tất cả các từ khóa nếu bạn muốn. Một số người trong chúng ta không đưa ra lựa chọn này và sử dụng các đối số vị trí.


1
Ồ, tôi đã nghĩ rằng các tham số, khi những gì nó thực sự là các đối số (những gì tôi vượt qua). Cảm ơn!
mk12

24

Tôi ngạc nhiên rằng dường như không ai chỉ ra rằng người ta có thể vượt qua một từ điển các tham số đối số được khóa, đáp ứng các tham số chính thức, như vậy.

>>> def func(a='a', b='b', c='c', **kwargs):
...    print 'a:%s, b:%s, c:%s' % (a, b, c)
... 
>>> func()
a:a, b:b, c:c
>>> func(**{'a' : 'z', 'b':'q', 'c':'v'})
a:z, b:q, c:v
>>> 

11
+1 cho một kỹ thuật hữu ích. Quan điểm của bạn sẽ rõ ràng hơn, không có , **kwargs. Điều đó sẽ chứng minh rằng ngay cả một func def đơn giản, với một số tham số cố định, có thể được cung cấp một từ điển. Đó là, nó không yêu cầu bất cứ điều gì lạ mắt trong định nghĩa. THÌ bạn có thể thêm một ví dụ thứ hai, VỚI ** kwargs trong định nghĩa và chỉ ra cách các mục EXTRA trong từ điển có sẵn thông qua đó.
ToolmakerSteve 16/12/13

1
Tôi đã thấy điều này xảy ra trong mã nguồn của các thư viện khác nhau và rất bối rối. Cảm ơn đã xóa nó!
Craig Labenz

3
Tham số chính thức thứ tư ở trên - ** kwargs là cần thiết nếu bạn từng gọi func bằng một từ điển có chứa các khóa khác ngoài 'a', 'b' và 'c'.
Eduardo

Đối với tôi print 'a:%s, b:%s, c:%s' % (a, b, c)đưa ra lỗi cú pháp, tuy nhiên print('a:%s, b:%s, c:%s' % (a, b, c))hoạt động. Một cái gì đó với phiên bản Python? Dù sao cũng cảm ơn vì sự sáng suốt này, cho đến bây giờ tôi vẫn đang sử dụng thứ đồ sộ hơnprint('a:{}, b:{}, c:{}'.format(a, b, c))
Axel Bregnsbo

17

Sử dụng Python 3, bạn có thể có cả đối số từ khóa bắt buộc và không bắt buộc :


Tùy chọn : (giá trị mặc định được xác định cho param 'b')

def func1(a, *, b=42):
    ...
func1(value_for_a) # b is optional and will default to 42

Bắt buộc (không có giá trị mặc định được xác định cho param 'b'):

def func2(a, *, b):
    ... 
func2(value_for_a, b=21) # b is set to 21 by the function call
func2(value_for_a) # ERROR: missing 1 required keyword-only argument: 'b'`

Điều này có thể giúp ích trong trường hợp bạn có nhiều đối số tương tự cạnh nhau, đặc biệt nếu chúng cùng loại, trong trường hợp đó tôi thích sử dụng các đối số được đặt tên hoặc tôi tạo một lớp tùy chỉnh nếu các đối số thuộc về nhau.


3
Các biến thể cần thiết là khá hữu ích. Nó thúc giục đưa ra các đối số theo tên mà không cung cấp mặc định, điều này thường không có ý nghĩa.
TNT

Giá trị mặc định trông đẹp và có thể giúp bạn tiết kiệm thời gian khi bạn bắt đầu, nhưng về lâu dài, giá trị mặc định có thể là PITA.
Barshe Roussy

11

Tôi ngạc nhiên không ai đề cập đến thực tế là bạn có thể kết hợp các đối số từ khóa và vị trí để làm những việc lén lút như thế này bằng cách sử dụng *args**kwargs( từ trang web này ):

def test_var_kwargs(farg, **kwargs):
    print "formal arg:", farg
    for key in kwargs:
        print "another keyword arg: %s: %s" % (key, kwargs[key])

Điều này cho phép bạn sử dụng các đối số từ khóa tùy ý có thể có các khóa bạn không muốn xác định trả trước.


0

Tôi đang tìm một ví dụ có kwargs mặc định bằng cách sử dụng chú thích kiểu:

def test_var_kwarg(a: str, b: str='B', c: str='', **kwargs) -> str:
     return ' '.join([a, b, c, str(kwargs)])

thí dụ:

>>> print(test_var_kwarg('A', c='okay'))
A B okay {}
>>> d = {'f': 'F', 'g': 'G'}
>>> print(test_var_kwarg('a', c='c', b='b', **d))
a b c {'f': 'F', 'g': 'G'}
>>> print(test_var_kwarg('a', 'b', 'c'))
a b c {}

0

Chỉ cần bổ sung / thêm một cách để xác định giá trị mặc định của các đối số không được gán trong các từ khóa khi gọi hàm:

def func(**keywargs):
if 'my_word' not in keywargs:
    word = 'default_msg'
else:
    word = keywargs['my_word']
return word

gọi đây là:

print(func())
print(func(my_word='love'))

bạn sẽ nhận được:

default_msg
love

đọc thêm về *args**kwargstrong python: https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-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.