در این مطلب میخوایم اول به بررسی تفاوت بین Argument و Parameter بپردازیم بعد تفاوت بین Call By Refrence و Call By Value رو در زبان های برنامه نویسی بررسی کنیم
تفاوت بین آرگومان (Argument) و پارامتر (Parameter) چیست؟
در زبان های برنامه نویسی اگر ما بخوایم یه تابعی رو صدا بزنیم و مقادیری رو بهش بفرستیم چند تا اصطلاح داریم :
def sum(p,o):
sum=p+o
return sum
a=int(input("1st Num: "))
b=int(input("2nd Num: "))
print(sum(a,b))
در اینجا اگر دقت کنید وقتی که ما میخوایم یه تابعی رو صدا بزنیم یه مقادیری رو بهش اصطلاحا پاس میدیم (Pass) و در اینجا دوتا اصطلاح هست ، مقادیر a و b ای که ما میخوایم پاس بدیم و در حال فرستاده شدنه میشه ارگومان ، و مقادیری که داخل تابع دریافت میشه و روش پردازش انجام میشه ، پارامتر نام میگیره ، یعنی p و o در خط 1 پارامتر هستن و a و b در خط 7 ارگومان هستن (این مفهوم در تمامی زبان های برنامه نویسی وجود داره)
تفاوت بین Call By Refrence و Call By Value چیست؟
در زبان های برنامه نویسی ما یه مفهوم داریم ، و اونم اینه که ارگومانی که ما پاس میدیم به تابع ، وقتی تابع اون پارامتر رو میگیره و روش عملیات انجام میده داخل خودش، روی مقادیر اون پارامتر تغییری اعمال کنه و ارگومانم عوض بشه به این نوع پاس دادن میگن call by refrence و اگر مقادیر ارگومان و پارامتر متفاوت باشن میشه call by value ، به زبانی دیگر : اگر ما موقعی که میخوایم مقادیر رو پاس بدیم به تابع ، از مقادیر کپی بگیریم و کپی اونو بدیم به تابع ، این روش میشه call by value ولی اگر بیاییم به تابع آدرس مقادیر اصلی رو بدیم ، چون تابع متغییر هارو از مقادیر اصلی میخونه ، هر تغییری توی تابع روی متغییرا ایجاد بشه مستقیما روی مقادیر اصلی اثر میزاره و این روش میشه call by refrence
پس اگر خود متغیرو پاس بدیم میشه call by value اگر ادرساشونو پاس بدیم میشه call by reference
در زبان ++c
مثلا ما به صورت پیشفرض مقادیر رو به صورت Call by Value انتقال میدیم :
#include <iostream>
using namespace std;
int sum (int x){
x = 10 + x;
return(x);
}
int main()
{
int x = 5;
cout << "The result of 10 + " << x << " is " << sum(x) << endl;
cout << "Value of x is still " << x;
cin.ignore();
}
--------------------------------------------
The result of 10 + 5 is 15
Value of x is still 5
مثلا اینجا ما یه برنامه داریم که متغییر x رو ک عدد 5 رو پیشفرض در خودش داره و میاییم و به تابع sum پاسش میدیم و با عدد 10 جمع میکنه که میشه 15 ، بعد پارس دادنش دوباره با مقدار x رو چاپ میکنیم و باز میشه 5 ، یعنی مقدار x ای که داخل تابع sum شده 15 یه مقدار کاملا جداییه از x خارج ، درواقع دوتا x داریم که در هر Local Variable حساب میشن و مقادیرشون در تابع های خودشون متفاوته
در زبان پایتون
روش کار ما Call by refrence هست و چون ما شئ داریم ، این شئ ها به دو دسته تقسیم میشن :
Mutable objects یا اشئای قابل تغییر : اگر شئ قابل تغییر باشه ، مقداری که تغییر میکنه خارج از تابع هم قابل دسترسه (list, dict, set)
Immutable objects یا اشیای غیر قابل تغییر: اگر شئ غیر قابل تغییر باشن پس مقداری که تغییر میکنه خارج از تابع قابل دسترس نیست (int, float, complex, string, tuple)
مثال از اشیاء قابل تغییر :
def add_more(list):
list.append(50)
print("Inside Function", list)
mylist = [10,20,30,40]
add_more(mylist)
print("Outside Function:", mylist)
----------------------------------
Inside Function [10, 20, 30, 40, 50]
Outside Function: [10, 20, 30, 40, 50]
در اینجا ما یه لیست داریم که قابل تغییره ، و وقتی ما یه عضو جدید (در اینجا 50) رو اضافه میکنیم به این لیست داخل لیست درون و تابع و بیرون تابع اضافه میشه (درواقع call by refrence کردیم)
ولی اشیاء غیر قابل تغییر :
string = "Hi"
def test(string):
string = "hello"
print("Inside Function:", string)
test(string)
print("Outside Function:", string)
---------------------------------
Inside Function: hello
Outside Function: Hi
در اینجا چون رشته غیر قابل تغییر هست پس ما دو مقدار متفاوت در داخل و خارج تابع داریم (انگار call by value کردیم)
call by refrence در ++c
نکته : توی cpp هم میشه این کارو انجام داد ، اما با پوینتر ها ما میتونیم یه call refrence درست کنیم به وسیله پاس دادن پوینتر بعنوان ارگومان به تابع ، بجای فرستادن خود ارگومان
قبلش کمی درباره پوینتر ها توضیح بدم : پوینتر متغییره که میتونه موقعیت مکانی یا مقدار یه متغییر دیگرو در خودش بگیره ، اگر متغییری اینطوریه نوشته بشه :
x = &y;
یعنی مکان متغیرy باید ریخته بشه توی x ولی اگر
x = *y;
اینطوری باشه باید مقدار خود متغیر y ریخته بشه تو x
حالا من به دو طریق با پوینتر ها call by refrence میکنم تو cpp :
#include <iostream>
using namespace std;
void swap(int& x, int& y)
{
int temp;
temp = x;
x = y;
y = temp;
}
int main ()
{
int i, j;
i = 5;
j = 10;
cout << "Before swap i is: " << i << " and j is: " << j <<endl;
swap(i,j);
cout << "After swap i is: " << i << " and j is: " << j;
cin.ignore();
return 0;
}
-------------------------------------------
Before swap i is: 5 and j is: 10
After swap i is: 10 and j is: 5
#include <iostream>
using namespace std;
void swap(int *x, int *y)
{
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int main ()
{
int i, j;
i = 5;
j = 10;
cout << "Before swap i is: " << i << " and j is: " << j <<endl;
swap(&i,&j);
cout << "After swap i is: " << i << " and j is: " << j;
cin.ignore();
return 0;
}
--------------------------------
Before swap i is: 5 and j is: 10
After swap i is: 10 and j is: 5
خیلی درگیر کدش نمیخوام بشم ولی جفتشون یه کارو میکنن ولی به طور خلاصه علامت & قبل اسم متغییرا یعنی قراره تو یه پوینتر بگیری بجای مقدار ارگومان ، جفتشون اول میان i و j رو پاس میدن به void و x میشه i و y میشه j ، پس x = 5 و y = 10 بعد که داخل تابع void ما کارمونو انجام میدیم ، اول temp میشه مساوی x یعنی temp=5 بعد x=y میشه یعنی مقدار y ریخته میشه تو x که جفتشون میشن 10 ، بعد y=temp میشه که مقدار temp یا همون 5 ریخته میشه تو y که در نهایت y میشه 5 ، یعنی الان x=10 و y=5 شده و از اونجایی ک x=i و y=j بوده پس مقادیرشون بعد رفتن تو تابع توسط پوینترا جابجا شده
مبحث تقریبا سختیه ، یکم کد بزنید و بهش فکر کنید ، اگر سوال داشتید در خدمتم :)
سلام وقت بخیر
خیر
ببینید void که اصلا جنس نوع تابعس ک تعریف میکنیم و return اون مقدار بازگشتی
ما وقتی یه ولیو یا مقداری رو پاس میدیم به تابع ، اگر اون مقدار کم حجم باشه ، همون مقدارو پاس میدیم به تابع یعنی به صورت call by value ولی اگر مقدار خیلی بزرگ باشه ، نمیاییم اونو کپی کنیم یا ولیو یا مقدار رو بدیم به تابع چون سنگین و کند میشه ، بجاش ادرس اونجایی که اون مقدار توشه رو میدیم به تابع ک بهش میگن call by reference
بازم اگر نامفهموم بود بفرمایید
با سلام
مطلب بسیار مفید و کاربردی بود
در کل بخوایم بگیم call by value در function به صورت void تعریف میشه و call by refrence در function عمل return انجام میشه درسته؟ یا برعکس گفتم