প্যারামিটারগুলির জন্য **
(ডাবল স্টার) এবং *
(তারা) কী করে
তারা ফাংশনগুলি গ্রহণযোগ্যতা হিসাবে সংজ্ঞায়িত করার জন্য এবং ব্যবহারকারীদের যে কোনও সংখ্যক যুক্তি, অবস্থানগত ( *
) এবং কীওয়ার্ড ( **
) পাস করার জন্য অনুমতি দেয় ।
কার্যকারিতা সংজ্ঞায়িত করা হচ্ছে
*args
যেকোন সংখ্যক alচ্ছিক অবস্থানগত আর্গুমেন্ট (পরামিতি) এর জন্য অনুমতি দেয়, যা নামের একটি টিপলকে অর্পণ করা হবে args
।
**kwargs
যেকোন সংখ্যক arguচ্ছিক কীওয়ার্ড আর্গুমেন্ট (পরামিতি) এর জন্য অনুমতি দেয় যা নামের একটি ডিকটিতে থাকবে kwargs
।
আপনি কোনও উপযুক্ত নাম চয়ন করতে পারেন (এবং হওয়া উচিত), তবে যদি উদ্দেশ্যটি অ-নির্দিষ্ট শব্দার্থ হতে পারে args
এবং kwargs
মানক নাম হয়।
সম্প্রসারণ, যে কোনও সংখ্যক আর্গুমেন্ট পাস করা
এছাড়াও আপনি ব্যবহার করতে পারেন *args
এবং **kwargs
তালিকা (অথবা কোন iterable) এবং dicts (অথবা কোন ম্যাপিং) থেকে পরামিতি মধ্যে পাস করতে যথাক্রমে।
পরামিতিগুলি পুনরুদ্ধার করে ফাংশনটি জানতে হবে না যে সেগুলি প্রসারিত হচ্ছে।
উদাহরণস্বরূপ, পাইথন 2 এর এক্সরেঞ্জ স্পষ্টভাবে প্রত্যাশা করে না *args
, তবে যেহেতু এটি 3 টি পূর্ণসংখ্যার যুক্তি হিসাবে গ্রহণ করে:
>>> x = xrange(3) # create our *args - an iterable of 3 integers
>>> xrange(*x) # expand here
xrange(0, 2, 2)
অন্য উদাহরণ হিসাবে, আমরা এতে ডেক সম্প্রসারণ ব্যবহার করতে পারি str.format
:
>>> foo = 'FOO'
>>> bar = 'BAR'
>>> 'this is foo, {foo} and bar, {bar}'.format(**locals())
'this is foo, FOO and bar, BAR'
পাইথন 3 এ নতুন: কেবলমাত্র মূলশব্দ যুক্তি দিয়ে কার্যকারিতা সংজ্ঞায়িত করা
আপনি থাকতে পারে শুধুমাত্র আর্গুমেন্ট শব্দ পর *args
- উদাহরণস্বরূপ, এখানে, kwarg2
একটি শব্দ আর্গুমেন্ট হিসাবে দেওয়া হবে - positionally না:
def foo(arg, kwarg=None, *args, kwarg2=None, **kwargs):
return arg, kwarg, args, kwarg2, kwargs
ব্যবহার:
>>> foo(1,2,3,4,5,kwarg2='kwarg2', bar='bar', baz='baz')
(1, 2, (3, 4, 5), 'kwarg2', {'bar': 'bar', 'baz': 'baz'})
এছাড়াও, *
সীমাহীন অবস্থানগত আর্গুমেন্টের অনুমতি না দিয়ে কেবল কীওয়ার্ডটি কেবল আর্গুমেন্ট অনুসরণ করে তা বোঝাতে নিজেই ব্যবহার করা যেতে পারে।
def foo(arg, kwarg=None, *, kwarg2=None, **kwargs):
return arg, kwarg, kwarg2, kwargs
এখানে kwarg2
আবার অবশ্যই একটি স্পষ্টরূপে নামকরণ করা উচিত, মূলশব্দ যুক্তি:
>>> foo(1,2,kwarg2='kwarg2', foo='foo', bar='bar')
(1, 2, 'kwarg2', {'foo': 'foo', 'bar': 'bar'})
এবং আমরা আর সীমাহীন অবস্থানগত যুক্তি গ্রহণ করতে পারি না কারণ আমাদের কাছে নেই *args*
:
>>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar='bar')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() takes from 1 to 2 positional arguments
but 5 positional arguments (and 1 keyword-only argument) were given
আবার, আরও সহজভাবে, এখানে আমাদের kwarg
নাম দিয়ে দেওয়া দরকার, অবস্থানগতভাবে নয়:
def bar(*, kwarg=None):
return kwarg
এই উদাহরণে, আমরা দেখতে পাচ্ছি যে আমরা kwarg
অবস্থানগতভাবে পাস করার চেষ্টা করলে আমরা একটি ত্রুটি পাই:
>>> bar('kwarg')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bar() takes 0 positional arguments but 1 was given
আমাদের kwarg
কীওয়ার্ড আর্গুমেন্ট হিসাবে স্পষ্টভাবে প্যারামিটারটি পাস করতে হবে ।
>>> bar(kwarg='kwarg')
'kwarg'
পাইথন 2 সামঞ্জস্যপূর্ণ ডেমো
*args
(সাধারণত "স্টার-আরগস" বলেছিলেন) এবং **kwargs
(তারাগুলি "কাওয়ার্গস" বলে বোঝানো যেতে পারে তবে "ডাবল-স্টার কাওয়ার্গস" দিয়ে স্পষ্ট হওয়া উচিত) পাইথনের সাধারণ পরিচয় *
এবং **
নোটেশনটি ব্যবহার করার জন্য । এই নির্দিষ্ট পরিবর্তনশীল নামগুলির প্রয়োজন নেই (যেমন আপনি ব্যবহার করতে পারেন *foos
এবং **bars
), তবে কনভেনশন থেকে বিদায় নেওয়ার ফলে আপনার সহকর্মী পাইথন কোডারকে ক্রোধ করতে পারে।
আমরা সাধারণত আমাদের এগুলি ব্যবহার করি যখন আমরা জানি না যে আমাদের ফাংশনটি কী পেতে চলেছে বা আমরা কয়টি যুক্তি দিয়ে যাচ্ছি এবং কিছু সময় এমনকি যখন প্রতিটি ভেরিয়েবলের আলাদা আলাদা নামকরণ করা হয় তখন খুব অগোছালো এবং নিষ্প্রয়োজনীয় হয় (তবে এটি এমন একটি ক্ষেত্রে যেখানে সাধারণত স্পষ্ট হয় অন্তর্নিহিত চেয়ে ভাল)।
উদাহরণ 1
নিম্নলিখিত ফাংশনটি কীভাবে সেগুলি ব্যবহার করা যায় তা বর্ণনা করে এবং আচরণ প্রদর্শন করে। নোট b
যুক্তিটি দ্বিতীয় অবস্থানগত আর্গুমেন্ট দ্বারা পূর্বে গ্রাস করা হবে নোট করুন :
def foo(a, b=10, *args, **kwargs):
'''
this function takes required argument a, not required keyword argument b
and any number of unknown positional arguments and keyword arguments after
'''
print('a is a required argument, and its value is {0}'.format(a))
print('b not required, its default value is 10, actual value: {0}'.format(b))
# we can inspect the unknown arguments we were passed:
# - args:
print('args is of type {0} and length {1}'.format(type(args), len(args)))
for arg in args:
print('unknown arg: {0}'.format(arg))
# - kwargs:
print('kwargs is of type {0} and length {1}'.format(type(kwargs),
len(kwargs)))
for kw, arg in kwargs.items():
print('unknown kwarg - kw: {0}, arg: {1}'.format(kw, arg))
# But we don't have to know anything about them
# to pass them to other functions.
print('Args or kwargs can be passed without knowing what they are.')
# max can take two or more positional args: max(a, b, c...)
print('e.g. max(a, b, *args) \n{0}'.format(
max(a, b, *args)))
kweg = 'dict({0})'.format( # named args same as unknown kwargs
', '.join('{k}={v}'.format(k=k, v=v)
for k, v in sorted(kwargs.items())))
print('e.g. dict(**kwargs) (same as {kweg}) returns: \n{0}'.format(
dict(**kwargs), kweg=kweg))
আমরা ফাংশনের স্বাক্ষরের জন্য অনলাইন সহায়তা পরীক্ষা করতে পারবেন সঙ্গে help(foo)
, যা আমাদের বলে
foo(a, b=10, *args, **kwargs)
এর সাথে এই ফাংশন কল করুন foo(1, 2, 3, 4, e=5, f=6, g=7)
যা প্রিন্ট করে:
a is a required argument, and its value is 1
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 2
unknown arg: 3
unknown arg: 4
kwargs is of type <type 'dict'> and length 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: g, arg: 7
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args)
4
e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns:
{'e': 5, 'g': 7, 'f': 6}
উদাহরণ 2
আমরা এটিকে আর একটি ফাংশন ব্যবহার করে কল করতে পারি, যেখানে আমরা কেবল সরবরাহ করি a
:
def bar(a):
b, c, d, e, f = 2, 3, 4, 5, 6
# dumping every local variable into foo as a keyword argument
# by expanding the locals dict:
foo(**locals())
bar(100)
কপি করে প্রিন্ট:
a is a required argument, and its value is 100
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 0
kwargs is of type <type 'dict'> and length 4
unknown kwarg - kw: c, arg: 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: d, arg: 4
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args)
100
e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns:
{'c': 3, 'e': 5, 'd': 4, 'f': 6}
উদাহরণ 3: সাজসজ্জারগুলিতে ব্যবহারিক ব্যবহার
ঠিক আছে, তাই সম্ভবত আমরা ইউটিলিটিটি এখনও দেখছি না। সুতরাং কল্পনা করুন যে আপনার আগে এবং / অথবা ডিফারেনটিটিং কোডের পরে অপ্রয়োজনীয় কোড সহ বেশ কয়েকটি ফাংশন রয়েছে। নিম্নলিখিত নামযুক্ত ফাংশনগুলি চিত্রের উদ্দেশ্যে কেবল ছদ্ম-কোড।
def foo(a, b, c, d=0, e=100):
# imagine this is much more code than a simple function call
preprocess()
differentiating_process_foo(a,b,c,d,e)
# imagine this is much more code than a simple function call
postprocess()
def bar(a, b, c=None, d=0, e=100, f=None):
preprocess()
differentiating_process_bar(a,b,c,d,e,f)
postprocess()
def baz(a, b, c, d, e, f):
... and so on
আমরা এটি অন্যভাবে পরিচালনা করতে সক্ষম হতে পারি, তবে আমরা অবশ্যই একটি ডিকোরেটারের সাহায্যে অতিরিক্ত অর্থ ছাড়তে পারি, এবং সুতরাং আমাদের নীচের উদাহরণটি দেখায় যে কীভাবে *args
এবং **kwargs
খুব কার্যকর হতে পারে:
def decorator(function):
'''function to wrap other functions with a pre- and postprocess'''
@functools.wraps(function) # applies module, name, and docstring to wrapper
def wrapper(*args, **kwargs):
# again, imagine this is complicated, but we only write it once!
preprocess()
function(*args, **kwargs)
postprocess()
return wrapper
এবং এখন প্রতিটি মোড়ানো ফাংশন আরও বেশি সংক্ষিপ্তভাবে লেখা যেতে পারে, যেমন আমরা অযৌক্তিকতাটি প্রকাশ করেছি:
@decorator
def foo(a, b, c, d=0, e=100):
differentiating_process_foo(a,b,c,d,e)
@decorator
def bar(a, b, c=None, d=0, e=100, f=None):
differentiating_process_bar(a,b,c,d,e,f)
@decorator
def baz(a, b, c=None, d=0, e=100, f=None, g=None):
differentiating_process_baz(a,b,c,d,e,f, g)
@decorator
def quux(a, b, c=None, d=0, e=100, f=None, g=None, h=None):
differentiating_process_quux(a,b,c,d,e,f,g,h)
এবং আমাদের কোডটি ফ্যাক্টরিংয়ের মাধ্যমে, যা আমাদের করার অনুমতি দেয় *args
এবং **kwargs
আমরা কোডের লাইনগুলি হ্রাস করি, পাঠযোগ্যতা এবং রক্ষণাবেক্ষণযোগ্যতা উন্নত করি এবং আমাদের প্রোগ্রামে যুক্তির জন্য একমাত্র আধ্যাত্মিক অবস্থানগুলি রাখি। আমাদের যদি এই কাঠামোর কোনও অংশ পরিবর্তন করার প্রয়োজন হয় তবে প্রতিটি পরিবর্তন করার জন্য আমাদের একটি জায়গা রয়েছে।