زبان برنامه نویسی پایتون – ۳ (Functionها)

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

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


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

در ابتدا باید اشاره کنیم که در زبان برنامه نویسی پایتون تعداد زیادی builtin function وجود دارد که میتوانیم از آنها استفاده کنیم و به مرور که با پایتون کار میکنیم با این فانکشنها آشنا میشویم. اگر کد زیر را اجرا کنید تمام builtin functionهایی که در زبان برنامه نویسی پایتون در دسترس هستند را مشاهده میکنید.

print(dir(__builtins__))

نکته مهم: در زبان برنامه نویسی پایتون هر چیزی یک آبجکت است، مثل string, list, tuple, … و هر آبجکتی بسته به type آن متدهایی برایش در دسترس است. همچنین برخی از آبجکتها متدهای مشابهی هم دارند مثلا builtin functionی به نام index برای هر دو نوع آبجکت string و list در دسترس است.


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

def my_function():
  print("Hello from a function")

مثل سایر زبانها، میتوانیم به فانکشن آرگومانهایی را پاس دهیم و یا بدون آرگومان باشد. همچنین میتوانیم برای آرگومان ها مقادیر پیشفرض تعریف کنیم.

def my_function(fname, lname):
  print(fname + " " + lname)

my_function("Emil", "Refsnes")

در تابع بالا در صورتیکه یکی از آرگومانها را پاس ندهیم با خطا مواجه میشویم و در صورتیکه یکی از آرگومانها اختیاری است باید برای آن مقدار پیشفرض تعیین کنیم. همچنین مهم است که طبق اولویت آرگومانها را پاس دهیم ولی ما میتوانیم برای آرگومانها کلیدواژه تعریف کنیم و بر آن اساس مهم نیست که کدام آرگومان را طبق کدام اولویت ارسال میکنیم. برای مثال در زبان برنامه نویسی پایتون یک builtin function به اسم sorted وجود دارد که وقتی لیستی را به آن پاس میدهیم آن را برای ما sort میکند و اگر دستور زیر را در کامندلاین وارد کنید آرگومانهای آن را مشاهده میکنید:

help(sorted)

// Output
Help on built-in function sorted in module builtins:

sorted(iterable, /, *, key=None, reverse=False)
    Return a new list containing all items from the iterable in ascending order.

    A custom key function can be supplied to customize the sort order, and the
    reverse flag can be set to request the result in descending order.

همانطور که مشاهده میکنید برای sorted فانکشن ما باید چند پارامتر ارسال کنیم و فقط آیتم اول الزامی است و سایر آرگومانها اختیاری هستند، حالا اگر بخواهیم نوع sort را به صورت DESC مرتب کنیم باید مقدار آخر یعنی reverse را پاس دهیم ولی مقدار دوم را چطور پاس دهیم؟! به صورت زیر میتوانیم مقدار دوم یعنی key را نادیده بگیریم:

degrees = [12, 8, 17, 45, 32, 18, 15]

sorted(degrees)
// [۸, ۱۲, ۱۵, ۱۷, ۱۸, ۳۲, ۴۵]

sorted(degrees, reverse=True)
// [۴۵, ۳۲, ۱۸, ۱۷, ۱۵, ۱۲, ۸]

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

Arbitrary / Non-keyword Arguments

در صورتیکه میخواهیم آرگومانهایی را به صورت داینامیک به فانکشن پاس دهیم میتوانیم آرگومان فانکشن را به صورت *args تعریف کنیم و در حالتهای مختلف پارامترهای مختلف با تعداد متغیر را میتوانیم پاس دهیم. در این حالت آرگومان ورودی به صورت یک لیست در فانکشن در دسترس است.

def my_function(*kids):
  print("The youngest child is " + kids[2])

my_function("Emil", "Tobias", "Linus")

Keyword Arguments

میتوانیم آرگومانهایی را به صورت key = value به فانکشن پاس دهیم و در این حالت مهم نیست کدام آرگومان را با کدام اولویت مینویسیم.

def my_function(child3, child2, child1):
  print("The youngest child is " + child3)

my_function(child1 = "Emil", child2 = "Tobias", child3 = "Linus")

Arbitrary Keyword Arguments, **kwargs

در صورتیکه تعداد آرگومانهایی که به صورت key = value به فانکشن پاس می دهیم نا مشخص باشد میتوانیم به صورت **kwargs آن را تعریف کنیم و در این حالت محدودیتی در حالتهای مختلف آرگومان نخواهیم داشت. در این حالت آرگومان ورودی به صورت یک dictionary داخل فانکشن در دسترس است.

def my_function(**kid):
  print("His last name is " + kid["lname"])

my_function(fname = "Tobias", lname = "Refsnes")
Non-keyword and keyword arguments

نکته: همانطور که در بخشهای قبل در رابطه با کلیدواژه pass صحبت کردیم، وقتی یک function را تعریف میکنیم مقدار آن نمیتواند خالی باشد و برای این خطایی رخ ندهد باید کلمه کلیدی pass را در body آن قرار دهیم.


Python Scope

Scope در برنامه نویسی مشخص میکند که کجا متغیرها میتوانند در دسترس و قابل ارجاع باشند.

در زبان برنامه نویسی پایتون وقتی متغیری را تعریف میکنیم برای آن در واقع scope مشخصی وجود دارد و باید بدانیم که متغیر چگونه و در چه بخشهایی در دسترس است. دو حالت local scope و global scope برای متغیرها وجود دارد. برای مثال وقتی یک متغیر را داخل یک فانکشن تعریف میکنیم متغیر فقط داخل فانکشن در دسترس است و اگر بخواهیم متغیر در بخشهای دیگر در دسترس باشد باید آن را خارج از فانکشن تعریف کنیم.

مثال زیر را با دقت مشاهده کنید

x = 10

def foo():
    x = 85
    print("inside the function: x=", x)

foo()
print("outside function: x=", x)

// OUTPUT
inside the function: x= 85
outside function: x= 10

و اگر تغییرات زیر را داخل function اعمال کنیم:

x = 10

def foo():
    global x
    x = 85
    print("inside the function: x=", x)

foo()
print("outside function: x=", x)

// OUTPUT
inside the function: x= 85
outside function: x= 85

Python Lambda Function

Lambda function یک فانکشن کوتاه و بدون نام در زبان برنامه نویسی پایتون است. این نوع فانکشن میتواند هر تعدادی آرگومان ورودی دریافت کند ولی تنها یک expression میتواند داشته باشد. و به صورت زیر میتوانیم آن را تعریف کنیم:

lambda arguments : expression

x = lambda a : a + 10
print(x(5))

x = lambda a, b, c : a + b + c
print(x(5, 6, 2))

Generator Function

جنریتور فانکشن یک نوع خاص از فانکشن در زبان برنامه نویسی پایتون است که یک آبجکت تکرار کننده را با دنباله ای از مقادیر برمی گرداند. این نوع فانکشن به جای اینکه از return استفاده کند و مقداری برگرداند از کلمه کلیدی yield استفاده میکند و وقتی یک فانکشن از yield استفاده کند در واقع Generator Function به حساب می آید.

تفاوت Return و Yield:

  • عبارت return به این معنی است که تابع، کنترل اجرا را به نقطه ای که تابع فراخوانی می شود برمی گرداند.
  • بعد از return، این فرآیند متغیرهای محلی و مقادیر تولید شده را از بین می برد.
  • عبارت yield بیانگر این است که انتقال کنترل به نقطه فراخوانی شده موقتی است.
  • از این رو، متغیرهای محلی تابع را از بین نمی برد.
def myFuncGenerator():
    n = 1
    yield 'first iteration:' + str(n)

    n += 2
    yield 'second iteration:'+ str(n)

    n += 5
    yield 'third iteration:'+ str(n)


genrator = myFuncGenerator()
genrator

// OUTPUT
<generator object myFuncGenerator at 0x7fd01306dba0>

وقتی خروجی بالا را ببینیم که جنریتور آبجکت در خروجی میبینیم و به صورت زیر مقادیر را میتوانیم چاپ کنیم:

Python function generator

استفاده از پکیج‌ها در پایتون

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

import numpy as np

array([1,2,3])  // OUTPUT => ERROR 

np.array([1,2,3])

ولی اگر بخواهیم فقط قابلیت array رو به برنامه اضافه کنیم میتوانیم به صورت زیر بنویسیم:

from numpy import array

array([1,2,3]) 

در این حالت با خطا مواجه نمیشویم ولی پیشنهاد این است از این روش به خاطر رعایت مفاهیم Clean Code استفاده نکنیم به این خاطر وقتی حجم برنامه زیاد میشود و developerهای دیگری روی پروژه کار میکنند با دیدن array نمیتونند متوجه شوند که چطور از آن استفاده شده است ولی وقتی بنویسیم np.array متوجه میشوند که از پکیج np و فانکشن array استفاده شده است و خوانایی کد بیشتر میشود.

مثالی از نوشتن یک function برای جنریت کردن رمز عبور

فرض کنید که ما در برنامه خود میخواهیم از تابعی استفاده کنیم که در بخشهای مختلف رمزهای قوی و یونیکی را برای ما جنریت کند. در این صورت به صورت زیر یک فانکشن مینویسیم و در هر بخش که نیاز داشتیم آن را فراخوانی میکنیم.

قبل از نوشتن و بررسی تابع پیشنهاد میکنم ابتدا داکیومنت پایتون برای stringها و همچنین بخش random را مطالعه کنید. تابع sample از random یک لیست به تعداد k از مقدار ورودی که دریافت میکند و یونیک است را جنریت میکند.

import string
import random

def passwordGenerator(length = 12):
    
    randomStrings = string.ascii_lowercase + string.ascii_uppercase + string.digits + string.punctuation
    randomChars = random.sample(randomStrings, length)
    password = ''.join(randomChars)
    print(password)


passwordGenerator()

ادامه سری مقالات زبان برنامه نویسی پایتون

زبان برنامه نویسی پایتون – ۴

Python Built-in Functions

Comments