PEP 8 یا PEP8 یا PEP-8 سندی است که دستورالعمل ها و بهترین شیوه ها را در مورد نحوه نوشتن کد پایتون ارائه می دهد. تمرکز اصلی PEP 8 بهبود خوانایی و سازگاری کد پایتون است. PEP مخفف Python Enhancement Proposal است و چندین نسخه از آنها وجود دارد. در این آموزش دستورالعمل های کلیدی ارائه شده در PEP 8 معرفی می شوند.

اصلا چرا به PEP8 نیاز داریم؟

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

همچنین اگر به عنوان یک توسعه دهنده دنبال شغل هستید پیروی از PEP 8 بسیار مهم است. نوشتن کد واضح و خوانا، حرفه ای بودن شما را نشان می دهد و به کارفرما می گوید که می دانید چگونه کد خود را به خوبی ساختار دهید.

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

قراردادهای نامگذاری

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

مثلا از حروف l و o و I به صورت تنها در نامگذاری متغیر ها استفاده نکنید چون ممکن است با اعداد 0 و 1 اشتباه گرفته شوند.

سبک های نامگذاری

تابع: از یک یا چند کلمه با حروف کوچک استفاده شود. اگر بیش از یک کلمه است با علامت _ از هم جدا شوند. مثال:

calculate
multiply_ten_numbers

متغیر: مثل تابع از یک یا چند کلمه با حروف کوچک استفاده شود. اگر بیش از یک کلمه است با علامت _ از هم جدا شوند. مثال:

average
j
my_age

کلاس: همه کلمات با حروف بزرگ شروع شوند و بین کلمات نیز هیچ علامتی مثل _ گذاشته نشود. به این سبک نامگذاری pascal case گفته می شود. مثال:

Separate
SeperateNumbers

متد: از یک یا چند کلمه با حروف کوچک استفاده شود. اگر بیش از یک کلمه است با علامت _ از هم جدا شوند. مثال:

clicked
link_hovered

ثابت: همه حروف بزرگ نوشته شوند و اگر بیش از یک کلمه است با علامت _ از هم جدا شوند. مثال:

PI
CELSIUS_TO_FAHRENHEIT

ماژول: از یک یا چند کلمه با حروف کوچک استفاده شود. اگر بیش از یک کلمه است با علامت _ از هم جدا شوند. مثال:

algebra.py
basic_algebra.py

پکیج: از یک یا چند کلمه با حروف کوچک استفاده شود و بین کلمات نیز هیچ علامتی مثل _ گذاشته نشود. مثال:

accounting
advancedaccounting

چگونه نام ها را انتخاب کنیم؟

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

هنگام نام‌گذاری متغیرها، ممکن است وسوسه شوید که نام‌های کوچک تک حرفی مانند a را انتخاب کنید. اما مشخص نیست که a  نشان دهنده چیست؟ به مثال های زیر توجه کنید:

a = “Karakit”
website_name = ”Karakit”

اگر شخص دیگری کد شما را بخواند یا چند ماه بعد خودتان به کد مراجعه کنید قطعا با دیدن متغیر دوم به سرعت متوجه خواهید شد که این متغیر چه نقشی در برنامه شما ایفا خواهد کرد.

همچنین از مخفف عبارات نیز نباید برای نام گذاری اشیا استفاده کرد. به طور مثال تابع زیر برای میانگین گرفتن از 2 عدد نام گذاری شده است:

def avg(a,b):
	return((a+b)/2)
def average_two_numbers(a,b):
	return((a+b)/2)

چیدمان کد

نحوه چیدمان کد نقش مهمی در خوانایی آن دارد. در این بخش، در مورد اینکه چگونه فضای سفید عمودی را برای بهبود خوانایی کد خود اضافه کنیم صحبت خواهیم کرد و همچنین خواهیم دید که که چگونه محدودیت خط 79 کاراکتری توصیه شده در PEP 8 را مدیریت کنیم.

خطوط خالی

فضای خالی عمودی یا خطوط خالی می تواند تا حد زیادی خوانایی کد شما را بهبود بخشد. خواندن کدهایی که بدون فاصله عمودی نوشته شده اند ممکن است کار سختی باشد. به طور مشابه، خطوط خالی بیش از حد در کد شما باعث می شود که پراکنده به نظر برسد، و خواننده ممکن است نیاز به پیمایش بیش از حد لازم داشته باشد. در زیر سه دستورالعمل کلیدی در مورد نحوه استفاده از فضای سفید عمودی آورده شده است.

توابع و کلاس های سطح بالا را با دو خط خالی فاصله گذاری کنید. توابع و کلاس های سطح بالا باید نسبتاً مستقل باشند و عملکردهای جداگانه ای را انجام دهند. بنابراین منطقی است که فضای عمودی اضافی در اطراف آنها قرار دهید، به طوری که مشخص شود که آنها از هم جدا هستند:

class ImportantClass:
	pass

class VeryImportantClass:
	pass

def important_function():
	return None

بین تعریف متدهای داخل کلاس ها یک خط خالی می گذاریم. مثال:

def MyClass:
    def method_one(self):
        return None

    def method_two(self):
        return None

از خطوط خالی در داخل توابع استفاده می کنیم تا مراحل از هم تفکیک شوند. گاهی اوقات، یک تابع پیچیده باید چندین مرحله را قبل از دستور return اجرا کند. برای کمک به خواننده در درک منطق داخل تابع، گذاشتن یک خط خالی بین هر مرحله می تواند مفید باشد. مثال:

def my_function():
	print(“step1 – line1”)
	print(“step1 – line2”)
	print(“step1 – line3”)

	print(“step2 – line1”)
	print(“step2 – line2”)
	print(“step2 – line3”)

	print(“step3 – line1”)
	print(“step3 – line2”)
	print(“step3 – line3”)

	return None

حداکثر طول خط و شکستن خط

8 پیشنهاد می کند که طول هر خط باید به 79 کاراکتر محدود شوند. چرا که به شما این امکان را می دهد که اگر چندین فایل را در کنار یکدیگر در محیط برنامه نویسی باز کنید، خطوط به هم نریزند و شکسته نشوند.

البته نگه داشتن خطوط تا 79 کاراکتر یا کمتر همیشه امکان پذیر نیست. پس PEP 8 راه هایی را ارایه می کند که به عبارات اجازه می دهد در چندین خط اجرا شوند.

اگر کد در داخل پرانتز، براکت یا کروشه باشد پایتون خط بعد را نیز در ادامه خط فعلی در نظر می گیرد. مثال:

Countries_data.append({
    			'Name': ‘Iran’
    			'Currency' : ‘Rial’
    			'Population' : 80000000
 			})

اگر استفاده از روش قبل ممکن نباشد، می توان به جای آن از بک اسلش \ برای شکستن خطوط استفاده نمود:

from mypackage import part1 \
	part2 , part3

اگر نیاز به شکستن خط در اطراف عملگرها، مانند + و * باشد، باید قبل از عملگر شکست رخ دهد. این قانون از ریاضیات سرچشمه می گیرد. ریاضیدانان موافق هستند که شکستن قبل از عملگرها خوانایی را بهبود می بخشد.

name = (first_name
	+ last_name)

تورفتگی یا indent

تورفتگی یا indent در پایتون بسیار مهم است. سطح تورفتگی خطوط کد در پایتون تعیین می کند که چگونه عبارات با هم گروه بندی می شوند. این مثال را ببینید:

def example_function():
	print(“this line is located inside the function.”)
print(“this line is located outside the function.”)

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

قوانین اصلی تورفتگی که توسط PEP 8 ارائه شده است به شرح زیر است:

از 4 اسپیس متوالی برای نشان دادن تورفتگی استفاده کنید.

به جای Tab از اسپیس استفاده کنید.

تورفتگی در مورد خطوط شکسته

مثال زیر را ببینید:

Countries_data.append({
    			'Name': ‘Iran’
    			'Currency' : ‘Rial’
    			'Population' : 80000000
 			})

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

در این مورد یک استثنا وجود دارد. اگر دستور if داشته باشیم و شرط داخل آن شکسته باشد بلاک if را باید به نحوی از خط شرط جدا کرد. برای این کار چند روش پیشنهاد شده است.

اولین روش این است که  بلاک if  را توسط یک خط کامنت از خط شرط جدا کرد. می توانید مثال زیر را برای روشن شدن موضوع مشاهده نمایید:

if (condition1 or
     condition2):
    #insert some comment to separate the conditions and the code block
    Print(‘Ok’)

روش دیگر در مورد if این است که در ابتدای خط شکسته یک تورفتگی اضافه ایجاد کنیم. مانند این مثال:

if (condition1 or
     	condition2):
    Print(‘Ok’)

یک روش دیگر برای تورفتگی خطوط شکسته این است که همه خطوط به جز خط اول را به اندازه 1 تورفتگی داخل ببریم:

average = average_two_numbers(
	num_one, num_two)

به این روش تورفتگی آویزان hanging indent می گویند.

وقتی که از این تو رفتگی موقع معرفی تابع با خط شکسته استفاده می کنیم بهتر است که خطوط شکسته بعد از خط اول را با دو تورفتگی از خطوط بعدی متمایز کنیم:

def average_two_numbers(
		first_number,
		second_number)
	return((first_number + second_number)/2)

بستن براکت

شکستن خطوط به ما این امکان را می دهد که خطوط داخل پرانتز، براکت یا پرانتز را در چند خط نمایش دهیم. اما مهم است که براکت را در جایی معقول ببندیم. در غیر این صورت باعث سردرگمی خواننده می شود. PEP 8 دو گزینه برای موقعیت بسته شدن براکت ارائه می دهد:

یکی اینکه براکت را زیر اولین کاراکتر غیر اسپیس آخرین خط قرار دهیم:

employee_salaris = [
	57000000, 78500000,
	65800000, 89000000,
	]

 یا اینکه براکت را با اولین کاراکتر خطی که ساختار را شروع می کند، هم تراز کنیم:

employee_salaris = [
	57000000, 78500000,
	65800000, 89000000,
]

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

کامنت ها

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

در اینجا برخی از نکات کلیدی که باید هنگام اضافه کردن کامنت ها به کد خود بخاطر بسپارید آورده شده است:

طول خط کامنت ها را به 72 کاراکتر محدود کنید.

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

اگر کد خود را تغییر دادید، حتما کامنت ها را به روز کنید.

بلاک کامنت

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

PEP 8 قوانین زیر را برای نوشتن بلاک های کامنت ارائه می کند:

تورفتگی کامنت‌ها را در همان سطح کدی که توضیح می‌دهند، قرار دهید.

هر خط را با یک # و سپس یک فاصله شروع کنید.

پاراگراف ها را با یک خط حاوی یک # جدا کنید.

مثال:

def average_two_numbers(first_number, second_number)
	# This code take 2 numbers
	# It calculates the sum of 2 numbers
	# Divide the summation on 2
	#
	# The function returns the average as result  
	return((first_number + second_number)/2)

کامنت های درون خطی

کامنت های درون خطی یک خط از کد را توضیح می دهند. آنها برای یادآوری یا توضیح به دیگران مفید هستند که چرا خط خاصی از کد ضروری است. در اینجا نکاتی که PEP 8 در مورد آنها توصیه می کند ارایه شده است:

از کامنت های درون خطی کمتر استفاده کنید.

کامنت های درون خطی را در همان سطر عبارتی که به آن اشاره می کنند بنویسید.

کامنت های درون خطی را با دو یا چند فاصله از عبارت جدا کنید.

کامنت های درون خطی را با یک # و یک فاصله شروع کنید.

از آنها برای توضیح بدیهیات استفاده نکنید.

average = round (a + b + c)/3 , 2)   # The average of 3 numbers is calculated and rounded to 2 digits

رشته های مستندات یا docstrings

رشته‌های مستندات، یا docstrings، رشته‌هایی هستند که در علامت‌های نقل قول دوتایی (“””) یا تکی (”’) قرار دارند که در خط اول هر تابع، کلاس، متد یا ماژول ظاهر می‌شوند. می‌توانید از آنها برای توضیح و مستندسازی استفاده کنید.

مهمترین قوانینی که برای docstrings اعمال می شود به شرح زیر است:

رشته‌های مستند را داخل سه نقل قول دوتایی در دو طرف، مانند “””explanations””  قرار دهید.

آنها را برای همه ماژول ها، توابع، کلاس ها و متدهای عمومی بنویسید.

“”” را که به یک رشته مستند چند خطی پایان می دهد به تنهایی روی یک خط قرار دهید.

برای رشته های مستند یک خطی، “”” را در همان خط قرار دهید.

مثال از docstring چند خطی:

def average_two_numbers(first_number, second_number)
	“”” this function calculates the average of two given numbers.
This code takes 2 numbers.
	It calculates the sum of 2 numbers and divide the summation on 2.
	
	 The function returns the average as result.
	“””
	return((first_number + second_number)/2)

مثال از docstring تک خطی:

def average_two_numbers(first_number, second_number)
	“”” this function calculates the average of two given numbers.”””
	return((first_number + second_number)/2)

اسپیس در عبارات

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

اسپیس در اطراف عملگرها

در دو طرف عملگرهای زیر یک اسپیس قرار می دهیم:

=     +=      -=        ==       !=     >     <       >=       <=       is       is not       not in       and        not        or

مثال:

sum = first_number + second_number

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

average = (first_number+second_number) / 2

در موردی که در شرط if بیش از یک شرط وجود داشته باشد نیز به همین صورت عمل می کنیم:

if  a>0 and b!=0:

در مورد عملگر انتساب = یک استثنا وجود دارد و آن موقعی است که یک مقدار پیش فرض به آرگومان یک تابع اختصاص می دهیم. در این حالت دو طرف = هیچ اسپیسی قرار نمی دهیم. مثال:

def factorial(number=2)

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

my_list[1:5]
my_list[1:3:5]
my_list[j+1 : k+2]
my_list[j+1 : k+2 :]

همان طور که می بینید اگر : در انتها به تنهایی به کار رفته باشد بعد از آن اسپیس نمی گذاریم.

چه زمانی اسپیس نگذاریم

در برخی موارد، افزودن اسپیس می‌تواند خواندن کد را سخت‌تر کند. فضای خالی بیش از حد می تواند کد را بسیار پراکنده و دنبال کردن آن را دشوار کند. PEP 8 مثال های بسیار واضحی را بیان می کند که در آن فضای خالی نامناسب است.

مهمترین مکان برای پرهیز از افزودن اسپیس انتهای یک خط است که به آن اسپیس دنباله دار یا تریلینگ اسپیس می گویند. این کاراکتر نامرئی است و می تواند خطاهایی ایجاد کند که ردیابی آنها دشوار است.

مورد بعدی بلافاصله بعد از باز کردن پرانتز و براکت و کروشه است. این مثال استفاده اشتباه از اسپیس را نشان می دهد:

age = [ 25 , 54 , 39 , 41 ]

همچنین قبل از علامت های , و ;  نباید از اسپیس استفاده نمود. این مثال استفاده اشتباه از اسپیس را نشان می دهد:

age = [25  ,  54  ,  39  ,  41]

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

average (2, 3)

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

my_list [4, 5, 8]

بعد از علامت , که قبل از پرانتز بسته شدن پرانتز قرار می گیرد. این مثال استفاده اشتباه از اسپیس را نشان می دهد:

My_tuple(1, 2, 3, )

پیشنهادهای PEP 8 برای برنامه نویسی

اغلب متوجه خواهید شد که چندین راه برای انجام یک عمل مشابه در برنامه نویسی دیگری وجود دارد. در این بخش، برخی از پیشنهاداتی را که PEP 8 برای رفع این ابهام و حفظ ثبات کدنویسی ارائه می کند، مشاهده خواهیم کرد.

با استفاده از عملگر == مقادیر بولی را با True یا False مقایسه نکنید. اغلب باید بررسی کنید که آیا یک مقدار True یا False است. این یک مثال اشتباه است:

my_condition = False
if my_condition == True
	print(‘this is True’)

در زیر نحوه صحیح نوشتن این کد را می بینید:

my_condition = False
if my_condition
	print(‘this is True’)

در پایتون هر لیست، رشته یا تاپل خالی False است. بنابراین برای بررسی خالی بودن یکیاز این موارد نیز می توانیم از روش بالا استفاده کنیم:

my_list = []
if not my_list
	print(‘the list is empty.’)

بسته های اصلاح خودکار کدهای پایتون بر اساس PEP 8

بسته های مختلفی برای اصلاح خودکار کدهای پایتون ارایه شده اند مانند autopep8 ، Black formatter، Ruff و yapf که می توانند شکل صحیح یک کد را بر اساس دستورالعمل های PEP 8 به شما نشان دهند.

در مطالب بعدی نحوه استفاده از این بسته ها را بررسی خواهیم کرد.