خلفية عن لغة Python
الملحق 1 من الفيديو التعليمي - صياغة لغة بايثون: https://singtown.com/learn/50061/
فوائد استخدام بايثون
يمكن لـ OpenMV استخدام Python للتطوير الثانوي. هناك عدة فوائد لذلك:
- سهلة التعلم والبدء بها
- لا حاجة للتفكير في تخصيص الذاكرة وتحريرها
- هناك العديد من مكتبات MicroPython التي يمكن استخدامها مباشرة (وهي غير متوافقة مع وحدات Python على الحاسوب الشخصي)
- قام فريق التطوير بتطوير خوارزميات ووحدات مختلفة يستدعيها OpenMV
بايثون لغة شائعة الاستخدام جدًا، وتُستخدم على نطاق واسع في معالجة الصور، وتعلم الآلة، وبرمجة الشبكات. كما أن بايثون لغة سهلة الاستخدام جدًا. إذا كانت لديك خبرة برمجية بلغات أخرى (مثل C أو ++C أو Java)، فسيكون من الأسهل عليك البدء بها.
إذا كانت لديك خبرة برمجية سابقة بلغة C/C++/Java (أو أي لغة أخرى)، أنصح بـ \ تعليم بايثون لـ Liao Xuefeng
إذا لم تكن لديك أي خبرة برمجية سابقة، يُنصح بـ\ تعلّم بايثون بالطريقة الصعبة
REPL والمنفذ التسلسلي
تأتي بيئة تطوير OpenMV (IDE) مزودة بمساعد منفذ تسلسلي للاتصال بـ OpenMV، ويمكنها أيضًا الاتصال بمنافذ تسلسلية أخرى، مثل Arduino و pyboard و esp8266.
أولًا، افصل OpenMV عن بيئة التطوير، وإلا سيحدث تعارض في المنفذ التسلسلي!
افتح Tools ← Open Terminal ← New Terminal في OpenMV




اكتب في الطرفية
print("hello OpenMV!")
سيظهر
hello OpenMV!
صياغة بايثون
الإخراج
استخدم print() لإضافة نص بين قوسين لإخراج النص المحدد إلى الشاشة. على سبيل المثال، لإخراج 'hello, world'، يكون الكود كما يلي:
print('hello, world')
hello, world
يمكن لدالة print() أيضًا قبول عدة نصوص مفصولة بفواصل ","، ثم يتم ربطها معًا كنص واحد للإخراج:
print('The quick brown fox', 'jumps over', 'the lazy dog')
The quick brown fox jumps over the lazy dog
ستطبع print() كل نص بالتتابع، وسيتم إخراج مسافة عند مصادفة الفاصلة "،"، لذا يُجمَّع النص المُخرَج على النحو التالي:
The quick brown fox jumps over the lazy dog
يمكن لـ print() أيضًا طباعة أعداد صحيحة أو نتائج حسابية:
print(300)
300
print(100 + 200)
300
لذلك يمكننا طباعة نتيجة حساب 100 + 200 بشكل أجمل:
print('100 + 200 =', 100 + 200)
100 + 200 = 300
لاحظ أنه بالنسبة لـ 100 + 200، يقوم مفسر بايثون تلقائيًا بحساب النتيجة 300، لكن '100 + 200 =' هو نص وليس معادلة رياضية، وتتعامل بايثون معه كنص.
المتغيرات
في بايثون، علامة المساواة = هي جملة إسناد، يمكنها إسناد أي نوع بيانات إلى متغير. يمكن إسناد قيمة جديدة إلى نفس المتغير بشكل متكرر، ويمكن أن تكون من أنواع مختلفة، على سبيل المثال:
a = 123 # a رقم صحيح
print(a)
a = 'ABC' # a أصبح نصًا (string)
print(a)
تُسمى اللغة التي لا يكون فيها نوع المتغير ثابتًا بلغة ديناميكية، ونقيضها اللغة الساكنة (Static). يجب على اللغات الساكنة تحديد نوع المتغير عند تعريفه. إذا لم يتطابق النوع عند الإسناد، سيتم الإبلاغ عن خطأ. على سبيل المثال، Java لغة ساكنة، وجملة الإسناد فيها كما يلي (// تشير إلى تعليق):
int a = 123; // a متغير من نوع رقم صحيح
a = "ABC"; // خطأ: لا يمكن إسناد نص إلى متغير من نوع رقم صحيح
مقارنةً باللغات الساكنة، اللغات الديناميكية أكثر مرونة، ولهذا السبب.
القائمة (List)
أحد أنواع البيانات المدمجة في بايثون هو القائمة: list. القائمة هي مجموعة مرتبة يمكن إضافة عناصر إليها وحذفها منها في أي وقت.\ على سبيل المثال، لسرد أسماء جميع الزملاء في الصف، يمكنك استخدام قائمة لتمثيل ذلك:
classmates = ['Michael', 'Bob', 'Tracy']
classmates
['Michael', 'Bob', 'Tracy']
المتغير classmates هو قائمة. استخدم الدالة len() للحصول على عدد عناصر القائمة:
len(classmates)
3
استخدم الفهرس (index) للوصول إلى العنصر في كل موضع في القائمة. تذكّر أن الفهرس يبدأ من 0:
classmates[0]
'Michael'
classmates[1]
'Bob'
classmates[2]
'Tracy'
classmates[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
عندما يكون الفهرس خارج النطاق، ستُبلغ بايثون عن خطأ IndexError، لذا تأكد من أن الفهرس لا يتجاوز الحدود. تذكّر أن فهرس العنصر الأخير هو len(classmates) - 1.
إذا كنت تريد الحصول على العنصر الأخير، بالإضافة إلى حساب موضع الفهرس، يمكنك أيضًا استخدام -1 كفهرس للحصول على العنصر الأخير مباشرة:
classmates[-1]
'Tracy'
وبالمثل، يمكنك الحصول على العنصر قبل الأخير والعنصر الذي قبله:
classmates[-2]
'Bob'
classmates[-3]
'Michael'
classmates[-4]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
بالطبع، العنصر الرابع من النهاية خارج النطاق.
القائمة عبارة عن قائمة مرتبة قابلة للتعديل، لذا يمكنك إضافة عناصر إلى نهاية القائمة:
classmates.append('Adam')
classmates
['Michael', 'Bob', 'Tracy', 'Adam']
يمكنك أيضًا إدراج عناصر في موضع محدد، مثل الفهرس 1:
classmates.insert(1, 'Jack')
classmates
['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']
لحذف عنصر من نهاية القائمة، استخدم الطريقة pop():
classmates.pop()
'Adam'
classmates
['Michael', 'Jack', 'Bob', 'Tracy']
لاستبدال عنصر بعنصر آخر، يمكنك إسناد القيمة مباشرة إلى موضع الفهرس المقابل:
classmates[1] = 'Sarah'
classmates
['Michael', 'Sarah', 'Tracy']
يمكن أيضًا أن تكون أنواع بيانات عناصر القائمة مختلفة، على سبيل المثال:
L = ['Apple', 123, True]
إذا لم تحتوِ القائمة على أي عناصر، فهي قائمة فارغة طولها 0:
L = []
len(L)
0
الصف (Tuple)
هناك نوع آخر من القوائم المرتبة يسمى الصف (tuple). الصفوف تشبه القوائم كثيرًا، لكن بمجرد تهيئة الصف، لا يمكن تعديله. على سبيل المثال، لسرد أسماء الزملاء أيضًا:
classmates = ('Michael', 'Bob', 'Tracy')
الآن، لا يمكن تغيير الصف classmates، وليس لديه طرق مثل append() و insert(). الطرق الأخرى للحصول على العناصر هي نفسها كما في القوائم. يمكنك استخدام classmates[0] و classmates[-1] بشكل طبيعي، لكن لا يمكنك إسناد قيم إلى عناصر أخرى فيه.
ما هي أهمية كون الصفوف غير قابلة للتعديل؟ لأن الصفوف غير قابلة للتعديل، يكون الكود أكثر أمانًا. إن أمكن، استخدم الصفوف بدلًا من القوائم.
فخ الصفوف: عند تعريف صف، يجب تحديد عناصره وقت التعريف، على سبيل المثال:
t = (1, 2)
t
(1, 2)
ومع ذلك، لتعريف صف بعنصر واحد فقط، إذا عرّفته على هذا النحو:
t = (1)
t
1
هذا التعريف ليس صفًا، بل t متغير من نوع رقم صحيح، وقيمة المتغير t هي 1! وذلك لأن الأقواس () يمكن أن تمثل الصفوف وكذلك الأقواس في المعادلات الرياضية، مما يخلق غموضًا. لذلك، تنص بايثون على أنه في هذه الحالة، يتم إجراء الحساب وفقًا للأقواس الرياضية، والنتيجة الطبيعية هي 1.
لذلك، يجب إضافة فاصلة , عند تعريف صف بعنصر واحد فقط لإزالة الغموض:
t = (1,)
t
(1,)
تضيف بايثون أيضًا فاصلة , عند عرض صف بعنصر واحد فقط، حتى لا تفهمه خطأً على أنه قوس بالمعنى الرياضي.
جملة الشرط (Conditional judgment)
الصيغة الكاملة لجملة if هي:
if <شرط1>:
<تنفيذ1>
elif <شرط2>:
<تنفيذ2>
elif <شرط3>:
<تنفيذ3>
else:
<تنفيذ4>
على سبيل المثال:
age = 20
if age >= 6:
print('teenager')
elif age >= 18:
print('adult')
else:
print('kid')
الحلقات (Loop)
تحتوي بايثون على نوعين من الحلقات. الأول هو حلقة for...in، التي تتنقل بين كل عنصر في القائمة أو الصف بالتتابع. انظر المثال:
names = ['Michael', 'Bob', 'Tracy']
for name in names:
print(name)
سيؤدي تنفيذ هذا الكود إلى طباعة كل عنصر من names بالتتابع:
Michael
Bob
Tracy
إذًا حلقة for x in ... تُدخل كل عنصر في المتغير x، ثم تنفذ الجمل الموجودة في الكتلة المُزاحة (indented).
إذا أردت حساب مجموع الأعداد الصحيحة من 1 إلى 100، فمن الصعب نوعًا ما كتابتها من 1 إلى 100. لحسن الحظ، توفر بايثون دالة range() يمكنها توليد سلسلة من الأعداد الصحيحة، والتي يمكن تحويلها إلى قائمة عبر دالة list(). على سبيل المثال، تولّد range(5) سلسلة من الأعداد الصحيحة الأقل من 5 بدءًا من 0:
list(range(5))
[0, 1, 2, 3, 4]
يمكن لـ range(101) توليد سلسلة من الأعداد الصحيحة من 0 إلى 100، والحساب كما يلي:
sum = 0
for x in range(101):
sum = sum + x
print(sum)
الحلقة الثانية هي حلقة while. على سبيل المثال، إذا أردنا حساب مجموع جميع الأعداد الفردية ضمن 100، يمكننا استخدام حلقة while لتنفيذ ذلك:
sum = 0
n = 99
while n > 0:
sum = sum + n
n = n - 2
print(sum)
===== تحويل أنواع البيانات =====
تشمل دوال بايثون المدمجة الشائعة أيضًا دوال تحويل أنواع البيانات، مثل دالة int()، التي يمكنها تحويل أنواع بيانات أخرى إلى أعداد صحيحة:
>>> int('123')
123
>>> int(12.34)
12
>>> float('12.34')
12.34
>>> str(1.23)
'1.23'
>>> str(100)
'100'
>>> bool(1)
True
>>> bool('')
False
===== الدوال (Function) =====
في بايثون، لتعريف دالة، تحتاج إلى استخدام جملة def، وكتابة اسم الدالة، والأقواس، والمعاملات داخل الأقواس، ونقطتين رأسيتين بالترتيب، ثم كتابة جسم الدالة في كتلة مُزاحة، وإرجاع النتيجة بجملة return.
لنكتب أولًا دالة لحساب x2:
def power(x):
return x * x
بالنسبة لدالة power(x)، المعامل x هو معامل موضعي (positional parameter).
عند استدعاء دالة power، يجب علينا تمرير معامل واحد فقط وهو x:
power(5)\ 25\ power(15)\ 225
الآن، ماذا لو أردنا حساب x3؟ يمكننا تعريف دالة أخرى باسم power3، لكن ماذا لو أردنا حساب x4 وx5 وما إلى ذلك؟ لا يمكننا تعريف عدد لا نهائي من الدوال.
ربما فكرت في أنه يمكننا تعديل power(x) لتصبح power(x, n) لحساب xn، فلنفعل ذلك فورًا:
def power(x, n):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
بالنسبة لدالة power(x, n) المعدَّلة هذه، يمكننا حساب أي قوة لـ n:
power(5, 2)\ 25\ power(5, 3)\ 125
تحتوي دالة power(x, n) المعدَّلة على معاملين: x و n. كلا المعاملين موضعيان. عند استدعاء الدالة، يتم إسناد القيمتين المُمررتين إلى المعاملين x و n حسب ترتيب الموضع.
التقطيع (Slicing)
أخذ جزء من قائمة أو صف عملية شائعة جدًا. على سبيل المثال، لدينا القائمة التالية:
L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
خذ أول 3 عناصر وقطّعها بسطر واحد من الكود:
L[0:3]\ ['Michael', 'Sarah', 'Tracy']
تعني L[0:3] البدء من الفهرس 0 والانتهاء عند الفهرس 3، دون تضمين الفهرس 3. أي أن الفهارس 0 و1 و2 هي بالضبط 3 عناصر.
إذا كان الفهرس الأول 0، يمكن حذفه:
L[:3]\ ['Michael', 'Sarah', 'Tracy']
يمكنك أيضًا البدء من الفهرس 1 وأخذ عنصرين:
L[1:3]\ ['Sarah', 'Tracy']
الصف (Tuple) هو أيضًا نوع من أنواع القوائم، والفرق الوحيد هو أن الصف غير قابل للتعديل. لذلك، يمكن أيضًا تطبيق التقطيع على الصفوف، لكن نتيجة العملية تبقى صفًا:
(0, 1, 2, 3, 4, 5)[:3]\ (0, 1, 2)
يمكن أيضًا اعتبار النص 'xxx' قائمة، وكل عنصر فيه حرف. لذلك، يمكن أيضًا تطبيق التقطيع على النصوص، لكن نتيجة العملية تبقى نصًا:
'ABCDEFG'[:3]\ 'ABC'
الكائنات (Object)
بايثون لغة برمجة كائنية التوجه (object-oriented)، مثل مصباح LED
from pyb import LED
red_led = LED(1)
red_led.on()
LED هو صنف (class)، وred_led هو كائن (object)، ويمكن التعامل مع هذا الكائن، مثل تشغيله وإيقافه والتحقق من قيمته.