للاطلاع على الأساسيات حول وسائط الدوال، راجع مفهوم الدوال.
أسماء المعاملات، مثل أسماء المتغيرات، يجب أن تبدأ بحرف أو بشرطة سفلية، ويمكن أن تحتوي على حروف أو شرطات سفلية أو أرقام. ويجب ألا تحتوي أسماء المعاملات على مسافات أو علامات ترقيم.
الوسائط الموضعية هي قيم تُمرَّر إلى دالة بالترتيب نفسه الذي ترتبط به المعاملات. ويمكن اختياريًا تمرير الوسائط الموضعية باستخدام اسم المعامل الخاص بها:
def concat(greeting, name):
return f"{greeting}{name}"
# Passing data to the function by position.
print(concat("Hello, ", "Lilly"))
#-> Hello, Lilly
# Passing data to the function using the parameter name.
print(concat(name="Glenn", greeting="Hello, "))
#-> Hello, Glenn
الاستدعاء الأول لـ concat يمرّر الوسائط حسب الموضع.
أما الاستدعاء الثاني لـ concat فيمرّر الوسائط بالأسماء، مما يسمح بتغيير مواضعها.
لاحظ أن الوسائط الموضعية لا يمكن أن تأتي بعد الوسائط الممرَّرة بالاسم (وتُسمى أيضًا الوسائط المفتاحية. ويجب عدم الخلط بينها وبين المعاملات الموضعية المتغيرة أو **kwargs).
هذه المجموعة من الوسائط:
print(concat(greeting="Hello, ", "Gregor"))
تؤدي إلى هذا الخطأ:
SyntaxError: positional argument follows keyword argument
يمكن فرض وسائط موضعية فقط عند استدعاء الدوال باستخدام العامل / في قائمة المعاملات:
# Parameters showing a position-only operator.
def concat(greeting, name, /):
return f"{greeting}{name}"
print(concat("Hello, ", "Ginnie"))
#-> Hello, Ginnie
# Call to the function using keyword arguments.
print(concat(name="Franklin", greeting="Hello, "))
Traceback (most recent call last):
print(concat(name="Franklin", greeting="Hello, "))
TypeError: concat() got some positional-only arguments passed as keyword arguments: 'greeting, name'
تستخدم الوسائط المفتاحية اسم المعامل عند استدعاء دالة. ويمكن اختياريًا الإشارة إليها حسب الموضع:
def concat(greeting, name):
return f"{greeting}{name}"
# Function call using parameter names as argument keywords.
print(concat(name="Eliza", greeting="Hello, "))
#-> Hello, Eliza
# Function call with positional data as arguments.
print(concat("Hello, ", "Tim"))
#-> Hello, Tim
يمكن فرض وسائط مفتاحية فقط عند استدعاء الدوال باستخدام العامل * في قائمة المعاملات:
# Function definition requiring keyword-only arguments.
def concat(*, greeting, name):
return f"{greeting}{name}"
# Keyword arguments can be in an arbitrary order.
print(concat(name="Kimmie", greeting="Hello, "))
#-> Hello, Kimmie
# Calling the function with positional data raises an error.
print(concat("Hello, ", "Coleen"))
Traceback (most recent call last):
print(concat("Hello, ", "Coleen"))
TypeError: concat() takes 0 positional arguments but 2 were given
يمكن توفير قيم افتراضية لواحد أو أكثر من الوسائط في قائمة المعاملات. وهذا يسمح باستدعاء الدالة بعدد أقل من الوسائط عند الحاجة. ويمكن تجاوز القيم الافتراضية باستدعاء الدالة بقيمة وسيط جديدة تتجاوز القيمة الافتراضية:
# Function with default argument values.
def concat(greeting, name="you", punctuation="!"):
return f"{greeting}, {name}{punctuation}"
print(concat("Hello"))
#-> Hello, you!
# Overriding the default values
print(concat("Hello", name="Polly", punctuation="."))
#-> Hello, Polly.
يمكن أن تكون الوسائط موضعية أو مفتاحية إذا لم يُستخدم أي من العاملين / أو * في تعريفات المعاملات.
أو يمكن وضع الوسائط الموضعية أو المفتاحية بين المعاملات الموضعية فقط على اليسار والمعاملات المفتاحية فقط على اليمين:
# Position-only argument followed by position-or-keyword, followed by keyword-only.
def concat(greeting, /, name, *, ending):
return f"{greeting}{name}{ending}"
print(concat("Hello, ", "Mark", ending="!"))
#-> Hello, Mark!
print(concat("Hello, ", name="Rachel", ending="!"))
#-> Hello, Rachel!
print(concat(greeting="Hello, ", name="JoJo", ending="!"))
Traceback (most recent call last):
print(concat(greeting="Hello, ", name="JoJo", ending="!"))
TypeError: concat() got some positional-only arguments passed as keyword arguments: 'greeting'
*argsغالبًا ما تستخدم أمثلة الكود تعريف دالة شبيهًا بما يلي:
def my_function(*args, **kwargs):
# code snipped
*args اسم مكوَّن من جزأين يمثل tuple بعدد غير محدد من الوسائط الموضعية المنفصلة، ويُعرف أيضًا باسم variadic argument.
وargs هو الاسم المعطى لـ tuple الوسائط، لكنه يمكن أن يكون أي اسم آخر صالح في Python، مثل my_args و arguments وغيرها.
والعامل * هو الذي يحوّل مجموعة الوسائط المنفصلة إلى tuple.
إذا سبق لك أن فككت tuple فقد تجد العامل * في *args مربكًا.
والعامل * في تعريف المعامل، بدلًا من فك tuple، يحوّل وسيطًا موضعيًا واحدًا أو أكثر إلى tuple.
نقول إن العامل * محمَّل بأكثر من معنى، لأنه يتصرف بطرق مختلفة في سياقات مختلفة.
فعلى سبيل المثال، يُستخدم * في الضرب، ويُستخدم في فك التغليف، ويُستخدم لتعريف عدد غير محدد من المعاملات الموضعية.
بما أنه يمكن التكرار على tuple، يمكن تمرير args إلى أي دالة أخرى تقبل كائنًا قابلًا للتكرار.
ورغم أن *args كثيرًا ما يُذكر إلى جانب **kwargs، فليس بالضرورة أن يكون كذلك:
def add(*args):
# args is passed to the sum function, which iterates over it.
return sum(args)
print(add(1, 2, 3))
#-> 6
إذا جاء *args بعد وسيط موضعي واحد أو أكثر، فسيكون *args هو ما تبقى بعد الوسائط الموضعية:
def add(first, *args):
# first will be 1, leaving the values 2 and 3 in *args
return first + sum(args)
print(add(1, 2, 3))
#-> 6
إذا عُرّفت وسائط افتراضية واحدة أو أكثر بعد *args، فهي منفصلة عن قيم *args:
def add(first, *args, last=0):
return first + sum(args) + last
print(add(1, 2, 3))
#-> 6
print(add(1, 2, 3, last=4))
#-> 10
# This uses the unpacking operator * to separate the list elements into positional arguments.
# It does not have the same behavior as the * (packing) in *args.
print(add(*[1, 2, 3]))
#-> 6
لاحظ أنه عندما يكون الوسيط موجودًا بالفعل داخل iterable (مثل tuple أو list)، فيجب فك تغليفه قبل تمريره إلى دالة تقبل عددًا غير محدد من الوسائط المنفصلة.
ويتم ذلك باستخدام *، وهو عامل فك التغليف.
العامل * في هذا السياق يفك تغليف الحاوية إلى عناصرها المنفصلة، ثم يحوّلها *args إلى tuple.
وعندما تكون الوسائط موضعية فقط، يجب أن ينتج عن فك التغليف نفس عدد الوسائط بعدد المعاملات المُعرَّفة.
بدون فك تغليف القائمة الممرَّرة إلى add، سيرفع البرنامج خطأً:
def add(first, *args, last=0):
return first + sum(args) + last
print(add([1, 2, 3]))
Traceback (most recent call last):
print(add([1, 2, 3]))
return first + sum(args) + last
TypeError: can only concatenate list (not "int") to list
**kwargs**kwargs اسم مكوَّن من جزأين يمثل عددًا غير محدد من وسائط أزواج المفتاح والقيمة المنفصلة.
وkwargs هو اسم مجموعة الوسائط، ويمكن أن يكون أي اسم آخر، مثل my_args و arguments وغيرها.
ويحوّل ** مجموعة الوسائط المُسمّاة إلى dictionary من أزواج {argument name: argument value}.
بما أنه يمكن التكرار على dictionary، يمكن تمرير kwargs إلى أي دالة أخرى تقبل كائنًا قابلًا للتكرار.
ورغم أن **kwargs كثيرًا ما يُذكر إلى جانب *args، فليس بالضرورة أن يكون كذلك:
def add(**kwargs):
return sum(kwargs.values())
print(add(one=1, two=2, three=3))
#-> 6
لاحظ أن الطريقة dict.values() تُستدعى للتكرار على values في dictionary الخاص بـ kwargs.
وعند التكرار على dictionary، يكون الافتراضي هو التكرار على keys، لذلك يجب تحديد dict.values() صراحةً:
def concat(**kwargs):
# Join concatenates the tuples from `kwargs.items()`
return " ".join((str(item) for item in kwargs.items()))
print(concat(one=1, two=2, three=3))
#-> ('one', 1) ('two', 2) ('three', 3)