* আরগস এবং ** কোয়ার্গের জন্য টীকা লিখুন


158

আমি কিছু ইন্টারফেস লিখতে অ্যাবস্ট্রাক্ট বেস ক্লাসগুলির সাথে পাইথনের ধরণের টীকাগুলি চেষ্টা করে দেখছি। এর সম্ভাব্য প্রকারগুলি *argsএবং এর জন্য কোনও উপায় আছে কি **kwargs?

উদাহরণস্বরূপ, কিভাবে প্রকাশ করবে একটি ফাংশন বুদ্ধিমানের আর্গুমেন্ট পারেন একটি হয় intবা দুই intগুলি? type(args)দেয় Tupleতাই আমার অনুমানটি প্রকারটি বর্ণনা করা ছিল Union[Tuple[int, int], Tuple[int]]তবে এটি কার্যকর হয় না।

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))

মাইপি থেকে ত্রুটি বার্তা:

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]]"

এটি বুঝায় যে মাইপি ফাংশন কলটির জন্য এটি পছন্দ করে না কারণ এটি tupleকলটি নিজেই একটি হবে বলে আশা করে। আনপ্যাক করার পরে সংযোজন একটি টাইপিং ত্রুটি দেয় যা আমি বুঝতে পারি না।

কেউ কীভাবে *argsএবং এর জন্য বোধগম্য প্রকারগুলি বর্ণনা করে **kwargs?

উত্তর:


167

পরিবর্তনশীল অবস্থানগত আর্গুমেন্টগুলি (জন্য *args) এবং পরিবর্তনশীল শব্দ আর্গুমেন্টগুলি ( **kw) আপনি শুধুমাত্র প্রত্যাশিত মান নির্দিষ্ট করতে হবে এক ধরনের যুক্তি।

স্বেচ্ছাসেবী আর্গুমেন্ট তালিকা এবং টাইপ ইঙ্গিত পিইপি এর ডিফল্ট আর্গুমেন্ট মান বিভাগ থেকে :

স্বেচ্ছাসেবী যুক্তির তালিকাগুলি পাশাপাশি টাইপযুক্ত টীকায়িত হতে পারে, যাতে সংজ্ঞা:

def foo(*args: str, **kwds: int): ...

গ্রহণযোগ্য এবং এর অর্থ হ'ল, নীচের সমস্তগুলি বৈধ ধরণের যুক্তি সহ ফাংশন কলগুলি উপস্থাপন করে:

foo('a', 'b', 'c')
foo(x=1, y=2)
foo('', z=0)

সুতরাং আপনি আপনার পদ্ধতিটি এভাবে নির্দিষ্ট করতে চান:

def foo(*args: int):

তবে, যদি আপনার ফাংশনটি কেবল দুটি বা দুটি পূর্ণসংখ্যার মান গ্রহণ করতে পারে তবে আপনার মোটেও ব্যবহার *argsকরা উচিত নয় , একটি স্পষ্ট অবস্থানগত আর্গুমেন্ট এবং দ্বিতীয় কীওয়ার্ড আর্গুমেন্ট ব্যবহার করা উচিত:

def foo(first: int, second: Optional[int] = None):

এখন আপনার ফাংশনটি আসলে এক বা দুটি যুক্তির মধ্যে সীমাবদ্ধ এবং নির্দিষ্ট করা থাকলে উভয়ই পূর্ণসংখ্যা হতে হবে। *args সর্বদা মানে 0 বা তার বেশি, এবং আরও নির্দিষ্ট সীমাতে টাইপ ইঙ্গিত দ্বারা সীমাবদ্ধ করা যায় না।


1
শুধু কৌতূহলী, কেন যোগ Optional? পাইথন সম্পর্কে কিছু পরিবর্তন হয়েছে বা আপনি নিজের মতামত পরিবর্তন করেছেন? এটি এখনও Noneডিফল্ট কারণে কঠোরভাবে প্রয়োজন হয় না ?
প্রক্সিওলিটিক

10
@ প্রেক্সিওলিটিক হ্যাঁ, আপনি Optionalযখন Noneডিফল্ট মান হিসাবে নির্দিষ্ট ইউজকেসকে আরও শক্ত করে তুলেন তখন ব্যবহারের সময় স্বয়ংক্রিয়ভাবে, উল্লিখিত টীকাগুলি কার্যকর হয় এবং এটি এখন পিইপি থেকে সরানো হচ্ছে।
মার্টিজন পিটারস

5
আগ্রহীদের জন্য এটি আলোচনা করার জন্য এখানে একটি লিঙ্ক দেওয়া হল । এটি অবশ্যই Optionalভবিষ্যতের মতো স্পষ্টরূপের মতো প্রয়োজনীয় হবে sound
রিক মনিকা 22

এটি প্রকৃতপক্ষে কল করার পক্ষে সমর্থিত নয়: github.com/python/mypy/issues/5876
শীতল শাহ

1
@ শীতলশাহ: সমস্যাটি আসলে এটিই নয়। Callableকোনও প্রকার ইঙ্গিত বা সম্পূর্ণ স্টপের কোনও উল্লেখকে সমর্থন করে না । সেই সুনির্দিষ্ট সমস্যাটি কলযোগ্যদের চিহ্নিত করার বিষয়ে যা নির্দিষ্ট আর্গুমেন্ট এবং অন্যের একটি স্বেচ্ছাসেবী সংখ্যাকে গ্রহণ করে এবং তাই দুটি ক্যাচ-অলসের জন্য খুব নির্দিষ্ট ধরণের ইঙ্গিতটি ব্যবহার করে। যে ক্ষেত্রে আপনি সেট করেছেন এবং / অথবা আরও নির্দিষ্ট কিছু নির্দিষ্ট করতে আপনি এ ব্যবহার করতে পারেন । *args**kwargs *args: Any, **kwargs: Any*args**kwargsProtocol
Martijn Pieters

26

এটি করার সঠিক উপায়টি হ'ল ব্যবহার করা @overload

from typing import overload

@overload
def foo(arg1: int, arg2: int) -> int:
    ...

@overload
def foo(arg: int) -> int:
    ...

def foo(*args):
    try:
        i, j = args
        return i + j
    except ValueError:
        assert len(args) == 1
        i = args[0]
        return i

print(foo(1))
print(foo(1, 2))

নোট করুন যে আপনি @overloadপ্রকৃত বাস্তবায়নে টীকা যুক্ত বা টাইপ করেন না , যা অবশ্যই শেষের দিকে আসতে হবে।

স্টাব ফাইলের বাইরেtyping @ ওভারলোডের জন্য সমর্থন পেতে আপনার এবং মাইপি উভয়ের একটি নতুন সংস্করণ প্রয়োজন ।

প্রত্যাশিত ফলাফলের পরিবর্তনের জন্য আপনি এটিও ব্যবহার করতে পারেন যা সুস্পষ্ট করে তোলে কোন যুক্তির প্রকারটি কোন রিটার্নের সাথে সম্পর্কিত। উদাহরণ:

from typing import Tuple, overload

@overload
def foo(arg1: int, arg2: int) -> Tuple[int, int]:
    ...

@overload
def foo(arg: int) -> int:
    ...

def foo(*args):
    try:
        i, j = args
        return j, i
    except ValueError:
        assert len(args) == 1
        i = args[0]
        return i

print(foo(1))
print(foo(1, 2))

2
আমি এই উত্তরটি পছন্দ করি কারণ এটি আরও সাধারণ ক্ষেত্রে সম্বোধন করে। পিছনে ফিরে তাকানো, আমার উদাহরণ হিসাবে (type1)বনাম (type1, type1)ফাংশন কলগুলি ব্যবহার করা উচিত নয় । সম্ভবত (type1)বনাম (type2, type1)একটি আরও ভাল উদাহরণ হতে পারে এবং আমি কেন এই উত্তরটি পছন্দ করি তা দেখায়। এটি পৃথক পৃথক রিটার্নেরও অনুমতি দেয়। তবে, বিশেষ ক্ষেত্রে যেখানে আপনার কেবলমাত্র একটি রিটার্ন টাইপ রয়েছে এবং আপনার *argsএবং *kwargsসমস্ত একই ধরণের, মার্টজিনের উত্তরের কৌশলটি আরও বোধগম্য হয় তাই উভয় উত্তর কার্যকর।
প্রক্সিওলিটিক

4
*argsসর্বাধিক সংখ্যক যুক্তি (2 টি এখানে) রয়েছে যেখানে ব্যবহার করা এখনও ভুল
মার্টিজান পিটারস

1
@ মার্তিজজনপিটার্স *argsএখানে কেন প্রয়োজনীয়ভাবে ভুল হয়? যদি প্রত্যাশিত কলগুলি (type1)বনাম হয় (type2, type1), তবে আর্গুমেন্টগুলির সংখ্যা পরিবর্তনশীল এবং পিছনের যুক্তির জন্য উপযুক্ত ডিফল্ট নেই। সর্বাধিক আছে কেন এটি গুরুত্বপূর্ণ?
প্রেক্সিওলিটিক

1
*argsশূন্য বা আরও বেশি , অনাবৃত, একজাতীয় যুক্তি বা 'এগুলি অচ্ছুত হয়ে যাওয়ার জন্য' ক্যাচ-অলসের জন্য সত্যিই আছে । আপনার একটি প্রয়োজন যুক্তি এবং একটি oneচ্ছিক। এটি সম্পূর্ণ আলাদা এবং দ্বিতীয়টি যুক্তিটি বাদ দেওয়া হয়েছে তা সনাক্ত করার জন্য একটি সেন্ডিনেল ডিফল্ট মান দিয়ে সাধারণত পরিচালনা করা হয়।
মার্টিজন পিটারস

3
পিইপি দেখার পরে, এটি পরিষ্কারভাবে @ ওভারলোডের ব্যবহারের উদ্দেশ্য নয়। যদিও এই উত্তরটি পৃথকভাবে প্রকারের ধরণের বর্ণনা দেওয়ার একটি আকর্ষণীয় উপায় দেখায় *args, প্রশ্নের আরও উত্তম উত্তর হ'ল এটি এমন কিছু নয় যা কিছু করা উচিত।
প্রক্সিওলিটিক

20

পূর্ববর্তী উত্তর একটি সংক্ষিপ্ত উপরন্তু হিসাবে, আপনি mypy টীকা পরিবর্তে ধরনের যোগ করার জন্য ব্যবহার মন্তব্যের 2 ফাইল এবং প্রয়োজন পাইথন ব্যবহার করতে চেষ্টা করছেন তবে আপনার জন্য ধরনের প্রিফিক্স প্রয়োজন argsএবং kwargsসঙ্গে *এবং **যথাক্রমে:

def foo(param, *args, **kwargs):
    # type: (bool, *str, **int) -> None
    pass

এটি মাইপি দ্বারা নীচের মতটি হিসাবে পাইথন 3.5 সংস্করণ হিসাবে গণ্য করা হয় foo:

def foo(param: bool, *args: str, **kwargs: int) -> None:
    pass
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.