كيفية كتابة كود بايثون نظيف Python Clean Code
في هذا المقال سأقدم بعض الإرشادات وأفضل الممارسات حول كيفية كتابة كود بايثون نظيف وجميل, لكن مهلاًماذا تعني بكود نظيف ؟
الكود النظيف أو Clean Code باختصار هو كتابة شفرة برمجية منسّقة ومنظّمة وعلى اسس منطقية, قد تسأل نفسك لماذا يجب علي كتابة كود نظيف مادام الكمبيوتر لا يفهم سوى الصفر والواحد ولن يرى جمال الكود ولا تنسيقه, اذن :
لماذا هذا الاهتمام بتنظيم الكود و قابلية القراءة ؟
كما قال جايدو ڤان روسم (Guido van Rossum) هو مبرمج هولندي يُعرف بأنه مبتكر لغة البرمجة بايثون، "تتم قراءة الكود أكثر مما هو مكتوب" ويعني بذلك أنه يمكنك قضاء بضع دقائق ، أو يوم كامل ، في كتابة جزء من التعليمات البرمجية لمعالجة تسجيل الدخول لمستخدم. وبمجرد كتابتها ، لن تكتبها مرة أخرى. ولكن عليك بالتأكيد قراءتها مرة أخرى.
قد تبقى هذه الشفرة جزءًا من مشروع تعمل عليه. في كل مرة تعود فيها إلى هذا الملف ، عليك أن تتذكر ما يفعله هذا الكود وسبب كتابته ، لذا فإن قابلية القراءة مهمة.
- إذا كنت جديدًا في بايثون، فقد يكون من الصعب تذكر ما تفعله إحدى التعليمات البرمجية خلال بضعة أيام أو أسابيع من كتابته.يجب أن تعرف أن أغلب المشاريع بدأت صغيرة ثم بدأت تكبر وتتطور بفضل تعدد المبرمجين والمطورين وتعاونهم, فربما تكتب الان برنامج ثم ترفعه على موقع جيت هب Github فيقوم بتحميله مبرمج اخر لغرض تطويره واضافة ميزات اخرى للبرنامج, ولكن لسوء الحظ يجد هذا المبرمج أن برنامجك تمت كتابته بطريقة غير منظمة وغير مفهومة وسيقضي وقت كبير في فهم المتغيرات اوالدوال التي كتبتها, لكن في أغلب الأحيان يفضل هذا المطور إعادة بناء المشروع من الصفر على القيام بالتعديل عليه وتضييع وقته.
ما هي العوامل التي يجب عليك مراعتها لكتابة كود نظيف؟
اتفاقية التسمية Naming Conventions
اختيار أسماء منطقية ومعقولة سيوفر عليك الوقت والجهد في وقت لاحق لأنك ستتمكن من معرفة ما يمثله متغير معين أو وظيفة أو فئة معينة بمجرد قراءة الاسم. كما ستتجنب استخدام أسماء غير لائقة inappropriate قد تؤدي إلى أخطاء يصعب تصحيحها في المستقبل. سأعطيك مثالا:
لاحظ هذه الشفرة البرمجية:O = 2 # قد يبدو هذا وكأنك تحاول اسناد قيمة 2 إلى صفر
يوضح الجدول أدناه بعض أنماط التسمية الشائعة في كود Python ، وحين يجب عليك استخدامها:
أنماط التسمية Naming Styles
النوع | الاتفاقية | أمثلة |
---|---|---|
Function الوظيفة |
استخدم كلمة أو كلمات صغيرة. افصل الكلمات باستخدام شرطات سفلية لتحسين القراءة. |
function , my_function
|
Variable متغير |
استخدم حرفًا واحدًا صغيرًا أو كلمة أو كلمات. افصل الكلمات مع الشرطات السفلية لتحسين قابلية القراءة. |
x , var , my_variable
|
Class الفئة |
ابدأ كل كلمة بحرف كبير. لا تفصل بين الكلمات والشرطات السفلية. هذا النمط يدعى حالة الجمل Camelcase |
Model , MyClass
|
Method الطريقة |
استخدم كلمة أو كلمات صغيرة. افصل الكلمات مع الشرطات السفلية لتحسين قابلية القراءة. |
class_method , method
|
Constant الثابت |
استخدم حرفًا واحدًا كبيرًا أو كلمة أو كلمات. افصل الكلمات مع الشرطات السفلية لتحسين قابلية القراءة. |
CONSTANT , MY_CONSTANT ,MY_LONG_CONSTANT
|
Module الوحدة |
استخدم كلمة أو كلمات قصيرة أو صغيرة. افصل الكلمات مع الشرطات السفلية لتحسين قابلية القراءة. |
module.py , my_module.py
|
Package الحزم |
استخدم كلمة أو كلمات قصيرة أو صغيرة. لا تفصل بين الكلمات والشرطات السفلية. |
package , mypackage
|
هذه بعض من اصطلاحات التسمية الشائعة وأمثلة حول كيفية استخدامها. ولكن لكتابة رمز قابل للقراءة ، لا يزال يتعين عليك توخي الحذر مع اختيارك للحروف والكلمات. بالإضافة إلى اختيار أنماط التسمية الصحيحة في شفرتك ، يجب عليك أيضًا اختيار الأسماء بعناية. فيما يلي بعض المؤشرات حول كيفية القيام بذلك بأكبر قدر ممكن من الفعالية.
كيفية اختيار الأسماء
عند تسمية المتغيرات ، قد يميل المبرمج لاختيار أسماء صغيرة وبسيطة من حرف واحد ، مثل x. ولكن ما لم تستخدم x كدالة رياضية ونحوها ، فليس من الواضح اذا ما الذي يمثله حرف x !. تخيل أنك تقوم بتخزين اسم شخص كسلسلة ، وتريد استخدام تقطيع السلسلة لتنسيق اسم الشخص بشكل مختلف. لنرى هذا المثال:
>>> x = 'Cortex Hacker'
>>> y ، z = x . split ()
>>> print ( z ، y ، sep = '،' )
'Hacker، Cortex'
>>> # مستحسن
>>> name = 'Cortex Hacker'
>>> first_name ، last_name = name . split ()
>>> print ( last_name ، first_name ، sep = '،' )
'Hacker، Cortex'
الاختصارات
# غير مستحسن
def mp ( x ):
return x * 2
# مستحسن
def multiply_by_two(x):
return x * 2
تخطيط التعليمات البرمجية Code Layout
الأسطر الفارغة Blank Lines
- تحيط وظائف وفئات المستوى الأعلى مع سطرين فارغين.
- يجب أن تكون الوظائف والفئات ذات المستوى الأعلى قائمة بذاتها تمامًا وتتعامل مع وظائف منفصلة.
- الافضل ترك مسافة عمودية حولها ، بحيث يكون واضحًا أن الوظائف مستقلة فيما بينها.
class MyFirstClass :
pass
class MySecondClass :
pass
def top_level_function ():
return None
class MyClass:
def first_method(self):
return None
def second_method(self):
return None
def calculate_variance(number_list):
sum_list = 0
for number in number_list:
sum_list = sum_list + number
mean = sum_list / len(number_list)
sum_squares = 0
for number in number_list:
sum_squares = sum_squares + number**2
mean_squares = sum_squares / len(number_list)
return mean_squares - mean**2
الحد الأقصى لطول السطر وتقسيم الاسطر:
def function(arg_one, arg_two,
arg_three, arg_four):
return arg_one
from mypkg import example1, \
example2, example3
total = (first_variable + second_variable - third_variable)
total = (first_variable +
second_variable -
third_variable)
# مستحسن
total = (first_variable
+ second_variable
- third_variable)
المسافة البادئة Indentation :
x = 3
if x > 5:
print('x is larger than 5')
- استخدم 4 مسافات متتالية للإشارة إلى المسافة البادئة.
- يفضل استخدام المسافات بدلاً من استخدام علامة التبويب TAB.
مسافة التعليق hanging indent
# غير مستحسن
var = function(arg_one, arg_two,
arg_three, arg_four)
# مستحسن
var = function(
arg_one, arg_two,
arg_three, arg_four)
# غير مستحسن
def function(
arg_one, arg_two,
arg_three, arg_four):
return arg_one
def function(
arg_one, arg_two,
arg_three, arg_four):
return arg_one
كيفية اغلاق الأقواس:
list_of_numbers = [
1 ، 2 ، 3 ،
4 ، 5 ، 6 ،
7 ، 8 ، 9
]
list_of_numbers = [
1 ، 2 ، 3 ،
4 ، 5 ، 6 ،
7 ، 8 ، 9
]
التعليقات Comments
- الحد من طول خط التعليقات و docstrings إلى 72 حرفًا.
- استخدم جمل كاملة ، تبدأ بحرف كبير.
- تأكد من تحديث التعليقات إذا قمت بتغيير شفرتك.
كتلة التعليقات Block Comments
- ضع تعليقات كتلة بادئة على نفس مستوى الكود البرمجي الذي يصفونه.
- ابدأ كل سطر # متبوعًا بمسافة واحدة.
- افصل بين الفقرات بخط يحتوي على مفردة #.
for i in range(0, 10):
# Loop over i ten times and print out the value of i, followed by a
# new line character
print(i, '\n')
def quadratic(a, b, c, x):
# Calculate the solution to a quadratic equation using the quadratic
# formula.
#
# There are always two solutions to a quadratic equation, x_1 and x_2.
x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a)
x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a)
return x_1, x_2
تعليقات مضمنة Inline Comments
- لا تبالغ في استخدام التعليقات المضمنة, استخدمها باعتدال.
- اكتب التعليقات المضمنة على نفس السطر الذي تشير إليه العبارة المراد ايضاحها.
- تعليقات مضمنة منفصلة بمساحات أو أكثر من العبارات Statements.
- ابدأ التعليقات المضمنة # بمساحة واحدة ، مثل تعليقات الحظر.
- لا تستخدمها لشرح ما هو بديهي.
x = 5 # هذا تعليق داخلي
empty_list = [] # Initialize empty list
x = 5
x = x * 5 # Multiply x by 5
سلاسل التوثيق Documentation Strings
- تحيط بثلاث علامات اقتباس مزدوجة على جانبيها ، كما هو الحال في """This is a docstring""".
- اكتبها لجميع الوحدات العامة والوظائف والطرق.
- ضع """ تلك النهاية docstring متعدد الأسطر على سطر بنفسها:
def quadratic(a, b, c, x):
"""Solve quadratic equation via the quadratic formula.
A quadratic equation has the following form:
ax**2 + bx + c = 0
There always two solutions to a quadratic equation: x_1 & x_2.
"""
x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a)
x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a)
return x_1, x_2
def quadratic(a, b, c, x):
"""Use the quadratic formula"""
x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a)
x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a)
return x_1, x_2
الفراغ في التعبيرات والبيانات
المسافات والمعاملات المنطقية
- معاملات الاسناد ( =، +=، -=، الخ)
- المقارنات ( ==، !=، >، <. >=، <=) و ( is، is not، in، not in)
- العبارة البوليانية ( and، not، or)
# مستحسن
def function(default_parameter=5):
# ...
# غير مستحسن
def function(default_parameter = 5):
# ...
# مستحسن
y = x**2 + 5
z = (x+y) * (x-y)
# غير مستحسن
y = x ** 2 + 5
z = (x + y) * (x - y)
# غير مستحسن
if x > 5 and x % 2 == 0:
print('x is larger than 5 and divisible by 2!')
# مستحسن
if x>5 and x%2==0:
print('x is larger than 5 and divisible by 2!')
# لا تستخدمها ابدا
if x >5 and x% 2== 0:
print('x is larger than 5 and divisible by 2!')
متى يجب تجنب الفراغ
# مستحسن
my_list = [1, 2, 3]
# غير مستحسن
my_list = [ 1, 2, 3, ]
x = 5
y = 6
# مستحسن
print(x, y)
# غير مستحسن
print(x , y)
def double ( x ):
return x * 2
# مستحسن
double ( 3 )
# غير مستحسن
double ( 3 )
# مستحسن
list[3]
# غير مستحسن
list [3]
# مستحسن
tuple = (1,)
# غير مستحسن
tuple = (1, )
# مستحسن
var1 = 5
var2 = 6
some_long_var = 7
# غير مستحسن
var1 = 5
var2 = 6
some_long_var = 7
توصيات وممارسات في البرمجة
# غير مستحسن
my_bool = 6 > 5
if my_bool == True:
return '6 is bigger than 5'
# مستحسن
if my_bool:
return '6 is bigger than 5'
# غير مستحسن
my_list = []
if not len(my_list):
print('List is empty!')
# مستحسن
my_list = []
if not my_list:
print('List is empty!')
# مستحسن
if x is not None:
return 'x exists!'
# غير مستحسن
if not x is None:
return 'x exists!'
# غير مستحسن
if arg :
# Do something with arg ...
# مستحسن
if arg is not None:
# Do something with arg...
# غير مستحسن
if word[:3] == 'cat':
print('The word starts with "cat"')
# مستحسن
if word.startswith('cat'):
print('The word starts with "cat"')
# غير مستحسن
if file_name[-3:] == 'jpg':
print('The file is a JPEG')
# مستحسنif file_name.endswith('jpg'): print('The file is a JPEG')