این حالت نمایش چند صفحه ای قابل پرینت این قسمت می‌باشد. برای پرینت کلیک کنید..

بازگشت به حالت نمایش عادی این قسمت.

کار کردن با لیست‌ها

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

1 - حلقه زدن در کل یک لیست

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

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

اکنون از حلقه‌ی for برای چاپ کردن تک‌تک نام‌ها در لیست شعبده‌بازها استفاده می‌کنیم:

1
2
3
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(magician)

در خط ۱ همانند کاری که در فصل سوم کردیم، از تعریف یک لیست شروع می‌کنیم. در خط ۲ یک حلقه‌ی for تعریف می‌کنیم. این خط از پایتون می‌خواهد تا یک نام را از لیست magicians بیرون کشیده و آن را به متغیّر magician نسبت دهد. در خط ۳ به پایتون می‌گوییم که نامی را که هم‌اکنون به magician نسبت داده چاپ کند. پایتون سپس خط‌های ۲ و ۳ را برای تمام نام‌های داخل لیست تکرار می‌کند. شاید خواندن این کد به این صورت برای شما سودمند باشد: «برای هر شعبده‌باز در لیست شعبده‌بازها، نام شعبده‌باز را چاپ کن.» در خروجی به سادگی چاپ شدن هر نام موجود در لیست را خواهیم دید:

1
2
3
alice
david
carolina

نگاهی نزدیک‌تر به حلقه‌زدن

مفهوم حلقه زدن بسیار مهم است زیرا یکی از معمول‌ترین راه‌ها برای خودکارسازی وظایف تکراری با رایانه است. به عنوان یک مثال در حلقه‌ی ساده‌ای که در magicians.py به کار بردیم، پایتون ابتدا اوّلین خط حلقه را می‌خواند:

1
for magician in magicians:

این خط به پایتون می‌گوید که اوّلین مقدار را از لیست magicians بیرون بکشد و آن را به متغیّر magician نسبت بدهد. اوّلین مقدار ‘alice’ است. پایتون سپس خط بعدی را می‌خواند:

1
print(magician)

پایتون مقدار فعلی magician را که همچنان ‘alice’ است چاپ می‌کند. از آن‌جایی که لیست مقادیر دیگری را نیز دربرمی‌گیرد، پایتون به اوّلین خط حلقه بازمی‌گردد:

1
for magician in magicians:

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

1
print(magician)

پایتون بار دیگر مقدار magician را چاپ می‌کند که الان ‘david’ است و بار دیگر کل حلقه را تا فرارسیدنِ آخرین مقدارِ درون لیست، ‘carolina’، تکرار می‌کند. چون مقدار دیگری در لیست وجود ندارد پایتون به خط بعد از حلقه می‌رود. در این مورد چون بعد از حلقه‌ی for چیزی وجود ندارد برنامه به سادگی پایان می‌یابد.

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

همچنین بدانید که هنگام نوشتن حلقه‌های for، برای متغیّر موقّت حلقه که هر مقدارِ درون لیست به آن منسوب می‌شود، می‌توانید هر اسم دلخواهی را انتخاب کنید. با این حال انتخاب کردن نامی معنادار که بیانگر یک عضو لیست باشد سودمند است. برای مثال راه مناسب برای نوشتن یک حلقه‌ی for برای لیست گربه‌ها، سگ‌ها و یک لیست عمومی از اقلام در اینجا می‌آید:

1
2
3
for cat in cats:
for dog in dogs:
for item in list_of_items:

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

2 - کارهای بیشتر در یک حلقه‌ی for

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

1
2
3
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(f"{magician.title()}, that was a great trick!")

تنها تفاوت این کد در خط ۱ است که در آن پیامی خطاب به هر شعبده‌باز چاپ کردیم که با نام او آغاز می‌شود. در اوّلین گام حلقه مقدار magician برابر با ‘alice’ است پس پایتون اوّلین پیام را برای او چاپ می‌کند. دومین پیام با ‘David’ و سومین مورد با ‘Carolina’ آغاز خواهد شد.

خروجی پیامی شخصی‌شده را برای هر شعبده‌بازِ داخلِ لیست نشان می‌دهد:

1
2
3
Alice, that was a great trick!
David, that was a great trick!
Carolina, that was a great trick!

همچنین می‌توانید هر تعداد خط کد که خواستید در حلقه‌ی for بنویسید. هر خط تورفته که بعد از خط for magician in magicians آمده، داخل حلقه تلقی شده و بر روی هر مقدارِ داخلِ لیست یک بار اجرا می‌شود. در نتیجه می‌توانید هر آن‌چه می‌خواهید با هر کدام از اعضای لیست انجام دهید.

اکنون خط دومی را به پیام خود اضافه می‌کنیم تا به هر شعبده‌باز بگوییم که منتظر شعبده‌ی بعدی او هستیم:

1
2
3
4
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(f"{magician.title()}, that was a great trick!")
    print(f"I can't wait to see your next trick, {magician.title()}.\n")

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

1
2
3
4
5
6
7
8
Alice, that was a great trick!
I can't wait to see your next trick, Alice.

David, that was a great trick!
I can't wait to see your next trick, David.

Carolina, that was a great trick!
I can't wait to see your next trick, Carolina.

به حلقه‌های for خود هر تعداد خط که بخواهید می‌توانید اضافه کنید. در عمل هنگام استفاده از حلقه‌ی for عملیّات متفاوت و متعدّدی را با اعضای لیست انجام می‌دهید.

انجام دادن کاری پس از حلقه‌ی for

درست پس از به پایان رسیدن یک حلقه‌ی for چه اتفاقی می‌افتد؟ معمولاً می‌خواهید که خروجی به دست آمده را خلاصه کنید یا به کار دیگری بپردازید که برنامه باید انجام دهد.

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

1
2
3
4
5
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(f"{magician.title()}, that was a great trick!")
    print(f"I can't wait to see your next trick, {magician.title()}.\n")
print("Thank you, everyone. That was a great magic show!")

چنانکه قبلاً دیدید دو دستور print() نخست، خطاب به هر شعبده‌باز چاپ می‌شود. امّا چون خط ۳ تورفته نیست، تنها یک بار چاپ می‌شود:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Alice, that was a great trick!
I can't wait to see your next trick, Alice.

David, that was a great trick!
I can't wait to see your next trick, David.

Carolina, that was a great trick!
I can't wait to see your next trick, Carolina.

Thank you, everyone. That was a great magic show!

هنگام پردازش اطّلاعات با یک حلقه‌ی for درمی‌یابید که روش خوبی برای خلاصه کردنِ عملیّاتی است که روی کلِّ مجموعه‌ی داده‌ها انجام می‌گیرد. برای مثال فرض کنید از یک حلقه‌ی for برای آماده‌سازی اوّلیّه‌ی یک بازی استفاده می‌کنید به نحوی که با پردازش لیستی از شخصیت‌ها، آن را یکی یکی روی صفحه نمایش می‌دهید. ممکن است پس از حلقه کدی اضافه کنید که پس از نمایشِ تمامِ شخصیت‌های بازی دکمه‌ی Play Now را نشان دهد.

3 - کارهای بیشتر در یک حلقه‌ی for

پایتون از تورفتگی برای تعیین ارتباط یک خط یا گروهی از خط‌ها با دیگر قسمت‌های برنامه استفاده می‌کند. در مثال‌های گذشته خط‌هایی که برای هر شعبده‌باز پیامی جداگانه چاپ کرد جزئی از حلقه‌ی for بودند زیرا آن‌ها را با تورفتگی نوشته بودیم. به‌کاررفتنِ تورفتگی در پایتون خواندنِ کد را بسیار ساده می‌کند و اساساً پایتون از فاصله‌ی خالی استفاده می‌کند تا شما را به نوشتن کدهای مرتّب با ساختار بصری واضح وادار کند. در برنامه‌های طولانی‌تر پایتون به قطعه‌های تورفته‌ی کد با سطح‌های تورفتگی‌های متفاوت برخواهید خورد. این سطوح تورفتگی به شما کمک می‌کند تا احساسی کلّی نسبت به سازمان و ساختار کلّی برنامه پیدا کنید.

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

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

فراموش کردن تورفتگی

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

1
2
3
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(magician)

فراخوانی print() در خط ۳ باید تورفته باشد امّا نیست. هنگامی که پایتون به دنبال خطی تورفته باشد امّا آن را نیابد، به شما می‌گوید که کدام خط چنین مشکلی دارد.

1
2
3
4
File "magicians.py", line 3
    print(magician)
                    ^
IndentationError: expected an indented block

این نوع از خطای تورفتگی را می‌توان با تصحیح خط یا خط‌هایی که بلافاصله بعد از عبارت for آمده‌اند برطرف کرد.

فراموش کردن تورفتگی خط‌های اضافی

گاهی حلقه‌ی شما بدون هیچ خطایی اجرا می‌شود امّا نتیجه‌ی مطلوب را نمی‌گیرید. این گاهی به این دلیل رخ می‌دهد که می‌خواهید چند وظیفه را در یک حلقه انجام دهید امّا فراموش کرده‌اید که برخی از خط‌ها را تورفته کنید.

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

1
2
3
4
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(f"{magician.title()}, that was a great trick!")
print(f"I can't wait to see your next trick, {magician.title()}.")

فراخوانی print() در خط ۲ باید با تورفتگی همراه باشد، امّا چون پایتون حداقل یک خطِ تورفته‌ی درست بعد از حلقه‌ی for می‌بیند، خطایی اعلام نمی‌کند. در نتیجه print() اول که خط آن تورفته است برای هر کدام از نام‌ها یک بار اجرا می‌شود. دومین print() را بدون تورفتگی نوشتیم پس تنها یک بار بعد از پایان کار حلقه اجرا می‌شود. از آن‌جایی که آخرین مقداری که به magician نسبت داده شده ‘carolina’ است، او تنها کسی است که پیام ’looking forward to the next trick’ را دریافت می‌کند:

1
2
3
4
Alice, that was a great trick!
David, that was a great trick!
Carolina, that was a great trick!
I can't wait to see your next trick, Carolina.

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

تورفتگی‌های بی‌مورد

اگر به طور تصادفی خطی را تورفته کنید بدون این که نیاز باشد پایتون در مورد آن به شما اطّلاع خواهد داد:

1
2
message = "Hello Python world!"
    print(message)

دستور print() در خط ۲ نیازی به تورفتگی ندارد چون بخشی از حلقه نیست؛ بنابراین پایتون این خطا را گزارش می‌کند:

1
2
3
4
File "hello_world.py", line 2
    print(message)
    ^
IndentationError: unexpected indent

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

تورفتگی بی‌مورد پس از حلقه

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

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

1
2
3
4
5
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(f"{magician.title()}, that was a great trick!")
    print(f"I can't wait to see your next trick, {magician.title()}.\n")
    print("Thank you everyone, that was a great magic show!")

چون که خط ۴ تورفته است، یک بار برای هر فرد داخل لیست چاپ می‌شود، چنانکه اینجا می‌بینید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Alice, that was a great trick!
I can't wait to see your next trick, Alice.

Thank you everyone, that was a great magic show!
David, that was a great trick!
I can't wait to see your next trick, David.

Thank you everyone, that was a great magic show!
Carolina, that was a great trick!
I can't wait to see your next trick, Carolina.

Thank you everyone, that was a great magic show!

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

فراموش کردن دونقطه

دونقطه‌ی پایان عبارت for به پایتون می‌گوید که خط بعدی را به عنوان آغاز حلقه در نظر بگیرد.

1
2
3
magicians = ['alice', 'david', 'carolina']
for magician in magicians
    print(magician)

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

خودآزمایی

۴-۱- پیتزاها

به دستِ کم سه نوع پیتزای دلخواه خود فکر کنید. نام آن‌ها را در لیستی ذخیره کنید و سپس به کمک حلقه‌ی for نام هرکدام را چاپ کنید.

  • حلقه را به نحوی تغییر دهید که به جای نام هر پیتزا جمله‌ای شامل نام آن چاپ شود. برای هر پیتزا باید جمله‌ای شبیه به «I like pepperoni pizza» در خروجی داشته باشید.
  • خطی به پایان برنامه‌ی خود، خارج از حلقه‌ی for، اضافه کنید که بیان می‌کند شما چه‌قدر پیتزا دوست دارید. خروجی باید از سه یا چند خط در مورد انواع پیتزاهای مورد علاقه‌ی شما تشکیل شده باشد و سپس جمله‌ای مانند I really like pizza! اضافه شود.

۴-۲- حیوانات

حداقل سه حیوان مختلف با ویژگی‌های مشترک در نظر بگیرید. نام آن‌ها را در لیستی ذخیره کنید و به کمک یک حلقه‌ی for نام هر یک را چاپ کنید.

  • برنامه را به نحوی تغییر دهید که جمله‌ای درباره‌ی هر حیوان چاپ کند، مثلاً A dog would make a great pet.
  • خطّی به پایان برنامه اضافه کنید که ویژگی مشترک این حیوانات را بیان کند. مثلاً می‌توانید جمله‌ای مانند Any of these animals would make a great pet!.

4 - پرهیز از خطای تورفتگی

پایتون از تورفتگی برای تعیین ارتباط یک خط یا گروهی از خط‌ها با دیگر قسمت‌های برنامه استفاده می‌کند. در مثال‌های گذشته خط‌هایی که برای هر شعبده‌باز پیامی جداگانه چاپ می‌کرد جزئی از حلقه‌ی for بودند زیرا آن‌ها را با تورفتگی نوشته بودیم. به‌کاررفتنِ تورفتگی در پایتون خواندنِ کد را بسیار ساده می‌کند و اساساً پایتون از فاصله‌ی خالی استفاده می‌کند تا شما را به نوشتن کدهای مرتّب با ساختار بصری واضح وادار کند. در برنامه‌های طولانی‌تر پایتون به قطعه‌های تورفته‌ی کد با سطح‌های تورفتگی‌های متفاوت برخواهید خورد. این سطوح تورفتگی به شما کمک می‌کند تا احساسی کلّی نسبت به سازمان و ساختار کلّی برنامه پیدا کنید.

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

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

فراموش کردن تورفتگی

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

1
2
3
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician)

فراخوانی print() در 1 باید تورفته باشد امّا نیست. هنگامی که پایتون به دنبال خطی تورفته باشد امّا آن را نیابد، به شما می‌گوید که کدام خط چنین مشکلی دارد.

1
2
3
4
File "magicians.py", line 3
    print(magician)
    ^
IndentationError: expected an indented block

این نوع از خطای تورفتگی را می‌توان با تصحیح خط یا خط‌هایی که بلافاصله بعد از عبارت for آمده‌اند برطرف کرد.

فراموش کردن تورفتگی خط‌های اضافی

گاهی حلقه‌ی شما بدون هیچ خطایی اجرا می‌شود امّا نتیجه‌ی مطلوب را نمی‌گیرید. این گاهی به این دلیل رخ می‌دهد که می‌خواهید چند وظیفه را در یک حلقه انجام دهید امّا فراموش کرده‌اید که برخی از خط‌ها را تورفته کنید.

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

1
2
3
4
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(f"{magician.title()}, that was a great trick!")
print(f"I can't wait to see your next trick, {magician.title()}.\n")

فراخوانی print() در 1 باید با تورفتگی همراه باشد، امّا چون پایتون حداقل یک خطِ تورفته‌ی درست بعد از حلقه‌ی for می‌بیند، خطایی اعلام نمی‌کند. در نتیجه print() اول که خط آن تورفته است برای هر کدام از نام‌ها یک بار اجرا می‌شود. دومین print() را بدون تورفتگی نوشتیم پس تنها یک بار بعد از پایان کار حلقه اجرا می‌شود. از آن‌جایی که آخرین مقداری که به magician نسبت داده شده ‘carolina’ است، او تنها کسی است که پیام ’looking forward to the next trick’ را دریافت می‌کند:

1
2
3
4
Alice, that was a great trick!
David, that was a great trick!
Carolina, that was a great trick!
I can't wait to see your next trick, Carolina.

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

تورفتگی‌های بی‌مورد

اگر به طور تصادفی خطی را تورفته کنید بدون این که نیاز باشد پایتون در مورد آن به شما اطّلاع خواهد داد:

1
2
message = "Hello Python world!"
    print(message)

دستور print() در 1 نیازی به تورفتگی ندارد چون بخشی از حلقه نیست؛ بنابراین پایتون این خطا را گزارش می‌کند:

1
2
3
4
File "hello_world.py", line 2
    print(message)
    ^
IndentationError: unexpected indent

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

تورفتگی بی‌مورد پس از حلقه

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

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

1
2
3
4
5
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
    print(f"{magician.title()}, that was a great trick!")
    print(f"I can't wait to see your next trick, {magician.title()}.\n")
    print("Thank you everyone, that was a great magic show!")

چون که خط 1 تورفته است، یک بار برای هر فرد داخل لیست چاپ می‌شود، چنانکه اینجا می‌بینید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Alice, that was a great trick!
I can't wait to see your next trick, Alice.

Thank you everyone, that was a great magic show!
David, that was a great trick!
I can't wait to see your next trick, David.

Thank you everyone, that was a great magic show!
Carolina, that was a great trick!
I can't wait to see your next trick, Carolina.

Thank you everyone, that was a great magic show!

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

فراموش کردن دونقطه

دونقطه‌ی پایان عبارت for به پایتون می‌گوید که خط بعدی را به عنوان آغاز حلقه در نظر بگیرد.

1
2
3
magicians = ['alice', 'david', 'carolina']
for magician in magicians
print(magician)

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

5 - ساختن لیست‌های عددی

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

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

به‌کارگیری تابع range

دستور range() در پایتون ایجاد دنباله‌ای از اعداد را آسان می‌کند. برای مثال به کمک آن می‌توانید دنباله‌ای از اعداد را مانند زیر چاپ کنید:

1
2
for value in range(1, 5):
    print(value)

هر چند به نظر می‌رسد این کد باید اعداد ۱ تا ۵ را چاپ کند، امّا عدد ۵ را چاپ نمی‌کند:

1
2
3
4
1
2
3
4

در این مثال range() تنها اعداد ۱ تا ۴ را چاپ می‌کند. این یکی دیگر از نتایج رفتار یکی‌جا‌به‌جا است که در زبان‌های برنامه‌نویسی غالباً دیده می‌شود. تابع range() باعث می‌شود پایتون از اولین مقدار داده‌شده شروع به شمارش کند و با رسیدن به دومین عددی که تعیین کرده‌اید توقف کند. از آن‌جایی که این تابع قبل از رسیدن به دومین مقدار مشخّص‌شده توقف می‌کند خروجی هرگز شامل مقدار پایانی نخواهد بود که در این مثال عدد ۵ است.

برای چاپ کردن اعداد ۱ تا ۵ از range(1,6) استفاده می‌کنید:

1
2
for value in range(1, 6):
    print(value)

این بار خروجی از ۱ آغاز و به ۵ ختم می‌شود:

1
2
3
4
5
1
2
3
4
5

اگر هنگام استفاده از range() خروجی با آن‌چه انتظار دارید متفاوت است سعی کنید مقدار پایانی را یکی جابه‌جا کنید.

همچنین می‌توانید به تابع range() تنها یک نشان‌وند بدهید آن‌گاه این تابع دنباله‌ی اعداد را از صفر آغاز می‌کند. برای مثال range(6) اعداد ۰ تا ۵ را برمی‌گرداند.

استفاده از range() برای تولید لیستی از اعداد

اگر بخواهید لیستی از اعداد تولید کنید می‌توانید به کمک تابع list()، خروجیِ تابعِ range() را مستقیماً به لیست تبدیل کنید. زمانی که تابع range() را داخل list() قرار می‌دهید خروجی لیستی از اعداد خواهد بود.

در مثال بخش قبل به سادگی دنباله‌ای از اعداد را چاپ کردیم. می‌توانیم از list() برای تبدیل این مجموعه‌ی اعداد به لیست استفاده کنیم:

1
2
numbers = list(range(1, 6))
print(numbers)

و نتیجه به این شکل است:

1
[1, 2, 3, 4, 5]

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

برای مثال اینجا نحوه‌ی تولید اعداد زوج بین ۱ تا ۱۰ را می‌بینیم:

1
2
even_numbers = list(range(2, 11, 2))
print(even_numbers)

در این مثال تابع range() از مقدار ۲ شروع می‌کند و سپس ۲ تا به آن اضافه می‌کند. این تابع تا زمان رسیدن یا گذشتن از مقدار پایانی، اینجا ۱۱، اضافه کردن ۲ را ادامه می‌دهد و این خروجی را تولید می‌کند:

1
[2, 4, 6, 8, 10]

به کمک تابع range() می‌توانید تقریباً هر نوع مجموعه‌ی عددی را تولید کنید. برای مثال فرض کنید که می‌خواهید لیست اوّلین ۱۰ عددِ مربّع را که توانِ دوی اعداد ۱ تا ۱۰ است تولید کنید. در پایتون دو علامت ستاره (**) بیانگر توان است. اینجا روشی نشان داده شده که شما هم احتمالاً برای قرار دادن ۱۰ عدد مربّع در یک لیست استفاده خواهید کرد:

1
2
3
4
5
6
squares = []
for value in range(1, 11):
    square = value ** 2
    squares.append(square)

print(squares)

در 1 از یک لیست تهی شروع می‌کنیم. در 2 به پایتون می‌گوییم که به کمک تابع range() در اعداد ۱ تا ۱۰ حلقه بزند. در 3 مقدار فعلی به توان ۲ رسیده و در متغیّر square ذخیره می‌شود. در 4، مقدار جدید square به لیست squares افزوده می‌شود. در نهایت با پایان یافتن حلقه لیست اعداد مربّع در 5 چاپ می‌شود:

1
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

برای مختصرتر نوشتن این کد می‌توانیم متغیّر موقّت square را حذف و مقادیر جدید را مستقیماً به لیست بیفزاییم:

1
2
3
4
squares = []
for value in range(1,11):
    squares.append(value**2)
print(squares)

کد در خط 1 همانند خط‌های 3 و 4 فایل squares.py کار می‌کند. هر کدام از مقدارها در حلقه به توان ۲ رسیده و بلافاصله به لیستِ اعدادِ مربّع افزوده می‌شود.

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

محاسبات آماری ساده با لیستی از اعداد

تعدادی از دستورهای پایتون هنگام کار با لیست‌های عددی سودمندند. برای مثال به راحتی می‌توانید کمینه، بیشینه و مجموع یک لیست اعداد را به دست آورید:

1
2
3
4
5
6
7
>>> digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> min(digits)
0
>>> max(digits)
9
>>> sum(digits)
45
نکته
در مثال‌های این بخش از لیست‌های کوچک اعداد بهره گرفته می‌شود تا به سادگی در صفحه جا شوند امّا اگر لیست شما شامل میلیون‌ها عدد یا بیشتر نیز باشد برنامه‌ها به همین ترتیب کار خواهند کرد.

تولید لیست به روش دربرداری

این رویکرد پیش از این برای تولیدِ لیستِ squares با سه یا چهار خط کد توضیح داده شد. روش دربرداری برای تولید لیست به شما امکان می‌دهد تا همین کار را تنها در یک خط انجام دهید. این روش حلقه‌ی for و ایجاد عناصر جدید را در یک خط ترکیب و هر عضو جدید را به طور خودکار اضافه می‌کند. ارائه کردن این روش به برنامه‌نویسانِ تازه‌کار معمولاً متداول نیست امّا اینجا آورده می‌شود چون شما به زودی و به محض آغازِ بررسیِ کدهای دیگران به آن برخواهید خورد.

مثال زیر ساختن لیستی مشابه با لیست اعداد مربّع را که پیش از این دیده‌اید نشان می‌دهد، امّا این بار با استفاده از روش دربرداری:

1
2
squares = [value**2 for value in range(1, 11)]
print(squares)

برای استفاده از این دستور، از یک نامِ گویا برای لیست، مثل squares، شروع کنید. حال یک کروشه باز کنید و برای مقادیری که می‌خواهید در لیست ذخیره کنید، عبارتی تعریف کنید. در این مثال این عبارت value**2 است که مقدارها را به توان ۲ می‌رساند. در ادامه یک حلقه‌ی for تعریف کنید تا اعدادِ ورودی به عبارتِ فوق را تولید کند. سرانجام کروشه را ببندید. حلقه‌ی for در این مثال for value in range(1,11) است که مقادیر ۱ تا ۱۰ را به عبارت value**2 می‌خوراند. توجّه کنید که در پایان حلقه‌ی for از دونقطه استفاده نشده است.

نتیجه مشابه همان لیستِ اعداد مربّعی است که پیش‌تر دیدید:

1
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

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

خودآزمایی

شمردن تا ۲۰

از یک حلقه‌ی for برای شمردن از ۱ تا ۲۰، و خودِ ۲۰، استفاده کنید.

یک میلیون

لیستی از اعدادِ ۱ تا یک میلیون بسازید سپس به کمک حلقه‌ی for آن را چاپ کنید. (اگر نمایش خروجی طولانی شد آن را با فشردن Ctrl+C یا بستن پنجره‌ی خروجی متوقّف کنید.)

جمع کردن یک میلیون عدد

لیستی از اعداد ۱ تا یک میلیون بسازید سپس با کمک min() و max() مطمئن شوید که لیست واقعاً از ۱ شروع و به یک میلیون ختم می‌شود. سپس از sum() استفاده کنید تا دریابید پایتون چه‌قدر سریع می‌توان یک میلیون عدد را با هم جمع کند.

اعداد فرد

به کمک ورودی یا نشان‌وند سوم تابع range() لیستی از اعداد فرد بین ۱ تا ۲۰ درست کنید. سپس به کمک یک حلقه‌ی for آن را چاپ کنید.

مضارب ۳

لیستی از مضرب‌های ۳ بین ۳ و ۳۰ بسازید و با یک حلقه‌ی for اعداد داخل آن را چاپ کنید.

اعداد مکعّب

به عددی که به توان ۳ رسیده باشد مکعّب گویند. برای مثال مکعّب ۲ در پایتون با 3**2 نمایش داده می‌شود. لیستی از ۱۰ عدد مکعّب نخست (که مکعّب اعداد صحیح از ۱ تا ۱۰ است)، بسازید و با یک حلقه‌ی for این اعداد را نمایش دهید.

اعداد مکعّب به روش دربرداری

به کمکِ این روش لیستی از ۱۰ عدد مکعّب نخست تولید کنید.

6 - کار کردن با بخشی از یک لیست

در فصل ۳ روش دسترسی به تک تک اعضای یک لیست و در این فصل کار کردن با تمام اعضای آن را آموختید. در عین حال شما می‌توانید با گروه مشخّصی از اعضای یک لیست کار کنید که پایتون آن را برش می‌نامد.

ساختن برشی از لیست

برای برش دادن یک لیست شاخص آغازی و پایانی اعضای مورد نظر خود را مشخّص می‌کنید. همانند تابع range() پایتون پیش از رسیدن به آخرین عضوِ مشخّص شده توقّف می‌کند. برای بریدن سه عضو اوّل یک لیست باید شاخص‌های ۰ تا ۳ را درخواست کنید که اعضای ۰، ۱ و ۲ را برمی‌گرداند.

مثال زیر درباره‌ی لیستی از بازیکن‌های یک تیم است:

1
2
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[0:3])

کد در 1 برشی از لیست را چاپ می‌کند که شامل سه بازیکن اوّل است. در خروجی ساختار لیست حفظ شده و شامل سه بازیکن است:

1
['charles', 'martina', 'michael']

می‌توانید هر زیرمجموعه‌ای را از یک لیست تولید کنید. مثلاً اگر برشی از لیست را شامل اعضای دوم، سوم و چهارم بخواهید می‌توانید آن را از شاخص ۱ آغاز و به شاخص ۴ ختم کنید:

1
2
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[1:4])

این بار برش از ‘martina’ شروع و با ‘florence’ تمام می‌شود:

1
['martina', 'michael', 'florence']

اگر شاخص اوّل برش را حذف کنید، پایتون برش را به طور خودکار از آغاز لیست شروع می‌کند:

1
2
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[:4])

بدونِ شاخصِ آغازین، پایتون از اوّلِ لیست شروع می‌کند:

1
['charles', 'martina', 'michael', 'florence']

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

1
2
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[2:])

پایتون عضو سوم تا پایان را برمی‌گرداند:

1
['michael', 'florence', 'eli']

به این ترتیب می‌توانید صرف نظر از طول لیست، تمام اعضای بین یک شاخص خاص و پایان آن را در خروجی داشته باشید. به خاطر بیاورید که شاخص منفی می‌توانست عضوی را در فاصله‌ی مشخّصی از پایان لیست برگرداند. پس به کمک آن می‌توانید برش‌هایی از انتهای لیست تولید کنید. برای مثال اگر بخواهیم سه بازیکنِ آخرِ ترکیبِ تیم را برگردانیم از برش players[-3:] استفاده می‌کنیم:

1
2
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[-3:])

این مثال نام سه بازیکن آخر را چاپ می‌کند و با افزایش تعداد بازیکنانِ لیست هم بدون مشکل کار خواهد کرد.

نکته
هنگام تعریف برش می‌توانید عدد سومی هم داخل کروشه بنویسید. این عدد مشخّص می‌کند که پایتون چند عضو را در بازه‌ی مشخّص‌شده نادیده بگیرد. (مانند آن‌چه که در تابع range بود.)

حلقه زدن در یک برش

اگر بخواهید تنها در زیرمجموعه‌ای از اعضای یک لیست حلقه بزنید می‌توانید از یک برش در حلقه‌ی for استفاده کنید. در مثال زیر در سه بازیکن اوّل حلقه می‌زنیم و نام آن‌ها را به عنوان یک ترکیبِ تیم ساده چاپ می‌کنیم:

1
2
3
4
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print("Here are the first three players on my team:")
for player in players[:3]:
    print(player.title())

پایتون در 1 به جای حلقه زدن در کل لیست، تنها در سه نام اول می‌چرخد:

1
2
3
4
Here are the first three players on my team:
Charles
Martina
Michael

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

کپی کردن یک لیست

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

برای کپی کردن یک لیست می‌توانید با حذف کردن شاخص‌های ابتدایی و پایانی ([:]) برشی از آن را تهیه کنید که شامل تمام اعضای لیست اوّلّیه است. این کار به پایتون می‌گوید که برشی از لیست تهیه کند که از عضو اول شروع و به عضو آخر ختم می‌شود و باعث ایجاد یک کپی از کل لیست می‌شود.

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

1
2
3
4
5
6
my_foods = ['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods[:]
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods are:")
print(friend_foods)

در 1 لیستی از غذاهایی را که دوست داریم به نام my_foods درست کرده‌ایم. در 2 لیست جدیدی به نام friend_foods می‌سازیم. با درخواست برشی از my_foods بدون مشخّص کردن هیچ شاخصی و ذخیره کردن آن در friend_foods، یک کپی از my_foods ایجاد می‌کنیم. اگر هر دو لیست را چاپ کنیم می‌بینیم که هر دو دربرگیرنده‌ی غذاهای مشابهی هستند:

1
2
3
4
My favorite foods are:
['pizza', 'falafel', 'carrot cake']
My friend's favorite foods are:
['pizza', 'falafel', 'carrot cake']

برای این که ثابت کنیم واقعاً دو لیست جداگانه داریم یک غذای جدید به هر یک از لیست‌ها اضافه می‌کنیم تا نشان دهیم که هر لیست غذاهای مورد علاقه‌ی یک نفر را به صورت جداگانه نگه می‌دارد:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
my_foods = ['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods[:]

my_foods.append('cannoli')
friend_foods.append('ice cream')

print("My favorite foods are:")
print(my_foods)

print("\nMy friend's favorite foods are:")
print(friend_foods)

در 1 همانند قبل، اعضای اوّلیّه‌ی داخل my_foods را در لیست جدید friend_foods کپی کردیم. در ادامه یک غذای جدید به هر لیست اضافه می‌کنیم: در 2 ‘cannoli’ را به my_foods و در 3 ‘ice cream’ را به friend_foods افزودیم. سپس هر دو لیست را چاپ می‌کنیم تا ببینیم هر کدام از این غذاها به لیست مناسب اضافه شده‌اند یا نه:

1
2
3
4
5
My favorite foods are:
['pizza', 'falafel', 'carrot cake', 'cannoli']

My friend's favorite foods are:
['pizza', 'falafel', 'carrot cake', 'ice cream']

خروجی نشان می‌دهد که ‘cannoli’ اکنون در لیست غذاهای مورد علاقه‌ی ما وجود دارد امّا ‘ice cream’ اینچنین نیست. در 5 می‌بینیم که ‘ice cream’ در لیست دوستمان هست امّا ‘cannoli’ نیست. اگر صرفاً و به سادگی متغیّر friend_foods را برابر با my_foods قرار می‌دادیم، منجر به ایجاد دو لیست جداگانه نمی‌شد. برای مثال اینجا می‌بینیم اگر لیستی را بدون استفاده از برش کپی کنیم چه اتّفاقی می‌افتد:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
my_foods = ['pizza', 'falafel', 'carrot cake']

# This doesn't work:
friend_foods = my_foods
my_foods.append('cannoli')
friend_foods.append('ice cream')

print("My favorite foods are:")
print(my_foods)

print("\nMy friend's favorite foods are:")
print(friend_foods)

در 1 به جای کپی کردن my_foods در friend_foods، صرفاً این دو متغیّر را برابر با یکدیگر قرار دادیم. این دستور به پایتون می‌گوید که متغیّر جدید friend_foods را به لیستی ارتباط دهد که خود قبلاً با my_foods مرتبط بوده است. بنابراین الان هر دو متغیّر به یک لیست مشابه اشاره می‌کنند. در نتیجه اگر ‘cannoli’ را به my_foods اضافه کنید این عضو در friend_foods نیز ظاهر خواهد شد. به طور مشابه اگر ‘ice cream’ را فقط به friend_foods اضافه کنید در هر دو لیست دیده خواهد شد.

خروجی نشان می‌دهد که هر دو لیست یکسان هستند و این چیزی نیست که ما می‌خواستیم:

1
2
3
4
5
My favorite foods are:
['pizza', 'falafel', 'carrot cake', 'cannoli', 'ice cream']

My friend's favorite foods are:
['pizza', 'falafel', 'carrot cake', 'cannoli', 'ice cream']
نکته
الان نگران جزئیات این مثال نباشید. اساساً هر جا هنگام کپی کردنِ یک لیست رفتاری غیرمنتظره دیدید مطمئن شوید که همانند مثال اوّل، از یک برش استفاده کرده‌اید.

خودآزمایی

برش‌ها

به یکی از برنامه‌هایی که در این فصل نوشته‌اید چند خط اضافه کنید تا کارهای زیر را انجام دهد:

  • پیام The first three items in the list are: و سپس به کمک یک برش سه عضو اوّل لیست برنامه را چاپ کند.
  • پیام Three items from the middle of the list are: و سپس به کمک یک برش سه عضو میانی لیست برنامه را چاپ کند.
  • پیام The last three items in the list are: و سپس به کمک یک برش سه عضو آخر لیست برنامه را چاپ کند.

پیتزاهای من، پیتزاهای تو

با شروع از برنامه‌ی تمرین ۴-۱ یک کپی از لیست پیتزاها ایجاد کنید و آن را friend_pizzas بنامید. سپس این کارها را انجام دهید:

  • یک پیتزای جدید به لیست اصلی اضافه کنید. پیام My favorite pizzas are: و در ادامه به کمک یک حلقه‌ی for لیست اول را چاپ کنید. پیام My friend's pizzas are: و با یک حلقه‌ی for لیست دوم را چاپ کنید. مطمئن شوید که هر پیتزا در لیست مناسب ذخیره شده باشد.

حلقه‌های بیشتر

در تمام نسخه‌های foods.py برای صرفه‌جویی در فضا از به‌کارگیری حلقه‌ی for برای چاپ لیست پرهیز شده است. یکی از نسخه‌ها را انتخاب کنید و دو حلقه‌ی for برای چاپ کردن هر کدام از لیست‌ها به آن بیفزایید.

7 - چندتایی‌ها

لیست‌ها برای ذخیره‌سازی مجموعه‌ای از اعضا مناسب است که ممکن است در طول برنامه تغییر کنند. قابلیّت تغییر دادن لیست‌ها به ویژه زمانی مهم است که بخواهید با فهرستی از کاربران یک وب‌سایت یا شخصیت‌های یک بازی کار کنید. با این حال گاهی به ساختن لیستی نیاز دارید که نباید تغییر کند. چندتایی‌ها چنین امکانی به شما می‌دهند. پایتون به مقادیری که مقدارشان قابل تغییر نیست تغییرناپذیر می‌گوید و لیستِ تغییرناپذیرْ چندتایی نامیده می‌شود.

تعریف کردن یک چندتایی

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

برای مثال اگر مستطیلی داشته باشیم که اندازه‌ی آن همیشه باید ثابت باشد، برای اطمینان از تغییر نیافتن اندازه‌ها می‌توانیم ابعاد آن را در یک چندتایی قرار دهیم:

1
2
3
dimensions = (200, 50)
print(dimensions[0])
print(dimensions[1])

چندتایی dimensions را با استفاده از پرانتز به جای کروشه در 1 تعریف کرده‌ایم. در 2 به کمک همان روشی که برای دسترسی به اعضای لیست استفاده می‌کردیم، هر عضو چندتایی را جداگانه چاپ می‌کنیم:

1
2
200
50

حال ببینیم اگر سعی کنیم یکی از عناصر داخل چندتایی را تغییر دهیم چه اتّفاقی می‌افتد:

1
2
dimensions = (200, 50)
dimensions[0] = 250

کد در 1 سعی می‌کند مقدار اولّین بُعد را تغییر دهد امّا پایتون خطایی مربوط به نوع برمی‌گرداند. دلیل این مساله این است که سعی کرده‌ایم یک چندتایی را تغییر دهیم و این کار برای این نوع مجاز نیست، پایتون می‌گوید که نمی‌توانیم مقدار جدیدی به یکی از اعضای داخل چندتایی نسبت دهیم:

1
2
3
4
Traceback (most recent call last):
  File "dimensions.py", line 2, in <module>
    dimensions[0] = 250
TypeError: 'tuple' object does not support item assignment

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

نکته

از لحاظ فنّی چندتایی‌ها با وجود کاما معنا می‌یابند؛ پرانتزها آن‌ها را مرتّب‌تر و خواناتر می‌کنند. اگر بخواهید یک چندتایی با تنها یک عضو ایجاد کنید باید کامایی در ادامه‌ی آن عضو بنویسید:

1
my_t = (3,)

معمولاً ساختن چندتایی با یک عضو بی‌معناست امّا در مواردی که آن‌ها را به طور خودکار تولید می‌کنیم ممکن است چنین حالتی رخ دهد.

حلقه زدن در تمام مقادیر یک چندتایی

درست همانند کاری که در لیست‌ها انجام می‌دادید، می‌توانید به کمک یک حلقه‌ی for در تمام اعضای یک چندتایی بچرخید:

1
2
3
dimensions = (200, 50)
for dimension in dimensions:
    print(dimension)

پایتون تمام اعضای چندتایی را برمی‌گرداند، درست مانند لیست‌ها:

1
2
200
50

رونویسی یک چندتایی

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

1
2
3
4
5
6
7
8
9
dimensions = (200, 50)
print("Original dimensions:")
for dimension in dimensions:
    print(dimension)

dimensions = (400, 100)
print("\nModified dimensions:")
for dimension in dimensions:
    print(dimension)

خط‌هایی که از 1 شروع می‌شوند چندتاییِ اوّلیّه را تعریف و آن را چاپ می‌کنند. در 2 یک چندتاییِ جدید به متغیّر dimensions نسبت می‌دهیم. در 3 ابعاد جدید را چاپ می‌کنیم. پایتون این بار خطایی اعلام نمی‌کند زیرا بازنشانی یک متغیّر مجاز است:

1
2
3
4
5
6
7
Original dimensions:
200
50

Modified dimensions:
400
100

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

خودآزمایی

بوفه

یک رستورانِ بوفه‌ای تنها پنج غذای اصلی ارائه می‌کند. پنج غذای ساده را در نظر بگیرید و نام آن‌ها را در یک چندتایی ذخیره کنید.

  • با یک حلقه‌ی for غذاهایی را که رستوران عرضه می‌کند چاپ کنید.
  • سعی کنید یکی از مقادیر چندتایی را تغییر دهید و مطمئن شوید پایتون ایجاد تغییرات را رد می‌کند.
  • رستوران فهرست غذاها را تغییر می‌دهد و دو غذا را جایگزین می‌کند. یک خط برای بازنویسی چندتایی اضافه کنید و سپس به کمک حلقه‌ی for تمام اعضای فهرستِ بازنگری‌شده را چاپ کنید.

8 - شکل‌دهی کدها

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

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

شیوه‌نامه

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

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

اگر بین نوشتن کدی که راحت‌تر نوشته شود و کدی که راحت‌تر خوانده شود حقّ انتخاب داشته باشید، برنامه‌نویسان پایتون تقریباً همیشه شما را به انتخاب گزینه‌ی دوم تشویق می‌کنند. راهنماهای زیر به شما کمک می‌کنند که از ابتدا کدی شفاف‌تر و واضح‌تر بنویسید.

تورفتگی

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

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

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

طول خط

بسیاری از برنامه‌نویسان پایتون پیشنهاد می‌کنند که طول هر خط کمتر از ۸۰ حرف باشد. از لحاظ تاریخی این توصیه به این دلیل ایجاد شده که بیشتر رایانه‌ها تنها ۷۹ کاراکتر در هر خط ترمینال جا می‌دادند. در حال حاضر می‌توان حرف‌های بسیار بیشتری در یک خط نمایشگر جا داد امّا دلایل دیگری برای وفادار ماندن به استاندارد خط ۷۹حرفی وجود دارد. برنامه‌نویسان حرفه‌ای گاهی چند فایل را همزمان روی صفحه‌ی خود باز می‌کنند و طول استاندارد خط به آن‌ها اجازه می‌دهد که در دو یا سه فایلی که کنار هم هستند، تمام خط‌ها را ببینند. PEP 8 همچنین توصیه می‌کند طول هر خطِ توضیحی را حداکثر ۷۲ حرف بگیرید زیرا ابزارهایی که برای پروژه‌های بزرگتر به طور خودکار مستندات را تولید می‌کنند در ابتدای هر توضیح چند حرف دیگر اضافه می‌کنند.

راهنمایی‌های PEP 8 در مورد طول خط وحیِ مُنزَل نیست و برخی از گروه‌ها حد ۹۹حرفی را می‌پسندند. در زمان یادگیری لازم نیست خیلی نگران طول خط باشید امّا حواستان باشد که افرادی که به صورت مشارکتی کار می‌کنند معمولاً همیشه از راهنماهای PEP 8 پیروی می‌کنند. بیشترِ ویرایشگرها برای شما یک سرنخ بصری ایجاد می‌کنند که معمولاً یک خط عمودی روی صفحه است و این حدود را به شما نشان می‌دهند.

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

خط‌های خالی

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

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

دیگر شیوه‌نامه‌ها

PEP 8 توصیه‌های متعدّد دیگر هم برای شکل‌دهی دارد امّا بیشتر آن‌ها در برنامه‌هایی کاربرد دارند که پیچیده‌تر از برنامه‌های فعلی شما هستند. همزمان با آموختن ساختارهای پیچیده‌تر پایتون بخش‌های مربوط در راهنماهای PEP 8 را با شما به اشتراک خواهم گذاشت.

خودآزمایی

PEP 8

به شیوه‌نامه‌ی اصلی PEP 8 در آدرس https://python.org/dev/peps/pep-0008/ نگاهی بیندازید. از بیشترِ آن استفاده نخواهید کرد امّا شاید مرور آن جالب باشد.

مرور کد

سه نمونه از برنامه‌هایی را که در این فصل نوشته‌اید انتخاب کنید و آن‌ها را برای تطبیق با PEP 8تغییر دهید:

  • از چهار فاصله برای هر سطح تورفتگی استفاده کنید. ویرایشگر متنی خود را تنظیم کنید تا با هر بار فشردن دکمه‌ی TAB چهار فاصله وارد کند. (برای مشاهده‌ی دستورالعمل انجام این کار پیوست ب را ببینید.)
  • کمتر از ۸۰ حرف در هر خط استفاده کنید و ویرایشگر خود را برای نمایش یک راهنمای عمودی در موقعیّت ۸۰امین حرف تنظیم کنید.
  • در برنامه‌های خود بیش از اندازه از خط خالی استفاده نکنید.

9 - خلاصه

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

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