آموزش پایتون - توابع

یک تابع در پایتون، بلوکی از کد سازمان‌یافته و قابل استفاده مجدد است که برای انجام یک عمل واحد و مرتبط استفاده می‌شود. توابع باعث ایجاد ساختار ماژولار بهتر برای برنامه شما و سطح بالایی از قابلیت استفاده مجدد کد می‌شوند.

یک رویکرد بالا به پایین برای ساخت منطق پردازش، شامل تعریف بلوک‌هایی از توابع مستقل و قابل استفاده مجدد است. یک تابع در پایتون می‌تواند از هر تابع دیگری با ارسال داده‌های مورد نیاز (که پارامترها یا آرگومان‌ها نامیده می‌شوند) فراخوانی شود. تابع فراخوانی‌شده نتیجه خود را به محیط فراخوان بازمی‌گرداند.

python functions

انواع توابع در پایتون

پایتون انواع توابع زیر را ارائه می‌دهد −

شماره نوع و شرح
1

توابع توکار (Built-in)

کتابخانه استاندارد پایتون شامل تعدادی تابع توکار است. برخی از توابع توکار پایتون عبارتند از print()، int()، len()، sum() و غیره. این توابع همیشه در دسترس هستند، زیرا به محض شروع مفسر پایتون در حافظه کامپیوتر بارگذاری می‌شوند.

2

توابع تعریف‌شده در ماژول‌های توکار

کتابخانه استاندارد همچنین تعدادی ماژول را در خود جای داده است. هر ماژول گروهی از توابع را تعریف می‌کند. این توابع بلافاصله در دسترس نیستند و لازم است آن‌ها را از ماژول‌های مربوطه‌شان وارد (import) حافظه کنید.

3

توابع تعریف‌شده توسط کاربر (User-defined)

علاوه بر توابع توکار و توابع موجود در ماژول‌های توکار، شما می‌توانید توابع اختصاصی خود را نیز ایجاد کنید. به این توابع، توابع تعریف‌شده توسط کاربر می‌گویند.

تعریف یک تابع در پایتون

شما می‌توانید برای ارائه عملکرد مورد نظر خود، توابع سفارشی تعریف کنید. در ادامه قواعد ساده‌ای برای تعریف تابع در پایتون آورده شده است −

  • بلوک‌های تابع با کلمه کلیدی def شروع می‌شوند که پس از آن نام تابع و پرانتز () قرار می‌گیرد.

  • هرگونه پارامتر یا آرگومان ورودی باید داخل این پرانتزها قرار گیرد. همچنین می‌توانید پارامترها را در داخل این پرانتزها تعریف کنید.

  • اولین دستور یک تابع می‌تواند یک دستور اختیاری باشد؛ رشته مستندات تابع یا همان docstring.

  • بلوک کد درون هر تابع با یک علامت دو نقطه (:) شروع می‌شود و دارای تورفتگی (indent) است.

  • دستور return [expression] از تابع خارج می‌شود و به صورت اختیاری یک عبارت را به فراخواننده بازمی‌گرداند. دستور return بدون هیچ آرگومانی معادل return None است.

سنتکس تعریف یک تابع در پایتون

def function_name( parameters ):
   "function_docstring"
   function_suite
   return [expression]

به طور پیش‌فرض، پارامترها رفتار موقعیتی (positional) دارند و شما باید آن‌ها را دقیقاً به همان ترتیبی که تعریف شده‌اند مقداردهی کنید.

پس از تعریف تابع، می‌توانید آن را با فراخوانی از یک تابع دیگر یا مستقیماً از محیط پایتون اجرا کنید.

مثالی از تعریف یک تابع در پایتون

مثال زیر نحوه تعریف تابع greetings() را نشان می‌دهد. پرانتز خالی است، بنابراین هیچ پارامتری وجود ندارد. در اینجا، سطر اول یک docstring است و بلوک تابع با دستور return به پایان می‌رسد.

def greetings():
   "This is docstring of greetings function"
   print ("Hello World")
   return

هنگامی که این تابع فراخوانی می‌شود، پیام Hello world چاپ خواهد شد.

فراخوانی یک تابع در پایتون

تعریف یک تابع فقط نامی به آن اختصاص می‌دهد، پارامترهایی را که قرار است در تابع گنجانده شوند مشخص می‌کند و بلوک‌های کد را ساختاردهی می‌کند. پس از نهایی شدن ساختار پایه یک تابع، می‌توانید آن را با استفاده از خود نام تابع فراخوانی کنید. اگر تابع به پارامتری نیاز داشته باشد، باید آن پارامترها داخل پرانتز ارسال شوند. اگر تابع به هیچ پارامتری نیاز نداشته باشد، پرانتزها باید خالی بمانند.

مثالی از فراخوانی یک تابع در پایتون

در ادامه مثالی برای فراخوانی تابع printme() آورده شده است −

# Function definition is here
def printme( str ):
   "This prints a passed string into this function"
   print (str)
   return;

# Now you can call the function
printme("I'm first call to user defined function!")
printme("Again second call to the same function")

هنگامی که کد بالا اجرا می‌شود، خروجی زیر را تولید می‌کند −

I'm first call to user defined function!
Again second call to the same function

ارسال با مرجع در برابر ارسال با مقدار (Pass by Reference vs Value)

در زبان‌های برنامه‌نویسی مانند C و ++C، دو روش اصلی برای ارسال متغیرها به یک تابع وجود دارد که عبارتند از Call by Value (ارسال با مقدار) و Call by Reference (ارسال با مرجع). با این حال، نحوه ارسال متغیرها به توابع در پایتون با دیگر زبان‌ها متفاوت است.

  • ارسال با مقدار (call by value) − هنگامی که یک متغیر در زمان فراخوانی به یک تابع ارسال می‌شود، مقدار آرگومان‌های واقعی در متغیرهایی که آرگومان‌های صوری را نمایندگی می‌کنند، کپی می‌شود. بنابراین، هرگونه تغییر در آرگومان‌های صوری در آرگومان واقعی منعکس نمی‌شود. این روش ارسال متغیر به عنوان ارسال با مقدار شناخته می‌شود.

  • ارسال با مرجع (call by reference) − در این روش ارسال متغیر، مرجعی به شیء موجود در حافظه ارسال می‌شود. هم آرگومان‌های صوری و هم آرگومان‌های واقعی (متغیرهای موجود در کد فراخواننده) به یک شیء یکسان اشاره می‌کنند. از این رو، هرگونه تغییر در آرگومان‌های صوری در آرگومان واقعی نیز منعکس می‌شود.

Pass By Reference Vs Value

پایتون از مکانیسم ارسال با مرجع استفاده می‌کند. از آنجایی که متغیر در پایتون یک برچسب یا مرجع به شیء موجود در حافظه است، هر دو متغیر مورد استفاده به عنوان آرگومان واقعی و آرگومان صوری در واقع به یک شیء یکسان در حافظه اشاره می‌کنند. ما می‌توانیم این موضوع را با بررسی id() متغیر ارسالی قبل و بعد از ارسال بررسی کنیم.

مثال

در مثال زیر، id() یک متغیر را بررسی می‌کنیم.

def testfunction(arg):
   print ("ID inside the function:", id(arg))

var = "Hello"
print ("ID before passing:", id(var))
testfunction(var)

اگر کد بالا اجرا شود، id() قبل از ارسال و داخل تابع نمایش داده خواهد شد.

ID before passing: 1996838294128
ID inside the function: 1996838294128

این رفتار همچنین به این بستگی دارد که شیء ارسالی تغییرپذیر (mutable) است یا تغییرناپذیر (immutable). شیء عددی در پایتون تغییرناپذیر است. وقتی یک شیء عددی ارسال می‌شود و سپس تابع مقدار آرگومان صوری را تغییر می‌دهد، در واقع یک شیء جدید در حافظه ایجاد می‌کند و متغیر اصلی را بدون تغییر باقی می‌گذارد.

مثال

مثال زیر نحوه رفتار یک شیء تغییرناپذیر را هنگام ارسال به یک تابع نشان می‌دهد.

def testfunction(arg):
   print ("ID inside the function:", id(arg))
   arg = arg + 1
   print ("new object after increment", arg, id(arg))

var=10
print ("ID before passing:", id(var))
testfunction(var)
print ("value after function call", var)

این کد خروجی زیر را تولید خواهد کرد −

ID before passing: 140719550297160
ID inside the function: 140719550297160
new object after increment 11 140719550297192
value after function call 10

اکنون بیاورید یک شیء تغییرپذیر (مانند یک لیست یا دیکشنری) را به یک تابع ارسال کنیم. این شیء نیز با مرجع ارسال می‌شود، زیرا id() لیست قبل و بعد از ارسال یکسان است. با این حال، اگر لیست را در داخل تابع تغییر دهیم، بازنمایی سراسری آن نیز تغییر را منعکس می‌کند.

مثال

در اینجا ما یک لیست را ارسال می‌کنیم، آیتم جدیدی به آن اضافه می‌کنیم و محتویات شیء لیست اصلی را مشاهده می‌کنیم که خواهیم دید تغییر کرده است.

def testfunction(arg):
   print ("Inside function:",arg)
   print ("ID inside the function:", id(arg))
   arg=arg.append(100)
   
var=[10, 20, 30, 40]
print ("ID before passing:", id(var))
testfunction(var)
print ("list after function call", var)

این کد خروجی زیر را تولید خواهد کرد −

ID before passing: 2716006372544
Inside function: [10, 20, 30, 40]
ID inside the function: 2716006372544
list after function call [10, 20, 30, 40, 100]

آرگومان‌های تابع در پایتون

آرگومان‌های تابع مقادیر یا متغیرهایی هستند که هنگام فراخوانی تابع به آن ارسال می‌شوند. رفتار یک تابع اغلب به آرگومان‌های ارسالی به آن بستگی دارد.

هنگام تعریف یک تابع، لیستی از متغیرها (که به عنوان پارامترهای صوری شناخته می‌شوند) را در داخل پرانتز مشخص می‌کنید. این پارامترها به عنوان نگه‌دارنده مکان (placeholder) برای داده‌هایی عمل می‌کنند که هنگام فراخوانی تابع به آن ارسال می‌شوند. وقتی تابع فراخوانی می‌شود، باید مقداری برای هر یک از آرگومان‌های صوری ارائه شود. به این مقادیر، آرگومان‌های واقعی می‌گویند.

function arguments

مثال

بیاورید تابع greetings را تغییر دهیم و name را به عنوان یک آرگومان قرار دهیم. رشته‌ای که به عنوان آرگومان واقعی به تابع ارسال می‌شود، تبدیل به متغیر name در داخل تابع می‌شود.

def greetings(name):
   "This is docstring of greetings function"
   print ("Hello {}".format(name))
   return
   
greetings("Samay")
greetings("Pratima")
greetings("Steven")

این کد خروجی زیر را تولید خواهد کرد −

Hello Samay
Hello Pratima
Hello Steven

انواع آرگومان‌های تابع در پایتون

بر اساس نحوه اعلام آرگومان‌ها هنگام تعریف تابع پایتون، آن‌ها به دسته‌های زیر طبقه‌بندی می‌شوند −

آرگومان‌های موقعیتی یا اجباری

آرگومان‌های اجباری آرگومان‌هایی هستند که با ترتیب موقعیتی درست به یک تابع ارسال می‌شوند. در اینجا، تعداد آرگومان‌ها در فراخوانی تابع باید دقیقاً با تعریف تابع مطابقت داشته باشد، در غیر این صورت کد خطای سنتکس می‌دهد.

مثال

در کد زیر، تابع printme() را بدون هیچ پارامتری فراخوانی می‌کنیم که باعث بروز خطا می‌شود.

# Function definition is here
def printme( str ):
   "This prints a passed string into this function"
   print (str)
   return;

# Now you can call printme function
printme()

هنگامی که کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

Traceback (most recent call last):
   File "test.py", line 11, in <module>
      printme();
TypeError: printme() takes exactly 1 argument (0 given)

آرگومان‌های کلیدواژه‌ای

آرگومان‌های کلیدواژه‌ای مربوط به فراخوانی‌های تابع هستند. وقتی از آرگومان‌های کلیدواژه‌ای در فراخوانی تابع استفاده می‌کنید، فراخواننده آرگومان‌ها را با نام پارامتر شناسایی می‌کند. این امر به شما امکان می‌دهد آرگومان‌ها را حذف کنید یا آن‌ها را بدون رعایت ترتیب قرار دهید، زیرا مفسر پایتون قادر است با استفاده از کلیدواژه‌های ارائه شده، مقادیر را با پارامترها تطبیق دهد.

مثال ۱

مثال زیر نحوه استفاده از آرگومان‌های کلیدواژه‌ای در پایتون را نشان می‌دهد.

# Function definition is here
def printme( str ):
   "This prints a passed string into this function"
   print (str)
   return;

# Now you can call printme function
printme( str = "My string")

هنگامی که کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

My string

مثال ۲

مثال زیر تصویر شفاف‌تری ارائه می‌دهد. توجه داشته باشید که ترتیب پارامترها اهمیتی ندارد.

# Function definition is here
def printinfo( name, age ):
   "This prints a passed info into this function"
   print ("Name: ", name)
   print ("Age ", age)
   return;

# Now you can call printinfo function
printinfo( age=50, name="miki" )

هنگامی که کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

Name:  miki
Age  50

آرگومان‌های پیش‌فرض

یک آرگومان پیش‌فرض آرگومانی است که اگر در فراخوانی تابع مقداری برای آن ارائه نشود، مقدار پیش‌فرض را به خود می‌گیرد.

مثال

مثال زیر ایده‌ای درباره آرگومان‌های پیش‌فرض ارائه می‌دهد؛ در صورتی که سن ارسال نشود، سن پیش‌فرض را چاپ می‌کند −

# Function definition is here
def printinfo( name, age = 35 ):
   "This prints a passed info into this function"
   print ("Name: ", name)
   print ("Age ", age)
   return;

# Now you can call printinfo function
printinfo( age=50, name="miki" )
printinfo( name="miki" )

هنگامی که کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

Name:  miki
Age  50
Name:  miki
Age  35

آرگومان‌های فقط-موقعیتی

به آرگومان‌هایی که فقط می‌توان آن‌ها را بر اساس موقعیتشان در فراخوانی تابع مشخص کرد، آرگومان‌های فقط-موقعیتی می‌گویند. آن‌ها با قرار دادن یک اسلش ("/") در لیست پارامترهای تابع بعد از همه پارامترهای فقط-موقعیتی تعریف می‌شوند. این ویژگی با انتشار پایتون ۳.۸ معرفی شد.

مزیت استفاده از این نوع آرگومان این است که تضمین می‌کند توابع با آرگومان‌های صحیح و به ترتیب درست فراخوانی می‌شوند. آرگومان‌های فقط-موقعیتی باید به عنوان آرگومان‌های موقعیتی به تابع ارسال شوند، نه آرگومان‌های کلیدواژه‌ای.

مثال

در مثال زیر، دو آرگومان فقط-موقعیتی به نام‌های "x" و "y" تعریف کرده‌ایم. این متد باید با آرگومان‌های موقعیتی به همانس ترتیبی که آرگومان‌ها اعلام شده‌اند فراخوانی شود، در غیر این صورت با خطا مواجه خواهیم شد.

def posFun(x, y, /, z):
    print(x + y + z)

print("Evaluating positional-only arguments: ")
posFun(33, 22, z=11) 

این کد خروجی زیر را تولید خواهد کرد −

Evaluating positional-only arguments: 
66

آرگومان‌های فقط-کلیدواژه‌ای

به آرگومان‌هایی که هنگام فراخوانی تابع حتماً باید با نامشان مشخص شوند، آرگومان‌های فقط-کلیدواژه‌ای می‌گویند. آن‌ها با قرار دادن یک ستاره ("*") در لیست پارامترهای تابع قبل از هرگونه پارامتر فقط-کلیدواژه‌ای تعریف می‌شوند. این نوع آرگومان فقط می‌تواند به صورت یک آرگومان کلیدواژه‌ای به تابع ارسال شود، نه یک آرگومان موقعیتی.

مثال

در کد زیر، یک تابع با سه آرگومان فقط-کلیدواژه‌ای تعریف کرده‌ایم. برای فراخوانی این متد، باید آرگومان‌های کلیدواژه‌ای ارسال کنیم، در غیر این صورت با خطا مواجه خواهیم شد.

def posFun(*, num1, num2, num3):
    print(num1 * num2 * num3)

print("Evaluating keyword-only arguments: ")
posFun(num1=6, num2=8, num3=5) 

این کد خروجی زیر را تولید خواهد کرد −

Evaluating keyword-only arguments: 
240

آرگومان‌های دلخواه یا با طول متغیر

ممکن است لازم باشد یک تابع را برای آرگومان‌های بیشتری نسبت به آنچه هنگام تعریف تابع مشخص کرده‌اید پردازش کنید. به این آرگومان‌ها آرگومان‌های با طول متغیر می‌گویند و برخلاف آرگومان‌های اجباری و پیش‌فرض، در تعریف تابع نام‌گذاری نمی‌شوند.

سنتکس یک تابع با آرگومان‌های متغیر غیرکلیدواژه‌ای به این صورت است −

def functionname([formal_args,] *var_args_tuple ):
   "function_docstring"
   function_suite
   return [expression]

یک علامت ستاره (*) قبل از نام متغیری قرار می‌گیرد که مقادیر تمام آرگومان‌های متغیر غیرکلیدواژه‌ای را نگه می‌دارد. اگر در طول فراخوانی تابع هیچ آرگومان اضافی مشخص نشود، این تاپل خالی می‌ماند.

مثال

در ادامه مثالی ساده از آرگومان‌های با طول متغیر در پایتون آورده شده است.

# Function definition is here
def printinfo( arg1, *vartuple ):
   "This prints a variable passed arguments"
   print ("Output is: ")
   print (arg1)
   for var in vartuple:
      print (var)
   return;

# Now you can call printinfo function
printinfo( 10 )
printinfo( 70, 60, 50 )

هنگامی که کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

Output is:
10
Output is:
70
60
50

در چند فصل بعدی، به تفصیل درباره این آرگومان‌های تابع بحث خواهیم کرد.

ترتیب آرگومان‌های تابع در پایتون

یک تابع می‌تواند دارای آرگومان‌هایی از هر یک از انواع تعریف‌شده در بالا باشد. با این حال، آرگومان‌ها باید به ترتیب زیر تعریف شوند −

  • لیست آرگومان‌ها با آرگومان‌های فقط-موقعیتی شروع می‌شود که پس از آن نماد اسلش (/) قرار می‌گیرد.

  • پس از آن آرگومان‌های موقعیتی معمولی قرار می‌گیرند که می‌توان آن‌ها را به عنوان آرگومان‌های کلیدواژه‌ای نیز فراخوانی کرد یا نکرد.

  • سپس ممکن است یک یا چند آرگومان با مقادیر پیش‌فرض وجود داشته باشد.

  • سپس آرگومان‌های موقعیتی دلخواه قرار می‌گیرند که با متغیری پیشوندشده با یک ستاره نشان داده می‌شوند و به عنوان تاپل در نظر گرفته می‌شوند. این مورد بعدی است.

  • اگر تابع دارای آرگومان‌های فقط-کلیدواژه‌ای باشد، قبل از شروع نام آن‌ها یک ستاره قرار دهید. برخی از آرگومان‌های فقط-کلیدواژه‌ای ممکن است مقدار پیش‌فرض داشته باشند.

  • آخرین مورد در پرانتز، آرگومانی با دو ستاره ** است تا تعداد دلخواهی از آرگومان‌های کلیدواژه‌ای را بپذیرد.

دیاگرام زیر ترتیب آرگومان‌های صوری را نشان می‌دهد −

Order Of Formal Arguments

تابع پایتون با مقدار بازگشتی

کلمه کلیدی return به عنوان آخرین دستور در تعریف تابع، نشان‌دهنده پایان بلوک تابع است و جریان برنامه به تابع فراخواننده بازمی‌گردد. اگرچه کاهش تورفتگی بعد از آخرین دستور در بلوک نیز به معنای بازگشت است، اما استفاده از return صریح یک روش خوب و استاندارد است.

تابع همراه با کنترل جریان، می‌تواند مقدار یک عبارت را نیز به تابع فراخواننده بازگرداند. مقدار عبارت بازگردانده‌شده را می‌توان در یک متغیر برای پردازش‌های بعدی ذخیره کرد.

مثال

بیاورید تابع add() را تعریف کنیم. این تابع دو مقدار ارسالی به خود را جمع می‌کند و حاصل جمع را بازمی‌گرداند. مقدار بازگردانده‌شده در متغیری به نام result ذخیره می‌شود.

def add(x,y):
   z=x+y
   return z
a=10
b=20
result = add(a,b)
print ("a = {} b = {} a+b = {}".format(a, b, result))

این کد خروجی زیر را تولید خواهد کرد −

a = 10 b = 20 a+b = 30

توابع بی‌نام (Anonymous Functions)

توابع زمانی بی‌نام نامیده می‌شوند که به روش استاندارد با استفاده از کلمه کلیدی def تعریف نشده باشند. در عوض، آن‌ها با استفاده از کلمه کلیدی lambda تعریف می‌شوند.

  • فرم‌های لمبدا می‌توانند هر تعداد آرگومان دریافت کنند اما فقط یک مقدار را به شکل یک عبارت بازمی‌گردانند. آن‌ها نمی‌توانند حاوی دستورات متعدد یا عبارات چندگانه باشند.

  • یک تابع بی‌نام نمی‌تواند فراخوانی مستقیم print باشد زیرا لمبدا به یک عبارت نیاز دارد.

  • توابع لمبدا فضای نام محلی خود را دارند و نمی‌توانند به متغیرهایی غیر از متغیرهای موجود در لیست پارامترهای خود و متغیرهای موجود در فضای نام سراسری دسترسی داشته باشند.

  • اگرچه به نظر می‌رسد لمبداها نسخه تک‌خطی یک تابع هستند، اما با دستورات inline در C یا ++C که هدف آن‌ها دور زدن تخصیص پشته تابع در طول فراخوانی به دلایل عملکردی است، یکسان نیستند.

سنتکس

سنتکس توابع لمبدا تنها شامل یک دستور است که به صورت زیر است −

lambda [arg1 [,arg2,.....argn]]:expression

مثال

در ادامه مثالی آورده شده است تا نحوه کار فرم لمبدای تابع را نشان دهد −

# Function definition is here
sum = lambda arg1, arg2: arg1 + arg2;

# Now you can call sum as a function
print ("Value of total : ", sum( 10, 20 ))
print ("Value of total : ", sum( 20, 20 ))

هنگامی که کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

Value of total :  30
Value of total :  40

حوزه متغیرها (Scope of Variables)

ممکن است تمام متغیرهای موجود در یک برنامه در همه بخش‌های آن برنامه قابل دسترسی نباشند. این امر به محل تعریف متغیر بستگی دارد.

حوزه یک متغیر بخشی از برنامه را تعیین می‌کند که در آن می‌توانید به یک شناسه خاص دسترسی داشته باشید. دو حوزه اصلی برای متغیرها در پایتون وجود دارد −

  • متغیرهای سراسری (Global variables)
  • متغیرهای محلی (Local variables)

متغیرهای سراسری در برابر محلی

متغیرهایی که در داخل بدنه یک تابع تعریف می‌شوند دارای حوزه محلی هستند و متغیرهایی که در خارج تعریف می‌شوند دارای حوزه سراسری هستند.

این بدان معناست که متغیرهای محلی فقط در داخل تابعی که در آن تعریف شده‌اند قابل دسترسی هستند، در حالی که متغیرهای سراسری می‌توانند در سراسر بدنه برنامه توسط همه توابع دسترسی داشته باشند. وقتی یک تابع را فراخوانی می‌کنید، متغیرهای تعریف‌شده در داخل آن وارد حوزه اجرایی می‌شوند.

مثال

در ادامه مثالی ساده از حوزه محلی و سراسری آورده شده است −

total = 0; # This is global variable.
# Function definition is here
def sum( arg1, arg2 ):
   # Add both the parameters and return them."
   total = arg1 + arg2; # Here total is local variable.
   print ("Inside the function local total : ", total)
   return total;

# Now you can call sum function
sum( 10, 20 );
print ("Outside the function global total : ", total) 

هنگامی که کد بالا اجرا می‌شود، نتیجه زیر را تولید می‌کند −

Inside the function local total :  30
Outside the function global total :  0

پیشرفت مطالعه: وضعیت خوانده‌شدن این درس فقط در همین مرورگر ذخیره می‌شود؛ بدون نیاز به حساب کاربری.