Saya mencoba anotasi tipe Python dengan kelas dasar abstrak untuk menulis beberapa antarmuka. Apakah ada cara untuk menjelaskan jenis *args
dan kemungkinan **kwargs
?
Sebagai contoh, bagaimana seseorang menyatakan bahwa argumen yang masuk akal untuk suatu fungsi adalah satu int
atau dua int
? type(args)
memberi Tuple
jadi dugaan saya adalah untuk membubuhi keterangan jenis Union[Tuple[int, int], Tuple[int]]
, tetapi ini tidak berhasil.
from typing import Union, Tuple
def foo(*args: Union[Tuple[int, int], Tuple[int]]):
try:
i, j = args
return i + j
except ValueError:
assert len(args) == 1
i = args[0]
return i
# ok
print(foo((1,)))
print(foo((1, 2)))
# mypy does not like this
print(foo(1))
print(foo(1, 2))
Pesan kesalahan dari mypy:
t.py: note: In function "foo":
t.py:6: error: Unsupported operand types for + ("tuple" and "Union[Tuple[int, int], Tuple[int]]")
t.py: note: At top level:
t.py:12: error: Argument 1 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"
t.py:14: error: Argument 1 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"
t.py:15: error: Argument 1 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"
t.py:15: error: Argument 2 to "foo" has incompatible type "int"; expected "Union[Tuple[int, int], Tuple[int]]"
Masuk akal bahwa mypy tidak menyukai ini untuk pemanggilan fungsi karena ia mengharapkan akan ada tuple
dalam pemanggilan itu sendiri. Tambahan setelah membongkar juga memberikan kesalahan pengetikan yang saya tidak mengerti.
Bagaimana cara menjelaskan jenis yang masuk akal untuk *args
dan **kwargs
?
sumber
Optional
? Apakah ada yang berubah tentang Python atau Anda berubah pikiran? Apakah masih belum sepenuhnya diperlukan karenaNone
default?Optional
penjelasan ketika Anda menggunakanNone
sebagai nilai default membuat usecases tertentu lebih sulit dan yang sekarang sedang dihapus dari PEP.Optional
akan diperlukan di masa depan.Callable
tidak mendukung salah menyebutkan jenis petunjuk untuk*args
atau**kwargs
berhenti penuh . Masalah spesifik tersebut adalah tentang menandai callable yang menerima argumen spesifik ditambah jumlah arbitrer lainnya , dan karenanya menggunakan*args: Any, **kwargs: Any
, tip tipe yang sangat spesifik untuk kedua catch-alls. Untuk kasus di mana Anda mengatur*args
dan / atau**kwargs
untuk sesuatu yang lebih spesifik, Anda dapat menggunakan aProtocol
.Cara yang tepat untuk melakukan ini adalah menggunakan
@overload
Perhatikan bahwa Anda tidak menambahkan
@overload
atau mengetik anotasi pada implementasi aktual, yang harus menjadi yang terakhir.Anda membutuhkan versi yang agak baru dari keduanya
typing
dan mypy untuk mendapatkan dukungan untuk @overload di luar file rintisan .Anda juga dapat menggunakan ini untuk memvariasikan hasil yang dikembalikan dengan cara yang membuat eksplisit jenis argumen yang sesuai dengan jenis kembali. misalnya:
sumber
(type1)
vs(type1, type1)
sebagai contoh saya. Mungkin(type1)
vs(type2, type1)
akan menjadi contoh yang lebih baik dan menunjukkan mengapa saya suka jawaban ini. Ini juga memungkinkan jenis pengembalian yang berbeda. Namun, dalam kasus khusus di mana Anda hanya memiliki satu tipe kembali dan Anda*args
dan*kwargs
semuanya jenis yang sama, teknik dalam jawaban Martin lebih masuk akal sehingga kedua jawaban itu berguna.*args
mana ada jumlah maksimum argumen (2 di sini) masih salah .*args
salah di sini? Jika panggilan yang diharapkan adalah(type1)
vs(type2, type1)
, maka jumlah argumen adalah variabel dan tidak ada standar yang sesuai untuk argumen tambahan. Mengapa penting bahwa ada maks?*args
benar-benar ada untuk nol atau lebih , argumen terbuka, tidak homogen, atau untuk 'melewati ini bersama' tersentuh 'alls-alls. Anda memiliki satu argumen yang diperlukan dan satu opsional. Itu sama sekali berbeda dan biasanya ditangani dengan memberikan argumen kedua nilai default sentinel untuk mendeteksi yang dihilangkan.*args
, jawaban yang lebih baik untuk pertanyaan ini adalah bahwa ini bukanlah sesuatu yang harus dilakukan sama sekali.Sebagai tambahan singkat untuk jawaban sebelumnya, jika Anda mencoba menggunakan mypy pada file Python 2 dan perlu menggunakan komentar untuk menambahkan jenis, bukan anotasi, Anda perlu awalan jenis untuk
args
dankwargs
dengan*
dan**
masing - masing:Ini diperlakukan oleh mypy sebagai sama dengan di bawah ini, versi Python 3.5 dari
foo
:sumber