while را به صورت ساده می توانیم این طور بیان کنیم:
“تا زمانی که شرط x برقرار است، دستور y را اجرا کن.“
یک بار دیگر برنامه ی whileLoop.py که در آموزش گذشته نوشتیم را در نظر بگیریم:
correctPassword = "SokanAcademy" password = input("Please enter the password --> ") while password != correctPassword: password = input("Please try again and enter the correct password --> ") print("Welcome to SokanAcadmy.com!")
در این برنامه یک رمز عبور ثابت برای ورود به سایت سکان آکادمی در نظر گرفته بودیم و کاربران باید
برای ورود به سایت این کلمه ی عبور را به درستی وارد می کردند. در صورت مطابقت ورودی کاربر با
مقدار از پیش تعیین شده، پیغام خوش آمد برای کاربر چاپ می شد و در غیر این صورت از کاربر
درخواست می شد که مجدداً تلاش کند و رمز عبور درست را وارد کند؛ اما مشکلی که این برنامه دارد
این است که در آن سناریویی برای زمانی که کاربر نتواند رمز عبور درست را وارد کند وجود ندارد و
لوپی که برای دریافت مجدد رمز عبور در نظر گرفته بودیم تا زمان وارد کردن کلمه ی درست دائماً
تکرار می شود.
در چنین شرایطی اگر کاربر نتواند کلمه عبور درست را وارد کند ناچار است که برنامه را ببندد.
برای رفع این مشکل باید به طریقی قبل از آن که شرط ورود به لوپ برابر با False شود از آن
خارج شویم. در چنین مواردی از دستور break استفاده می کنیم.
برای روشن شدن نحوه ی عملکرد دستور break، برنامه ی WhileLoop را به صورت زیر بازنویسی
کرده و اسکریپت آن را در فایلی تحت عنوان BreakLoop.py ذخیره می کنیم:
correctPassword = "SokanAcademy" password = input("Please enter the password --> ") while password != correctPassword: if password == "I’ve forgotten the password": break password = input("Please try again and enter the correct password "+ "or type:I’ve forgotten the password --> ")
به تغییرات این برنامه توجه کنید. داخل لوپ while یک دستور شرطی if قرار داده ایم. در صورتی
که شرط این دستور برقرار باشد، یعنی کاربر عبارت “I`ve forgotton the password” به معنای “من
کلمه ی رمز را فراموش کرده ام” را وارد کند مفسر وارد بدنه ی دستور شرطی if می شود و دستور
break که در داخل آن قرار دارد را اجرا می کند. این دستور به مفسر می گوید که باید از بدنه ی
لوپ while خارج شود و بقیه ی دستورهای داخل بدنه ی آن را اجرا نکند.اما در صورتی که شرط
دستور if برقرار نباشد، دستور بعدی لوپ while اجرا خواهد شد و از کاربر درخواست می شود مجدداً
برای وارد کردن رمز عبور درست تلاش کند و یا همان عبارت “I`ve forgotton the password” را وارد
کند تا از لوپ خارج شود. یک نمونه از خروجی این برنامه به صورت زیر است:
====== RESTART: C:\SokanAcademy\While\BreakLoop.py ====== Please enter the password --> I`ve forgotton the password >>>
همان طور که می بینید زمانی که کاربر عبارت I`ve forgotton the password را وارد کرده است، بقیه دستورات داخل لوپ while اجرا نشده اند. دقت کنید که در این جا دستور شرطی if را قبل از دستور
دیگری که در داخل بدنه ی لوپ وجود دارد قرار داده ایم به این دلیل که ممکن است کاربر مانند اجرایی
که دیدیم از همان ابتدای اجرای برنامه رمز عبور درست را نداند و بخواهد به سیستم اطلاع دهد که آن
را فراموش کرده است. بنابراین وقتی عبارت I`ve forgotton the password را وارد می کند، چون با رمز عبور درست مطابقت ندارد، مفسر وارد لوپ while می شود و اگر دستور if در ابتدا نیامده باشد از کاربر
یک بار دیگر هم درخواست وارد کردن رمز عبور می شود که این کار درست نیست، چون قبلاً کاربر
اعلام کرده است که رمز عبور درست را نمی داند.
پس به طور کلی، یک دستور break می تواند در هر قسمت از بدنه ی لوپ قرار بگیرد و زمانی که مفسر پایتون به آن می رسد دستورات موجود در بدنه ی لوپ که بعد از آن قرار می گیرند را نادیده می گیرد و
از لوپ خارج می شود. اگرچه ما می توانیم از این دستور در هر بخش از لوپ استفاده کنیم، اما معمولاً
از آن در داخل یک دستور شرطی if که در بدنه ی لوپ آمده است استفاده می شود، چرا که معنایی ندارد
ما به صورت ساده از یک دستور break در داخل لوپ استفاده کنیم و بعد از آن دستوراتی را قرار دهیم
که می دانیم هرگز اجرا نخواهند شد. پس در حقیقت دستور break جریان برنامه را در داخل لوپ
متوقف می کند و بقیه ی کدهای برنامه اجرا می شوند.
حالا که با دستور break و کارکرد آن آشنا شدیم می خواهیم برنامه را کمی توسعه دهیم. برای این
منظور، سناریویی به صورت زیر را در نظر می گیریم:
اگر کاربر رمز عبور درست را وارد کرد پیغام خوش آمد گویی برای او چاپ شود و در صورتی که کاربر
اعلام کند که رمز عبور درست را فراموش کرده است آدرس ایمیلی از او گرفته شود تا رمز عبور درست
برای وی ارسال شود. برنامه را به صورت زیر بازنویسی می کنیم:
correctPassword = "SokanAcademy" password = input("Please enter the password --> ") while password != correctPassword: if password == "I`ve forgotton the password": email = input("Please enter your email to sent you correct password --> ") print("The password has sent to",email) break password = input("Please try again and enter the correct password "+ "or type:I`ve forgotton the password --> ") else: print("Welcome to SokanAcadmy.com") # Run if didn't exit loop with break
به کدهای اضافه شده به برنامه توجه کنید. در دستور شرطی if که به صورت تو در تو در لوپ while قرار دارد و در صورتی که کاربر اعلام کند که رمز ورود را فراموش کرده است بدنه ی آن اجرا خواهد شد،
دستور جدیدی قرار داده ایم که از کاربر درخواست می کند آدرس ایمیل خود را وارد کند تا رمز ورود
درست برای او ارسال شود و این در حالی است که ورودی کاربر به متغیری با نام email ارجاع داده می شود.
اما بعد از لوپ while یک دستور else قرار گرفته است. کدهای داخل بدنه ی دستور else زمانی اجرا خواهند شد که مفسر با دستور break از لوپ while خارج نشده باشد، بنابراین در این جا دستور else زمانی اجرا خواهد شد که کاربر بتواند رمز عبور درست را وارد کند. ساختار کلی لوپ while به همراه دستور else به صورت زیر است
while testConditions: # Loop head with test Block(s) of code # Loop body else: # Optional else Block(s) of code # Run if the loop didn`t exit with break
همان طور که در ساختار بالا می بینید، اضافه کردن بند else در این دستور مرکب کاملاً اختیاری است
و در صورتی که مفسر با دستور break از لوپ while خارج نشود، کدهای داخل بدنه ی این دستور
حتماً اجرا خواهند شد. حال سه نمونه از خروجی های حاصل از اجرای این برنامه را بررسی می کنیم:
====== RESTART: C:\SokanAcademy\While\BreakLoop.py ====== Please enter the password --> SokanAcademy Welcome to SokanAcadmy.com >>>
در این اجرا، کاربر از همان ابتدا رمز عبور درست را وارد کرده است، بنابراین مفسر اصلاً وارد بدنه ی
لوپ نمی شود، با این حال دستور داخل بدنه ی else اجرا شده است. مجدد برنامه را اجرا می کنیم:
====== RESTART: C:\SokanAcademy\While\BreakLoop.py ====== Please enter the password --> sokanacademy Please try again and enter the correct password or type:I`ve forgotton the password --> SokanAcademy Welcome to SokanAcadmy.com >>>
در این نوبت از اجرا، کاربر در ابتدا رمز ورود را به درستی وارد نمی کند، بنابراین شرط لوپ برقرار است
و مفسر وارد آن می شود. چون کاربر عبارت فراموش کردن رمز را وارد نکرده است، دستور if اجرا نمی شود و در عوض از کاربر درخواست می شود که مجدداً برای وارد کردن رمز عبور جدید تلاش کند، و زمانی که
رمز ورود را برای بار دوم به درستی وارد می کند، مفسر از لوپ خارج می شود و دستور else را اجرا می کند، چون با وجود آن که وارد لوپ شده بود، اما با دستور break از آن خارج نشد. و برای سومین و آخرین بار برنامه ی خود را اجرا می کنیم:
====== RESTART: C:\SokanAcademy\While\BreakLoop.py ====== Please enter the password --> sokanacademy Please try again and enter the correct password or type:I`ve forgotton the password --> I`ve forgotton the password Please enter your email to sent you correct password --> narges.asadi@sokanacademy.com The password has sent to narges.asadi@sokanacademy.com >>>
در این نوبت از اجرا، کاربر در ابتدا رمز عبور درست را وارد نکرده است و مفسر وارد بدنه ی لوپ می شود. شرط if در ابتدا برقرار نیست، چرا که کاربر اعلام نکرده است که رمز عبور را فراموش کرده است، بنابراین
از او درخواست می شود که مجدداً برای وارد کردن رمز عبور جدید تلاش کند. این بار کاربر اعلام می کند
که رمز عبور را فراموش کرده است، بنابراین شرط while هم چنان برقرار است و این بار شرط if داخل آن
نیز برقرار است، بنابراین از کاربر درخواست می شود که آدرس پست الکترونیک خود را وارد کند تا کلمه ی عبور درست به آن آدرس ارسال شود. وقتی کاربر ایمیل خود را وارد می کند، دستور پرینت پیغامی چاپ
می کند که کلمه ی عبور به آدرس ایمیل کاربر فرستاده شده است (البته در این برنامه هیچ ایمیلی ارسال
نمی شود.) سپس مفسر با دستور break از لوپ خارج می شود، به همین دلیل دیگر دستور else اجرا نشده است.
حلقه while
correctPassword = "SokanAcademy" password = input("Please enter the password --> ") if password == correctPassword: print("Welcome to SokanAcademy.com!")
همان طور که می بینید ما یک پسورد ثابت را در متغیری تحت عنوان correctPassword به معنی | «رمزعبور صحیح» ذخیره کرده ایم. سپس از کاربران خواسته ایم تا کلمه ی عبوری را وارد کنند. آن گاه با دستور شرطی if تطابق کلمه ی عبور درست را با کلمه ی عبور وارد شده توسط کاربر بررسی می کنیم و در صورت درست بودن این شرط پیغام خوش آمد برای کاربر سایت چاپ میشود و در غیر این صورت هم هیچ اتفاقی رخ نخواهد داد. حال فرض کنید کاربری در زمان اجرای برنامه به صورت زیر عمل می کند:
======= RESTART: C:/SokanAcademy/While/ifClause.py ======= Please enter the password --> sokanacademy
همان طور که می بینید کاربر توجهی به بزرگ و کوچک بودن حروف کلمه ی رمز نداشته است و تمام حروف آن را به صورت کوچک وارد کرده است، در حالی که مفسر پایتون نسبت به حالت حروف حساس است و چون در رمز عبور برنامه یعنی SokanAcademy دو حرف S و A با حروف بزرگ تعریف شده اند، پاسخ به شرط دستور شرطی True نیست بنابراین دستور پرینت داخل بدنه ی آن هرگز اجرا نخواهد شد.
مسلم است که در این صورت کاربر نمی تواند وارد سایت شود، اما اگر کاربر بخواهد مجدداً تلاش کند و کلمه ی عبور را به درستی وارد کند چه طور؟ همان طور که می بینید، دستور شرطی if تنها یک بار درست بودن رمز عبور را بررسی می کند و این امکان را به کاربر نمی دهد تا در صورت نادرست بودن رمز عبور دوباره کلمه ی جدیدی را وارد کند تا مجدداً مورد بررسی قرار بگیرد. بنابراین برای این که امکان تکرار را برای کاربران خود فراهم کنیم تا چند بار بتوانند کلمه ی عبور را ارسال کند نیاز به دستوری داریم که این عمل -یعنی گرفتن کلمه ی عبور از کاربر و بررسی مطابقت آن با رمز عبور درست- را بارها و بارها تکرار کند.
قبلاً هم گفتیم که یکی از قابلیت های زبان های برنامه نویسی از جمله Python این است که با استفاده از سینتکس های استاندارد تعریف شده در آن ها، امکان تکرار اجرای بخشی از کدهای برنامه را فراهم می کنند تا از این طریق جریان برنامه کنترل شود. زبان برنامه نویسی پایتون این امکان را از طریق بکارگیری ساختارهای تحت عنوان Loop (لوپ به معنی حلقه) برای برنامه نویسان فراهم می کند که یکی از این لوپ ها، while نام دارد. آشنایی بیشتر با ساختار حلقه یی از جنس while در زبان برنامه نویسی پایتون، ابتدا سعی میکنیم تا همان برنامه ی قبل را این بار با استفاده از دستور while بازنویسی و تکمیل کنیم:
correctPassword = "SokanAcademy" password = input("Please enter the password --> ") while password != correctPassword: password = input("Please try again and enter the correct password --> ") print("Welcome to SokanAcadmy.com")
اجازه دهید قبل از بررسی ساختار برنامه آن را اجرا کنیم تا تفاوت این دستور را با دستور شرطی if ببنیم. برای این کار ابتدا اسکریپت برنامه را در فایل whileLoop.py ذخیره می کنیم و آن گاه برنامه را به صورت زیر اجرا می کنیم:
====== RESTART: C:/SokanAcademy/While/whileLoop.py ====== Please enter the password --> sokanacademy Please try again and enter the correct password --> sokanAcademy Please try again and enter the correct password --> Sokanacademy Please try again and enter the correct password --> SokanAcademy Welcome to SokanAcadmy.com >>>
همان طور که در نتایج خروجی می بینید با اجرای برنامه برای اولین بار، از کاربر درخواست می شود تا کلمه ی عبور را وارد کند. چون در زمان وارد کردن کلمه ی عبور، بزرگ و کوچک بودن حروف توجه نکرده ایم پیغام خوش آمدگویی چاپ نشده است، در عوض می بینید که به جای حالت قبل که برنامه به پایان می رسید اکنون از کاربر خواسته شده تا مجدداً تلاش کند و رمز عبور درست را وارد کند.
در تلاش دوم هم همان طور که می بینید مجدد رمز عبور درست وارد نشده است، با این وجود هنوز هم برنامه به پایان نمی رسد و مجدداً به کاربر فرصت داده می شود که رمز عبور درست را وارد کند و این کار تا زمانی ادامه پیدا می کند که پسورد درست توسط کاربر وارد شود، آن گاه برنامه پیغام خوش آمد را برای کاربر چاپ خواهد کرد.
حال که نحوه ی اجرای این برنامه را دیدیم، اجازه دهید با ساختار کدنویسی چنین حلقه هایی بیشتر آشنا شویم. برای این کار مجدداً به کدهای برنامه نگاه می کنیم. همان طور که می بینید، مثل برنامه ی قبل باز هم در ابتدا یک کلمه ی عبور با مقدار “SokanAcademy” تعریف کرده ایم تا با کلمه ی وارد شده توسط کاربر مقایسه شود. سپس از کاربر می خواهیم رمز عبور را وارد کند و مقدار ورودی را به متغیر password ارجاع می دهیم. دستور بعدی، دستور مرکب while است. همان طور که می بینید این دستور هم مانند تمام دستورهای مرکب با یک کیورد از پیش تعریف شده در زبان پایتون آغاز می شود که در این جا while است. در این جا، کیورد while به معنای “تا زمانی که” است. منطقی را که می خواستیم در برنامه پیاده سازی کنیم را به یاد می آورید. قرار بر این بود برنامه ای بنویسیم که “تا زمانی که کلمه ی عبور وارد شده توسط کاربر با کلمه ی عبور درست مطابقت نداشت، مجدداً از کاربر بخواهیم پسورد جدیدی را وارد کند،” بنابراین بعد از کیورد while باید شرط مورد نظر بررسی شود. برای این کار می بینید که پس از کیورد while، یک دستور مقایسه ای آمده است: password != correctPassword به معنی «مادامی که مقدار متغیر correctPassword مخالف بود با مقدار متغیر password»
تا زمانی که مقدار این دستور مقایسه ای درست باشد، یعنی ورودی کاربر برابر با کلمه ی عبور درست نباشد، دستورات داخل بدنه ی while اجرا خواهند شد و به محض آن که مقدار این شرط برابر با مقدار False ارزیابی شود مفسر از بدنه ی دستور while خارج خواهد شد. پس از شرط برای پایان دادن به سربند این دستور مرکب از : استفاده کرده ایم و سپس دستورات داخل بدنه ی while را با رعایت تورفتگی نسبت به بلوک سربند آن در یک بلوک جدید می نویسیم.
همان طور که می بینید دستور داخل بدنه ی while به این صورت است که مجدداً از کاربر درخواست می شود کلمه ی جدیدی را وارد کند و این کلمه ی جدید به همان متغیر password ارجاع داده می شود. بعد از این کار، وقتی دستورات داخل بدنه ی while به پایان می رسند، مفسر مجدداً شرط while را بررسی می کند. اگر این شرط درست باشد باز هم وارد بدنه ی while می شود و دستورات آن را تکرار می کند، اما در صورت نادرست بودن شرط while یعنی زمانی که کاربر کلمه ی عبور درست را وارد می کند، مفسر دیگر وارد بدنه ی while نشده و جریان اصلی برنامه ادامه پیدا می کند که در این مثال آخرین دستور برنامه چاپ پیغام خوش آمد برای کاربری است که رمز عبور را به درستی وارد کرده است و به این صورت سیستم اجازه ی ورود کاربر را به ناحیه ی کاربری اش فراهم می کند.
در صورتی که کاربر نتواند رمز عبور را به درستی وارد کند دستور داخل بدنه ی while به صورت مکرر اجرا خواهد شد و تنها با بستن پنجره ی خروجی یا فشردن کلیدهای ترکیبی Ctrl+C می تواند اجرای برنامه را متوقف کند و از آن خارج شود. فرم کلی دستور مرکب while را به صورت زیر می توانیم بیان کنیم:
while testConditions: # Loop head with test condition(s) block(s) of code
همان طور که گفتیم، مفسر پایتون با رسیدن به دستور while، شرطی را که برای آن در نظر گرفته ایم بررسی می کند و تا زمانی که مقدار این شرط معادل با True باشد، قطعه کدهای داخل بدنه ی آن را به صورت مکرر اجرا خواهد کرد. چنین دستوری اصطلاحاً Loop (لوپ یا معادل آن حلقه) نامیده می شود، چرا که دستورات داخل آن پشت سر هم اجرا می شوند و با پایان یافتن آن ها مجدداً به ابتدا بر می گردیم، شرط پایان حلقه بررسی می شود، اگر برابر با True باشد جریان در لوپ ادامه پیدا می کند، و اگر شرط برابر False ارزیابی شود جریان برنامه از لوپ خارج می شود و سایر دستورات بعد از while اجرا می شوند.
نکته
لوپ تنها در صورت درست بودن شرط تکرار می شود؛ بنابراین اگر در همان ابتدا پیش از ورود به لوپ شرط آن برقرار نباشد، مفسر اصلاً وارد لوپ نخواهد شد و دستورات داخل آن را نادیده خواهد گرفت و از آن ها رد می شود تا بقیه ی کدها را اجرا کند. بنابراین ممکن است که حلقه while اصلاً اجرا نشود. برای مثال قطعه کد زیر را در نظر بگیرید:
>>> while False: print("This code never will run.") >>>
همان طور که می بینید چون مقدار شرط while از همان ابتدا برابر False است، دستور داخل بدنه ی آن اصلاً اجرا نمی شود. نکته ی دیگری که باید مورد توجه قرار بگیرد این است که در زمان کدنویسی دستور while باید دقت داشته باشیم که شرط ورود به آن را با استفاده از دستورات داخل بدنه ی آن به گونه ای کنترل کنیم که در جایی برابر با مقدار False شود، در غیر این صورت اجرای لوپ تا بی نهایت ادامه پیدا میکند -که اصطلاحاً به آن Infinite Loop یا حلقه بی پایان گفته می شود- و برای توقف آن ناچار باید پنجره ی خروجی را ببندیم که در این صورت سایر دستورات برنامه هم اجرا نخواهند شد. برای مثال برنامه زیر را در نظر بگیرید:
i = 5 while i: print(i) i -= 1 #i = i-1 print("At the end i equals",i,".")
اسکریپت این برنامه را در فایل whileLoopInfinite.py ذخیره می کنیم. مفسر پایتون اجرای برنامه را از خط اول کدها شروع می کند. در ابتدا متغیری با شناسه ی i تعریف و به عدد صحیح ۵ منتسب شده است -حرف i را میتوان مخفف واژه ی index (ایندکس به معنی اندیس) در نظر گرفت- و در خط بعد مفسر پایتون با رسیدن به کلمه ی کلیدی while شرط آن را بررسی میکند (همان طور که می بینید این شرط بررسی متغیر i است. قبلاً گفتیم که تمام اعداد به جز صفر برابر مقدار True ارزیابی می شوند. بنابراین شرط این لوپ برقرار است و مفسر برای اجرای کدهای بدنه ی آن وارد می شود).
اولین دستور بدنه ی این لوپ یک دستور پرینت است که مقدار متغیر i را چاپ می کند. دستور دیگری که در بدنه ی while قرار دارد i -= 1 است. این دستور یک واحد از مقدار متغیر i کم می کند و این متغیر را به مقدار جدید منتسب می کند (به عنوان راه کاری جایگزین، می توان کد i = i-1 را نوشت.) وقتی برای اولین بار مفسر پایتون دستورات این لوپ را اجرا می کند عدد صحیح ۵ به عنوان مقدار آن چاپ می شود و سپس یک واحد از آن کم می شود، آن گاه مفسر دوباره به ابتدای لوپ برمی گردد و شرط را بررسی می کند. اکنون مقدار جدید i که برابر با ۴ است باز هم معادل True ارزیابی می شود و دستورات داخل لوپ مجدداً تکرار می شود و این تکرارها ادامه پیدا می کند. اجازه دهید خروجی این برنامه را ببینیم:
====== RESTART: C:\SokanAcademy\While\whileLoop1.py ====== ۵ ۴ ۳ ۲ ۱ At the end i equals 0 . >>>
همان طور که می بینید این لوپ در نهایت متوقف شده است. زمانی که برای آخرین بار مقدار i برابر با ۱ بوده و چاپ شده است، یک واحد از این مقدار کم و برابر با مقدار ۰ می شود. سپس مفسر شروع به بررسی شرط می کند. اکنون مقدار متغیر i که برابر با ۰ است معادل False ارزیابی می شود. بنابراین شرط ورود به لوپ برقرار نیست و مفسر دیگر وارد لوپ نمی شود و به سراغ اجرای مابقی دستورات برنامه می رود. همان طور که می بینید یک دستور پرینت دیگر بعد از لوپ وجود دارد که عبارتی به معنای “در نهایت مقدار i برابر است با ۰” را چاپ می کند. پس می بینیم که در نهایت مقدار i برابر با صفر بوده و لوپ به درستی متوقف شده است. بنابراین در این برنامه به کمک تعریف متغیر i و انتساب آن به مقادیر مختلف در داخل بدنه ی لوپ شرط while را به گونه ای کنترل کردیم که در نهایت برابر با مقدار False قرار گیرد.
حال برای آن که ببینیم ساز و کار یک حلقه ی بی انتها به چه شکل است، برنامه ی بالا را با کمی تغییر به صورت زیر مد نظر قرار می دهیم:
i = 5 while i: print(i) #i -= 1 #i = i-1 print("At the end i equals",i,".")
تنها تغییری که در این برنامه صورت گرفته، این است که بخشی از کد که مسئول کاهش مقدار متغیر i است را کامنت کرده ایم. به عبارت دیگر، در هر بار اجرای این لوپ، چیزی از مقدار اولیه ی متغیر i کم نخواهد شد و مقدار این متغیر همواره برابر با ۵ باقی مانده و بالتبع شرط این لوپ هم همواره True در نظر گرفته خواهد شد. اکنون یک بار دیگر برنامه را اجرا می کنیم:
====== RESTART: C:\SokanAcademy\While\whileLoop1.py ====
همان طور که می بینیم، برنامه ی ما باتوجه به این که هیچ نقطه ی پایانی ندارد، تا بی نهایت ادامه خواهد یافت.
continue
در آموزش قبل با دستور break و نحوه ی بکارگیری آن در ساختار لوپ while آشنا شدیم و دیدیم زمانی که مفسر دستور break را در داخل یک لوپ اجرا می کند، به جای اجرای بقیه ی دستورات داخل لوپیا اجرای مجدد لوپ، سریعاً از آن خارج می شود و بقیه دستورات برنامه را اجرا می کند (البته فراموش نکنیم که در این صورت دستور else که بلافاصله بعد از لوپ آمده باشد هم اجرا نمی شود.)
در این آموزش با دستور continue که یکی دیگر از دستورهای قابل استفاده در loop ها است آشنا
خواهیم شد که به نوعی جریان اصلی اجرای دستورهای داخل یک لوپ را تغییر می دهد. در ادامه،
اجرای این دستور را در قالب ارائه ی آن در یک مثال بررسی می کنیم به این شکل که می خواهیم
برنامه ای بنویسیم که اعداد زوج یک رقمی مثبت یعنی ۸، ۶، ۴، ۲، و ۰ را به ترتیب از بزرگ به
کوچکدر خروجی چاپ کند.
به خاطر داشته باشید
تقسیم آن بر ۲ برابر با ۰ است. اعداد فرد هم در مقابل اعداد زوج قرار می گیرند؛ به عبارت دیگر
باقیمانده ی تقسیم آن ها بر ۲ عددی غیر از صفر است.
برای نوشتن این برنامه می توانیم از یک لوپ while برای تکرار عملیات چاپ اعداد استفاده کنیم، اما
باید دقت کنیم که برنامه ی خود را به صورتی بنویسیم که اگر یک عدد زوج داشتیم در خروجی
چاپ شود و اگر به عدد فرد در لوپ رسیدیم از آن بگذریم. برنامه را به صورت زیر کدنویسی
می کنیم و درفایلی تحت عنوان ContinueStatement.py ذخیره می کنیم:
x = 10 while x: x -= 1 # Or, x = x-1 if x % 2 != 0: continue # Odd? Skip print(x) print(x)
خروجی برنامه ی بالا به صورت زیر است:
===== RESTART: C:\SokanAcademy\ContinueStatement.py ===== ۸ ۶ ۴ ۲ ۰ >>
کدهای برنامه ی بالا را در نظر بگیرید. ابتدا متغیر x را به عدد صحیح ۱۰ منتسب می کنیم سپس از
آن در شرط کنترل لوپ استفاده می کنیم. با اجرای برنامه مفسر شرط لوپ را ارزیابی می کند و از
آن جا که هر عدد غیر صفر مقداری برابر True دارد، وارد لوپ می شود و اولین دستور لوپ که در
آن یک واحد از مقدار متغیر x کم می شود را اجرا می کند، که در نتیجه ی آن x به عدد صحیح ۹
منتسب می شود.
آن گاه دستور بعدی که یک دستور شرطی if است اجرا می شود. ابتدا مفسر شرط if یعنی x % 2 != 0
را بررسیمی کند. چون حاصل تقسیم ۹ بر ۲ برابر ۱ و عددی غیر صفر است شرط if برقرار است،
بنابراین دستورداخل بدنه ی آن اجرا می شود.
دستور continue در بدنه ی این شرط به مفسر اعلام می کند که به جای اجرای بقیه ی دستورهای داخل
لوپ به ابتدای آن بازگردد و مجدداً شرط آن را بررسی کند. همان طور که در خروجی دیدید با وجود
آن که دستور بعدی داخل لوپ باید مقدار متغیر x را چاپ کند این اتفاق نمی افتد و عدد ۹ در خروجی
چاپ نشده است. در عوض مفسر پایتون مجدداً به ابتدای لوپ باز می گردد و از آن جا که هنوز هم
مقدار متغیر x که برابر با عدد صحیح ۹ است برابر با مقدار True ارزیابی می شود باز هم وارد لوپ
می شودو مجدداً دستورها را اجرا می کند.
ابتدا مانند دور قبل یک واحد از مقدار x کم می شود و برابر ۸ قرار می گیرد، سپس شرط if بررسی
می شود. این بار چون مقدار x عددی زوج است، شرط if برآورده نمی شود و از این رو دستور continue
در داخل بدنه ی این دستور شرطی اجرا نخواهد شد. بنابراین مفسر اجرای بقیه ی دستورات داخل لوپ
را ادامه می دهد و این بار فانکشن ()print که برای چاپ مقدار x در نظر گرفته بودیم عدد صحیح ۸ را
در خروجی چاپ می کند. به این ترتیب اجرای دستورات داخل لوپ ادامه پیدا می کند، هرگاه مقدار x
عددی زوج بود در خروجی چاپ می شود و زمانی که مقدار x عددی فرد بود، این عدد چاپ نشده
و با استفاده از دستور continue اجرای لوپ مجدداً از سر گرفته می شود.
این عمل تا زمانی ادامه پیدا می کند که x به عدد صحیح صفر منتسب می شود. با این کار شرط
لوپ برابر با مقدار False ارزیابی می شود و اجرای آن به طور کامل متوقف می شود.
همان طور که در قالب این مثال دیدیم، از دستور continue زمانی استفاده می کنیم که بخواهیم به
ابتدای لوپ برگردیم و بقیه دستورات لوپ را در یک دور اجرا نکنیم، در حالی که از دستور break
برای خروج کامل از لوپ استفاده می کنیم.
حلقه for
بهترین راه برای آشنایی بیش تر با ساختار دستور for و نحوه ی کارکرد آن در زبان برنامه نویسی پایتون، ارائه ی آن در قالب یک مثال است. در این مثال می خواهیم به کمک دستور for حروف نام تجاری “SokanAcademy” را به صورت جداگانه در خروجی چاپ کنیم. برای این کار برنامه را به صورت زیر کدنویسی می کنیم و اسکریپت آن را در فایلی تحت عنوان ForLoop.py ذخیره می کنیم:
letterNum = 0 for letter in "SokanAcademy": letterNum += 1 print("Letter ", letterNum, " is ", letter,".") print("SokanAcademy has",letterNum,"letters.")
این برنامه با ایجاد یک متغیر با شناسه ی letterNum آغاز می شود که عدد صحیح ۱ به آن ارجاع داده شده است و از آن برای شمارش تعداد حروف کلمه ی مورد نظر یا به عبارت دیگر برای شمارش تعداد دفعات تکرار اجرای دستورات داخل لوپ استفاده می کنیم. بنابراین در داخل بدنه ی لوپ باید کدی قرار دهیم که با هر بار اجرای لوپ، این متغیر به عددی که یک واحد بزرگ تر است ارجاع داده شود.
دستور بعدی یک دستور مرکب است و مانند هر دستور مرکب دیگر با یک کیورد که در این جا کلمه ی for است آغاز شده است. بعد از کیورد for باید شناسه ی یک متغیر را قرار دهیم. در این مثال شناسه ی متغیر letter یا هر نام دلخواه دیگری است. در ادامه کیورد in را قرار می دهیم که به مفسر پایتون نشان می دهد در ادامه قرار است داده ای از نوع دنباله قرار گیرد. یک آبجکت از نوع دنباله به گونه ای است که از چند عضو تشکیل شده است و اعضا به ترتیب یکی پس از دیگری در جایگاه ثابتی قرار گرفته اند و دنباله را ایجاد کرده اند.
برای مثال در زمان معرفی نوع داده ی استرینگ گفتیم که این آبجکت ها از نوع دنباله هستند، چرا که هر آبجکت استرینگ از تعدادی حرف ساخته شده است که به ترتیب و پشت سر هم در یک ردیف به دنبال هم آمده اند. جایگاه هر یک از حروف در این دنباله ثابت است، به طوری که اگر جای یکی از اعضای دنباله را با عضو دیگری عوض کنیم دنباله ی جدیدی ایجاد می شود. برای مثال دنباله های “eat” و “ate” با وجود آن که از حروف یکسانی تشکیل شده اند، اما چون ترتیب اعضای آن ها با هم فرق دارد دو دنباله ی متفاوت هستند. اگرچه در این مثال آبجکت بعد از کیورد in دنباله ای از جنس استرینگ با مقدار “SokanAcademy” است، اما دنباله ها می توانند انواع دیگری هم داشته باشند که در آموزش های آینده با آن ها آشنا خواهیم شد.
بعد از تعریف کردن آبجکت دنباله در این دستور مانند هر دستور مرکب دیگر، سربند آن را با علامت : به پایان می رسانیم. در حقیقت ترجمه ی این سربند به زبان عادی این است که:
برای هر حرف در دنباله ی “SokanAcademy” :
پس همان طور که می بینید در این جا برای دسترسی پیدا کردن به هر عضو یا حرف دنباله از متغیر letter استفاده می کنیم و هر بار که لوپ for تکرار شود، این متغیر به ترتیب به یکی از حروف “SokanAcademy” منتسب می شود.
دستورات داخل بدنه ی لوپ for با رعایت تورفتگی نسبت به بلوک سربند آن در یک بلوک مجزا نوشته می شود. این دستورها همان کدهایی هستند که می خواهیم در هر نوبت از اجرای لوپ توسط مفسر اجرا شوند. در این مثال همان طور که پیش تر گفتیم ابتدا دستور ۱ =+ letteNum در بدنه ی لوپ برای افزودن یک واحد به مقدار متغیر letterNum استفاده شده است. سپس دستور پرینت را در بدنه ی لوپ قرار داده ایم. در این فانکشن از پنج آرگومان استفاده کرده ایم. سه آرگومان از نوع استرینگ و دو آرگومان متغیر، یکی letterNum که شماره ی حرف را در کلمه ی “SokanAcademy” نشان می دهد و دیگری letter که نشان دهنده ی خود آن حرف است. در نهایت هم پس از خروج از بدنه ی لوپ for از یک دستور پرینت استفاده کرده ایم تا پس از پایان تکرارها در لوپ for، تعداد حروف کلمه را در خروجی چاپ کند. خروجی این برنامه به صورت زیر است:
========== RESTART: C:/SokanAcademy/ForLoop.py ========== Letter 1 is S . Letter 2 is o . Letter 3 is k . Letter 4 is a . Letter 5 is n . Letter 6 is A . Letter 7 is c . Letter 8 is a . Letter 9 is d . Letter 10 is e . Letter 11 is m . Letter 12 is y . SokanAcademy has 12 letters. >>>
بنابراین فرم کلی لوپ for را می توانیم به صورت زیر در نظر بگیریم:
for target in object: # Assign object items to target block(s) of statements # Repeated loop body: uses target
در حالت عادی، بر اساس این الگو هر لوپ for دقیقاً به تعداد عضوهای دنباله ی object تکرار می شود، به این شکل که متغیر target هر بار با رعایت ترتیب به یکی از اعضای دنباله، با شروع از عضو اول و در ادامه به سایر اعضا منتسب می شود و دستورات داخل بدنه ی لوپ اجرا می شوند. این عملیات تکراری ادامه پیدا می کند تا دستورهای داخل لوپ به ازای تمام اعضای دنباله ی object اجرا شوند.
در پاراگراف قبل اشاره ای داشتیم که لوپ for در حالت عادی به ازای تمام اعضای دنباله اجرا می شود؛ با این حال باید بدانید که در لوپ for هم مانند لوپ while امکان استفاده از دستورهای break و continue برای تغییر جریان عادی اجرای لوپ، و هم چنین دستور else وجود دارد. در ادامه کاربرد این دستورها را در لوپ for در قالب مثال هایی می بینیم.
کاربرد دستور break در لوپ for
برنامه ی زیر که اسکریپت آن در فایل ForBreak.py ذخیره شده است را در نظر بگیرید:
username = input("Enter a username less than 6 characters: ") letterNum = 1 for letter in username: print("Letter ", letterNum, " is ", letter) letterNum+=1 if letterNum > 6: print("Your username is too long!") break
این برنامه به شکلی کدنویسی شده است که یک مقدار ورودی را از کاربر دریافت می کند و آن را به متغیر username ارجاع می دهد. سپس با استفاده از یک لوپ for مانند مثال قبل حروف به کار رفته در کلمه ی ورودی را در خروجی چاپ می کند؛ با این تفاوت که یک محدودیت در تعداد کارکترهای کلمه ی وارد شده توسط کاربر در نظر گرفته شده است و از او خواسته شده تا کلمه ای ۶ حرفی یا کم تر را وارد کند.
دستور شرطی if که در بدنه ی لوپ for قرار داده شده است این شرط را بررسی می کند. زمانی که کاربر کلمه ی مورد نظر خود را وارد می کند و لوپ for اجرا می شود، حروف این کلمه به ترتیب با استفاده از دستور پرینت چاپ می شوند و مقدار متغیر letterNum که در این برنامه هم چون مثال قبل تعداد حروف کلمه ی وارد شده را شمارش می کند یک واحد اضافه می شود. حال اگر کاربر شرط را رعایت نکند و کلمه ای با تعداد بیش تر از ۶ حرف را وارد کند، زمانی که لوپ برای بار ششم اجرا می شود متغیر letterNum به عدد صحیح ۷ منتسب می شود و در این صورت شرط دستور if برابر با true ارزیابی خواهد شد و دستورات بدنه ی آن اجرا می شوند. در بدنه ی if از دستور پرینت برای چاپ پیغام “کلمه ی کاربری شما بیش از حد طولانی است!” استفاده شده است و پس از اجرای این دستور، دستور break اجرا خواهد شد که باعث می شود مفسر پایتون به طور کامل از لوپ for خارج شود و بقیه حروف کلمه ی وارد شده چاپ نشوند. برای مثال یک نمونه از خروجی برنامه ی فوق به صورت زیر خواهد بود:
========== RESTART: C:/SokanAcademy/ForBreak.py ========== Enter a username less than 6 characters: NargesAsadi Letter 1 is N Letter 2 is a Letter 3 is r Letter 4 is g Letter 5 is e Letter 6 is s Your username is too long! >>>
همان طور که می بینید اجرای لوپ for برای ۶ بار تکرار شده و سپس مفسر به طور کامل از آن خارج شده است.
کاربرد دستور continue در لوپ for
برنامه ی زیر که اسکریپت آن در فایل ForContinue.py ذخیره شده است را در نظر بگیرید:
letterNum = 0 for letter in "SokanAcademy": letterNum+=1 if (letter == "a" or letter == "A"): print("Letter ", letterNum, " is ", letter,"and not processed.") continue print("Letter ", letterNum, " is ", letter)
این برنامه مانند مثال اول است، و می خواهیم حروف نام تجاری “SokanAcademy” را در خروجی چاپ کند؛ با این تفاوت که علاقه ای به چاپ حروف a یا A در آن نداریم. برای این کار یک دستور if به بدنه ی لوپ for افزوده شده است. در صورتی که شرط این دستور برقرار باشد، یعنی متغیر letter به یکی از حروف a یا A منتسب شده باشد، مفسر پایتون وارد بدنه ی if می شود و ابتدا دستور پرینت اجرا خواهد شد که پیغام می دهد حرف a در برنامه پردازش نشده است. سپس مفسر دستور continue را اجرا می کند. با اجرای این دستور سایر دستورهایی که در ادامه آمده اند اجرا نخواهند شد و مفسر مجدداً به ابتدای لوپ برمی گردد و دور بعدی تکرار را با حرف بعدی شروع می کند. خروجی این برنامه به صورت زیر است:
======== RESTART: C:\SokanAcademy\ForContinue.py ======== Letter 1 is S Letter 2 is o Letter 3 is k Letter 4 is a and not processed. Letter 5 is n Letter 6 is A and not processed. Letter 7 is c Letter 8 is a and not processed. Letter 9 is d Letter 10 is e Letter 11 is m Letter 12 is y >>>
همان طور که می بینید حروف چهارم، ششم، و هشتم در خروجی چاپ نشده اند. به خاطر داشته باشید زمانی که می خواهیم بعضی از اعضای یک دنباله را بررسی کنیم اما علاقه ای به بررسی تمام اعضای آن نداریم می توانیم از لوپ for و یک دستور continue درون آن استفاده کنیم. در چنین شرایطی دستور break کاربرد ندارد، چرا که اگر در یک دور تکرار لوپ به عضوی برسیم که علاقه ای به آن نداریم و با دستور break بررسی آن را کنسل کنیم بقیه ی اعضای دنباله هم که در ادامه ی آن عضو آمده اند بررسی نخواهند شد، اما دستور continue تنها همان یک دور از تکرار لوپ را نادیده خواهد گرفت و بقیه ی تکرارها را اجرا خواهد کرد.
کاربرد دستور range در لوپ for
فرض کنید بخواهیم دنباله ای از اعداد صحیح ۰ تا ۹ را در نظر بگیریم و در لوپ از آن استفاده کنیم. یکی از روش های ایجاد این دنباله استفاده از دستور range است که سازنده ی آبجکتی از نوع range است. البته ما هنوز در مورد مفاهیم Constructor (کانستراکتور یا سازنده) کلاس ها توضیحی نداده ایم، اما فعلاً این دستور را مانند یک تابع در نظر می گیریم که یک عدد صحیح مثبت -برای مثال ۱۰- را به عنوان آرگومان ورودی می گیرد و بازه یا دنباله ای از اعداد ۰ تا ۹ را تولید می کند. یکی از کاربردهای range در لوپ for است. برای مثال برنامه ی زیر که اسکریپت آن را در فایل range.py ذخیره کرده ایم را در نظر بگیرید
# range(stop) for i in range(10): print(i)
خروجی این برنامه به صورت زیر است:
۰ ۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ >>>
بنابراین می توانیم با دادن نقطه ی پایانی به دستور range دنباله ای از اعداد صحیح کم تر از آن عدد را که از صفر شروع می شود به دست بیاوریم. گاهی نیاز داریم که دنباله ای از اعداد صحیح را در بازه ی مشخصی ایجاد کنیم. برای این کار از الگوی (range(start, stop استفاده می کنیم و دو آرگومان یکی به عنوان نقطه ی شروع و دیگری به عنوان نقطه ی پایانی به دستور range می دهیم. برای مثال برنامه ی زیر را در نظر بگیرید:
# range(start,stop) for i in range(5,10): print(i)
خروجی این برنامه به صورت زیر است:
۵ ۶ ۷ ۸ ۹ >>>
همان طور که می بینید در خروجی برنامه اعضای دنباله ی تولید شده توسط دستور ()range آمده است که اولین عضو آن برابر با اولین آرگومان داده شده به دستور ()range، یعنی عدد صحیح ۵ است و اعضای بعدی نیز به ترتیب آمده اند و با رسیدن به نقطه ی انتهایی یعنی عدد صحیح ۱۰ که با آرگومان دوم تعیین می شود دنباله پایان می یابد و خود عدد ۱۰ به عنوان عضو دنباله حساب نمی شود.
گاهی ممکن است ما بخواهیم دنباله ای از اعداد را داشته باشیم که اعضای آن با هم فاصله یکسان اما بیش تر از یک داشته باشند. در این شرایط می توانیم از دستور ()range با الگوی (range(start, stop, step استفاده کنیم. برای مثال برنامه ی زیر را در نظر بگیرید:
# range(start,stop,step) for i in range(0,20,3): print(i)
خروجی این برنامه به صورت زیر است:
۰ ۳ ۶ ۹ ۱۲ ۱۵ ۱۸ >>>
همان طور که می بینید اعضای دنباله ی تولید شده در این مثال در بازه ی ۰ تا ۲۰ قرار می گیرند (البته خود ۲۰ را شامل نمی شود) و هر عضو با عضو قبل و بعد از خود به اندازه ی ۳ گام یا ۳ واحد فاصله دارد. البته می توان از این الگو به صورت دیگری هم استفاده کرد که نمونه ی آن را در برنامه ی زیر می بینید:
# range(start,stop,negativeStep) for i in range(20,2,-2): print(i)
خروجی این برنامه به صورت زیر است:
۲۰ ۱۸ ۱۶ ۱۴ ۱۲ ۱۰ ۸ ۶ ۴ ۲ >>>
همان طور که می بینید این بار دنباله با عدد بزرگ تر آغاز می شود و با گام های متوالی منفی به سمت عدد کوچک تر دنباله که در انتها قرار دارد می رود و در آخر باز هم عدد صفر که آرگومان پایان دهنده ی ()range است چاپ نمی شود. توجه داشته باشید که در این الگو هر سه آرگومان باید از نوع اعداد صحیح باشند. برای تعیین آرگومان stop منفی، باید آرگومان گام را نیز به شکل منفی تعیین کنیم.
استفاده از لوپ های for به صورت تو در تو
پیش از این گفتیم که از دستورهای مرکب پایتون می توان در بدنه ی هم به صورت تو در تو استفاده کرد؛ بنابراین همان طور که از دستور if در بدنه ی یک لوپ می توانیم استفاده کنیم، از یک دستور لوپ for هم می توانیم در لوپ دیگری استفاده کنیم. برای مثال برنامه ی زیر که اسکریپت آن در فایل NestedLoop.py ذخیره شده است را در نظر بگیرید:
for i in range(1, 4): for j in range(1, 4): print(i,"*",j," = ",i * j)
در این برنامه از دو لوپ for به صورت تو در تو استفاده کرده ایم که خروجی آن به صورت زیر است:
========= RESTART: C:/SokanAcademy/NestedLoop.py ========= ۱ * ۱ = ۱ ۱ * ۲ = ۲ ۱ * ۳ = ۳ ۲ * ۱ = ۲ ۲ * ۲ = ۴ ۲ * ۳ = ۶ ۳ * ۱ = ۳ ۳ * ۲ = ۶ ۳ * ۳ = ۹ >>>
استفاده از دستور else در لوپ for
اگر به خاطر داشته باشید در زمان بکارگیری لوپ while می توانستیم از دستور else هم استفاده کنیم و در صورتی که مفسر با دستور break از بدنه ی لوپ خارج نمی شد، بدنه ی دستور else را اجرا می کرد. در لوپ for هم می توانیم از دستور else استفاده کنیم. برای مثال برنامه ی زیر که اسکریپت آن را در فایل ForElse.py ذخیره کرده ایم را در نظر بگیرید:
n = int(input("Enter a number -->")) for i in range(2, n): if n % i == 0: print(n, "is not a prime number") break else: print(n, "is a prime number")
در این برنامه عددی را از کاربر دریافت می کنیم و می خواهیم برنامه بگوید که عدد وارد شده یک عدد اول است یا نه؟
بر اساس تعریف بالا می توانیم اول بودن یک عدد را این طور تست کنیم که آن را بر تمام اعداد کوچک تر از خودش تقسیم کنیم. لذا از یک لوپ for استفاده کرده ایم و با استفاده از دستور (range(2, n دنباله ای که از عدد ۲ شروع می شود و تمام اعداد کوچک تر از عدد وارد شده توسط کاربر -یعنی n- در برمی گیرد را برای استفاده در لوپ تولید کرده ایم.
حال در هر بار تکرار لوپ for یک دستور شرطی if بررسی می شود. اگر عدد n بر عضوی از دنباله بخش پذیر باشد شرط if برابر با true ارزیابی می شود و دستورهای داخل بدنه ی آن اجرای می شوند. یعنی ابتدا دستور پرینت در خروجی چاپ می کند که عدد وارد شده اول نیست و بعد مفسر با اجرای دستور break از بدنه ی لوپ خارج می شود. در این صورت دستور بدنه ی else هم که بعد از لوپ for آمده است اجرا نخواهد شد. برای مثال نمونه ای از این حالت با وارد کردن عدد غیر اول ۲۵ در زمان اجرای برنامه اتفاق می افتد:
========== RESTART: C:/SokanAcademy/ForElse.py ========== Enter a number -->25 ۲۵ is not a prime number. >>>
اما در حالتی که عدد وارد شده به هیچ کدام از اعداد صحیح کوچک تر از خود بخش پذیر نباشد، در هیچ یک از تکرارهای لوپ for مفسر وارد بدنه ی دستور شرطی if نخواهد شد و در این صورت با پایان یافتن لوپ بدون برخورد با تابع break از لوپ خارج خواهد شد. در این شرایط دستور داخل بدنه ی else اجرا می شود و تابع ()print عبارتی را در خروجی چاپ می کند که می گوید عدد وارد شده توسط کاربر یک عدد اول است. برای نمونه اگر کاربر عدد ۲۳ که یک عدد اول است را وارد کند برنامه خروجی زیر را به او خواهد داد:
========== RESTART: C:/SokanAcademy/ForElse.py ========== Enter a number -->23 ۲۳ is a prime number >>>
بنابراین فرم کلی لوپ for به صورت زیر خواهد بود:
for target in object: # Assign object items to target statements # Repeated loop body: use target else: # Optional else part statements # If we didn't hit a 'break'
لیست ها
ما از لیست ها برای سازماندهی اطلاعات و دسترسی و تغییر سریع تر آن ها استفاده می کنیم. برای مثال لیستی از اسامی دانش آموزان یک کلاس را در نظر بگیرید که به ترتیب حروف الفبا مرتب شده اند. با استفاده از چنین لیستی، دسترسی به اطلاعات دانش آموزان کلاس و تغییر یا به روزرسانی آن ها راحت تر خواهد شد. نمونه ای دیگر از کاربرد لیست ها در دنیای واقعی، لیست های خرید است تا در زمان خرید با استفاده از یک چک لیست ساده بدانیم کدام یک از کالاهای مورد نیاز خود را خریداری کرده ایم و کدام یک از اقلام داخل لیست باقی مانده اند.
همان طور که می بینید کاربرد لیست ها در زندگی روزمره بسیار زیاد است و ما می توانیم بی نهایت مثال در این جا بیاوریم که برای ذخیره ی داده ها و دسترسی و تغییر آسان آن ها از لیست ها استفاده می کنیم؛ بنابراین با توجه به این کاربرد گسترده، طراحان زبان برنامه نویسی پایتون نیز مفهوم لیست را در قالب آبجکتی از نوع List وارد این زبان برنامه نویسی کرده اند تا برنامه نویسان بتوانند از مزایای استفاده از لیست ها در زمان کدنویسی برنامه ها هم بهره مند شوند. در این آموزش با نحوه ی ایجاد آبجکت هایی از نوع لیست و دسترسی به اطلاعات درون لیست ها و مدیریت اطلاعات آن ها آشنا خواهیم شد.
در زبان پایتون لیست ها به عنوان نوعی از دنباله تعریف می شوند. اگر به خاطر داشته باشید قبلاً در مورد دنباله ها مطالبی را بیان کردیم و گفتیم آبجکت هایی از جنس استرینگ هم از نوع دنباله هستند. دنباله ها را مانند زنجیره ای از اشیاء در نظر گرفتیم که در قالب شیئی از نوع دنباله به هم متصل شده اند، اما می توانیم به هر یک از اشیاء این زنجیره ی به هم پیوسته دسترسی داشته باشیم. برای مثال می توانیم به تک تک حروف یک دنباله ی استرینگی دسترسی داشته باشیم و یا می توانیم حروف اول و آخر آن را در خروجی چاپ کنیم. پیش از این هم گفتیم که دنباله ها انواع زیادی دارند که با آن ها آشنا خواهیم شد؛ با این حال نوع داده ی لیست یکی از ملموس ترین و قابل فهم ترین دنباله ها برای برنامه نویسان است، چرا که همان طور که در ابتدا گفتیم در دنیای واقعی استفاده زیادی از لیست ها می کنیم.
در دنیای واقعی قبل از استفاده از لیست ها باید آن ها را ایجاد کنیم. در زمان کدنویسی برنامه ها هم برای استفاده از لیست ها ابتدا باید آن ها را برای مفسر پایتون تعریف کنیم. برای این کار از علامت کروشه [] استفاده می کنیم و آبجکت هایی که می خواهیم عضو لیست باشند را در میان این دو علامت می آوریم و با علامت کاما (,) از هم جدا می کنیم. برای مثال لیست های زیر را در نظر بگیرید:
>>> listA = [1, 2, 3, 4] >>> listB = ["Spring", "Summer", "Autumn", "Winter"] >>> listC = ["One", 2, "Three", 4, False] >>> listD = [True, False] >>> listE =[] >>> listF = [listA, listB, [1,2,3]]
همان طور که از این مثال ها مشخص است تعداد اعضای لیست ها متفاوتند و می توانیم در هر لیست به تعداد دلخواه آبجکت قرار دهیم. کامپیوتر هر عضو لیست را در یک محل مجزا از حافظه ی خود قرار می دهد. فضای این حافظه بهم پیوسته است و هر زمان که آیتم جدیدی به لیست اضافه شود، آن آیتم در محل بعدی حافظه قرار می گیرد. کامپیوتر برای دسترسی به هر عضو یک اندیس را به حافظه ی آن نسبت می دهد. این اندیس ها از شماره ی صفر آغاز می شوند و به ترتیب یک واحد بزرگ تر می شوند. برای مثال در listA عضو اول که عدد صحیح ۱ است اندیس ۰، عضو دوم یا عدد صحیح ۲ اندیس ۱، عضو سوم یا عدد صحیح ۳ اندیس ۲، و در نهایت عضو آخر که عدد صحیح ۴ است اندیس ۳ می گیرد. بنابراین اندیسی که به آخرین عضو لیست داده می شود یک واحد کم تر از تعداد اعضای لیست است.
نکته ی بعدی که می توانیم در مورد اعضای لیست ها بگوییم از مثال سوم یعنی listC قابل دریافت است. همان طور که می بینید اعضای این لیست برخلاف دو لیست اول از نوع یکسانی نیستند؛ به عبارت دیگر در میان اعضای این لیست داده هایی از جنس استرینگ، عدد صحیح، و بولین می بینیم. این نکته در مورد تمام لیست ها صادق است و هر آبجکت از نوع لیست در زبان پایتون می تواند اعضایی از دیتا تایپ های مختلف داشته باشد.
هشدار
همان طور که از مثال listE مشخص است یک لیست می تواند هیچ عضوی نداشته باشد، با این حال علامت کروشه [] هنوز هم برای مفسر پایتون تعریف کننده ی یک لیست است. برای اطمینان از این موضوع از فانکشن ()type استفاده می کنیم تا نوع این متغیر را بررسی کنیم:
>>> type(listE) <class 'list'>
همان طور که در خروجی مشخص است این متغیر از کلاس list است. گفتیم که اعضای یک لیست می توانند انواع متفاوت و دلخواهی داشته باشند. برای نمونه در مثال listF می بینیم که تمام اعضای این لیست، خود یک لیست هستند؛ بنابراین از لیست ها می توان به صورت تودرتو نیز استفاده کرد.
در این آموزش با نحوه ی تعریف آبجکت هایی از نوع list در زبان برنامه نویسی پایتون آشنا شدیم. در آموزش های بعدی به نحوه ی دسترسی به اعضای لیست و مدیریت آن ها خواهیم پرداخت.
دسترسی به محتوای لیست
در آموزش گذشتهبا نحوه ی تعریف و ایجاد آبجکت هایی از نوع لیست در زبان پایتون آشنا شدیم. گفتیم هدف ما از ایجاد لیست ها، دسترسی و مدیریت آسان اطلاعات درون آن ها است. برای این کار لازم است به نحوی به اعضای درون یک لیست دسترسی پیدا کنیم. فرض کنید که بخواهیم محتوای داخل یکی از لیست هایی که در آموزش قبل تعریف کردیم را در خروجی نمایش دهیم. برای این کار از دستور پرینت استفاده می کنیم. برای مثال داریم:
>>> listA = [1, 2, 3, 4, 5] >>> print(listA) [۱, ۲, ۳, ۴, ۵] >>>
با این وجود، عموماً این سطح از دسترسی مطلوب نیست و ما می خواهیم به تک تک اعضای درون لیست به صورت جداگانه یی دسترسی داشته باشیم. برای این منظور کافی است به صورت زیر عمل کنیم:
>>>print(listA[0]) ۱
ان طور که در کد پایتون بالا می بینید، برای چاپ اولین عضو لیست ابتدا شناسه ی لیست که listA است را می آوریم و بلافاصله بعد از آن درون کروشه اندیس عضو مورد نظر خود که ۰ است را قرار می دهیم. خروجی این دستور عضو اول لیست است.
نکته
به همین ترتیب می توانیم به تمام اعضای لیست با استفاده از اندیس های آن ها به صورت جداگانه دسترسی پیدا کنیم:
>>> listA[1] ۲ >>> listA[2] ۳ >>> listA[3] ۴ >>> listA[4] ۵
در مثال بالا listA پنج عضو دارد بنابراین اندیسی که به اعضای آن داده می شود در بازه ی ۰ تا ۴ قرار می گیرد. در این شرایط اگر از مفسر پایتون بخواهیم عضوی با اندیس بیش تر از ۴ را به ما نشان دهد با خطای زیر مواجه خواهیم شد:
>>> listA[5] Traceback (most recent call last): File "<pyshell#14>", line 1, in listA[5] IndexError: list index out of range
در خط آخر، مفسر پایتون به ما نشان می دهد که اندیس استفاده شده در این دستور در دامنه ی مجاز قرار نمی گیرد؛ به عبارت دیگر هیچ عضوی در این لیست با چنین اندیسی وجود ندارد. حال فرض کنید بخواهیم همزمان به زیر مجموعه ای از اعضای یک لیست دسترسی داشته باشیم که بیش تر از یک عضو را شامل می شود ولی تمام اعضای آن را در برنمی گیرد. برای این کار از بازه ای از اندیس ها که زیر مجموعه ی کل اندیس ها است استفاده می کنیم. برای مثال فرض کنید در listA بخواهیم اعضایی که اندیس ۱ تا ۳ دارند را مشخص کنیم. برای این کار از دستور زیر استفاده می کنیم:
>>> listA[1:4] [۲, ۳, ۴]
همان طور که می بینید، در دستور بالا از الگویی به شکل [listName[i:j استفاده کرده ایم. i نشان دهنده ی اندیس اولین عضوی از لیست است که می خواهیم به آن دسترسی داشته باشیم که در این جا برابر با ۱ است و j هم عددی است که یک واحد بیش تر از اندیس آخرین عضوی از لیست است که می خواهیم آن را نمایش دهیم که در این جا چون می خواهیم عضوی را که اندیس آن ۳ است به عنوان آخرین عضو در نظر بگیریم، از عدد ۴ به جای j استفاده می کنیم. به عبارت دیگر، با استفاده از این الگو به اعضایی از لیست که اندیس آن ها بزرگ تر یا مساوی i و کوچک تر از j است دسترسی پیدا می کنیم. حال مثال زیر را در نظر بگیرید:
>>> listA[2:] [۳, ۴, ۵]
در این دستور از الگوی [:listName[i استفاده کرده ایم تا اعضایی از listA را که اندیس آن ها بزرگ تر یا مساوی i که در این جا برابر با ۲ است را پیدا کنیم. حال برای دسترسی به اعضایی از listA که اندیس آن ها کوچک تر از عدد ۳ باشد دستوری را به صورت زیر وارد می کنیم:
>>> listA[:3] [۱, ۲, ۳]
همان طور که می بینید در دستور بالا از الگوی [listName[:j استفاده کرده ایم تا به اعضایی از لیست را که اندیس آن ها کوچک تر از عدد صحیح j و نه مساوی با آن است دسترسی داشته باشیم.
جالب است بدانید که در زبان پایتون اعضای یک آبجکت یا شیء از نوع لیست می توانند اندیس های منفی هم داشته باشند. در این صورت اولین عضوی که در سمت راست لیست قرار می گیرد اندیس ۱- می گیرد. برای مثال می توانیم با اندیس های منفی به اعضای listA به صورت زیر دسترسی داشته باشیم:
>>> listA[-1] ۵ >>> listA[-2] ۴ >>> listA[-3] ۳ >>> listA[-4] ۲ >>> listA[-5] ۱
تاکنون دیدیم که چطور می توانیم به اعضای داخل یک لیست دسترسی پیدا کنیم. حال در نظر بگیرید که بخواهیم عمل ثابتی را روی تک تک اعضای یک لیست انجام دهیم. برای مثال فرض کنید لیستی از وزن های گروهی از ورزشکاران را داریم و می خواهیم بر اساس معیار وزن، آن ها را در سه دسته ی سبک وزن، متوسط، و سنگین وزن تقسیم بندی کنیم. برای این کار لازم است که وزن هر ورزشکار را به صورت جداگانه بررسی کنیم. اگر وزن ورزشکار کم تر ۵۵ کیلوگرم باشد در دسته ی سبک وزن، بین ۵۵ تا ۸۵ در دسته ی متوسط، و بیش تر از ۸۵ کیلوگرم در دسته ی سنگین وزن جای می گیرد. فرض کنیم لیست مورد نظر ما به شکل زیر باشد:
weightList = [['A', 64], ['B', 92], ['C', 49], ['D', 110], ['E', 51], ['F', 73]]
در این جا از لیست های تو در تو استفاده کرده ایم به این شکل که اعضای لیست هر کدام یک لیست هستند که عضو اول آن ها شناسه ی ورزشکار و عضو دوم آن ها وزن ورزشکار است. مثلاً اولین عضو لیست وزن ها، لیستی است که متعلق به ورزشکار A با وزن ۶۴ کیلو گرم است. حال برای آن که بررسی های مورد نظر را برای تک تک ورزشکاران انجام دهیم از یک لوپ for استفاده می کنیم. برای این کار برنامه ای را به شکل زیر می نویسیم:
weightList = [['A', 64], ['B', 92], ['C', 49], ['D', 110], ['E', 51], ['F', 73]] for item in weightList: if(item[1] <= 55): print("Athlete", item[0], "is light-weight.") elif(55 < item[1] <= 85 ): print("Athlete", item[0], "is in average weight.") else: print("Athlete", item[0], "is heavy-weight.")
پیش از این گفتیم که هر دستور مرکب که با کیورد for آغاز شود در ادامه ی آن نام یک شناسه می آید که در اینجا شناسه ی استفاده شده item است. این متغیر در هر با تکرار لوپ به یکی از اعضای دنباله ای که بعد از کیورد in می آید و در این جا همان لیست weightList است منتسب می شود، در نتیجه در بدنه ی لوپ هر بار یکی از اعضای این لیست مورد بررسی قرار می گیرد. از آن جا که اعضای weightList خود یک لیست هستند متغیر item هر بار به یک لیست با دو عضو منتسب می شود که با دستور [item[0 به عضو اول آن که مشخصه ی ورزشکار و با دستور [item[1 به عضو دوم آن که وزن ورزشکار است دسترسی پیدا می کنیم.
در بدنه ی لوپ for با استفاده از دستورهای شرطی عضو دوم متغیر item یا وزن هر ورزشکار مورد بررسی قرار می گیرد و در صورتی که در هر یک از شرط ها صدق کند پیغام متناسب با آن در خروجی چاپ می شود. برنامه را در فایل ListLoop.py ذخیره و اجرا می کنیم که خروجی آن به شکل زیر خواهد بود:
========== RESTART: C:/SokanAcademy/ListLoop.py ========== Athlete A is in average weight. Athlete B is heavy-weight. Athlete C is light-weight. Athlete D is heavy-weight. Athlete E is light-weight. Athlete F is in average weight. >>>
ویرایش محتوای لیست
در آموزش های گذشته با مفهوم لیست ها و نحوه ی تعریف و دسترسی به محتوای درون آن ها در زبان برنامه نویسی Python آشنا شدیم. جالب است بدانید که پس از تعریف یک آبجکت یا شیء از نوع لیست، می توانید آن را بر اساس نیاز خود ویرایش کنید. ویرایش یک لیست می تواند به صورت تغییر یک آیتم خاص در آن، افزودن یک آیتم جدید به آن، یا حذف یک آیتم از اقلام آن باشد. در حقیقت به کمک فانکشن های از پیش تعریف شده در زبان پایتون که روی لیست ها عمل می کنند، می توانیم عملیات CRUD که عبارت است از Create یا «ایجاد»، Read یا «خواندن»، Update یا «به روزرسانی» و Delete یا «حذف» را روی آن ها اجرا کنیم. در این آموزش به بررسی برخی از مهم ترین فانکشن های قابل استفاده روی لیست ها می پردازیم. برای شروع کار، متغیر list1 که به آبجکتی از نوع لیست منتسب شده است را در نظر بگیرید:
>>>list1 = []
همان طور که می بینید، این لیست هیچ عضوی ندارد. به هر حال، با استفاده از فانکشن ()len می توانیم تعداد اعضای لیست یا طول لیست (چون لیست ها از جنس دنباله هستند) را به دست آوریم:
>>>len(list1) ۰
حال فرض کنید بخواهیم آیتم جدیدی به این لیست اضافه کنیم؛ برای این کار از فانکشن ()append به صورت زیر استفاده می کنیم:
>>> list1.append("egg")
به فرم نوشتن دستور بالا دقت کنید. فانکشن هایی مانند ()append روی یک نمونه آبجکت خاص از یک کلاس اجرا می شوند. برای استفاده از این نوع فانکشن ها، ابتدا آبجکت مورد نظر خود را می آوریم که در این جا آبجکت ارجاع داده شده به متغیر list1 است، سپس در ادامه ی آن یک علامت . می آوریم و آن گاه فانکشن مورد نظر را به همراه آرگومان های آن که در این جا (“append(“egg است می نویسیم (در آموزش های آینده با این نوع فراخوانی بیش تر آشنا خواهیم شد.) پس از اجرای دستور بالا، list1 را مجدداَ فراخوانی می کنیم تا ببینیم که با اثر دادن این فانکشن روی آن، چه تغییری در محتوای لیست صورت پیدا کرده است:
>>> list1 ['egg'] >>> len(list1) ۱
همان طور که در خروجی می بینید استرینگ ‘egg’ به list1 اضافه شده است و حالا طول این لیست که قبلاً ۰ بود برابر با ۱ است. بنابراین فانکشن ()append یک مقدار را در یک لیست ذخیره می کند. با استفاده از این فانکشن مقادیر دیگری را در لیست خود ذخیره می کنیم:
>>> list1.append("meet") >>> list1.append("tea") >>> list1.append("rice") >>> list1 ['egg', 'meet', 'tea', 'rice']
عضو سوم این لیست را در نظر بگیرید:
>>> list1[2] 'tea'
فرض کنید بخواهیم آبجکت جدیدی را قبل از این عضو به لیست اضافه کنیم. همان طور که دیدیم فانکشن ()append اعضای جدید را در انتهای لیست اضافه می کرد، بنابراین در این مورد باید به دنبال استفاده از فانکشن دیگری باشیم. پایتون برای این کار فانکشن ()insert را در اختیار ما قرار می دهد. نحوه ی استفاده از این فانکشن به صورت زیر است:
>>> list1.insert(2,"bread")
همان طور که می بینید، فانکشن ()insert دو آرگومان ورودی می گیرد؛ آرگومان اول اندیس محل قرار گیری عضو جدید در لیست است که در این جا ۲ را در نظر گرفته ایم و آرگومان دوم آن عضو جدیدی است که می خواهیم به لیست اضافه کنیم. اکنون با فراخوانی متغیر list1 تغییرات آن را پس از اثر دادن فانکشن ()insert می بینیم:
>>> list1 ['egg', 'meet', 'bread', 'tea', 'rice']
حال دستور زیر را در نظر بگیرید:
>>> list2 = list1.copy()
در این دستور، متغیر جدیدی با شناسه ی list2 ایجاد کرده ایم و یک کپی از list1 را به آن ارجاع داده ایم. برای کپی کردن list1 از فانکشن copy استفاده کرده و آن را روی list1 اثر داده ایم. اکنون محتوای list2 به صورت زیر خواهد بود:
>>> list2 ['egg', 'meet', 'bread', 'tea', 'rice']
اغلب از فانکشن copy زمانی استفاده می کنیم که بخواهیم به صورت موقتی اصلاحاتی را روی لیست خود ایجاد کنیم و مواردی را امتحان کنیم بدون آن که لیست اصلی ما دچار تغییر شود. حتی در صورت تغییر در لیست دوم می توانیم آن را حذف کنیم یا حتی محتوای آن را در لیست اولیه کپی کنیم. برای مثال فرض کنید بخواهیم عضو آخر list2 را حذف کنیم. برای این کار به صورت زیر عمل می کنیم:
>>> list2.remove("rice")
در این جا با اعمال کردن فانکشن ()remove روی list2 عملیات مورد نظر خود را انجام داده ایم. فانکشن ()remove یکی از اعضای لیست را به عنوان آرگومان می گیرد و آن را از لیست حذف می کند. دقت داشته باشید که این آرگومان، خود آن عضو از لیست است نه اندیس آن. اکنون list2 به صورت زیر درآمده است:
>>> list2 ['egg', 'meet', 'bread', 'tea']
نکته
برای تست کردن نکته ی بالا، اکنون استرینگ “rice” عضو list2 نیست، بنابراین با اجرای دستور
>>> list2.remove("rice")
پیغام خطایی به شکل زیر دریافت می کنیم:
Traceback (most recent call last): File "<pyshell#21>", line 1, in list2.remove("rice") ValueError: list.remove(x): x not in list
که در خط آخر اشاره کرده است آرگومان داده شده به فانکشن ()remove در لیست وجود ندارد. علاوه بر این مورد، دقت داشته باشید که فانکشن ()remove تنها یک آرگومان ورودی می گیرد و نمی توان هم زمان چند عضو لیست را با استفاده از آن حذف کرد.
در صورتی که بخواهیم تمام اعضای یک لیست را به محتوای لیست دیگری اضافه کنیم از دستور زیر استفاده می کنیم:
>>> list1.extend(list2)
فانکشن ()extend که در این جا list2 را به عنوان آرگومان خود گرفته است تمام اعضای آن را به انتهای list1 اضافه می کند. بنابراین داریم:
>>> list1 ['egg', 'meet', 'bread', 'tea', 'rice', 'egg', 'meet', 'bread', 'tea'] >>> list2 ['egg', 'meet', 'bread', 'tea']
حال دستور زیر را اجرا می کنیم:
>>> list1.pop() 'tea'
در این دستور از فانکشن ()pop استفاده کرده ایم و آن را روی list1 اعمال کرده ایم. خروجی این دستور، عضو آخر list1 یعنی استرینگ ‘tea’ است، با این حال فانکشن ()pop تنها برای دسترسی به عضو آخر لیست استفاده نمی شود و تغییرات دیگری نیز در لیست اعمال می کند. برای آن که متوجه این تغییرات شویم اجازه دهید نگاهی به محتوای list1 بیاندازیم:
>>> list1 ['egg', 'meet', 'bread', 'tea', 'rice', 'egg', 'meet', 'bread']
همان طور که می بینید اثر دادن فانکشن pop روی list1 باعث شده عضو آخر آن که استرینگ ‘tea’ بود از لیست حذف شود. اگر بخواهیم تمام اعضای یک لیست را حذف کنیم از فانکشن ()clear استفاده می کنیم. دستور زیر را در نظر بگیرید:
>>> list1.clear() >>> list1 [] >>> len(list1) ۰
همان طور که می بینید تمام اعضای list1 حذف شده اند و اکنون این لیست هیچ عضوی ندارد.
جست و جو در لیست
در آموزش قبل با نحوه ی ویرایش محتوای لیست ها در زبان برنامه نویسی Python آشنا شدیم؛ با وجود این باید بدانیم برای آن که عملیات ویرایش اقلام درون لیست را بهتر و سریع تر انجام دهیم لازم است با نحوه ی جست و جوی آن ها نیز آشنا باشیم. بنابراین در این آموزش خواهیم دید که چطور می توانیم چنین کاری را انجام دهیم. برای شروع برنامه ی زیر که در فایل SearchList.py ذخیره شده است را در نظر بگیرید:
colors = ["Red", "Green" ,"Orange", "Red", "Yellow", "Green", "Blue"] colorSelect = "" while colorSelect.upper()!= "QUIT": colorSelect = input("Please type a color name: ") if (colors.count(colorSelect) >= 1): print("The color exists in the list!") elif (colorSelect.upper() != "QUIT"): print("The list doesn't contain the color.")
این برنامه با ایجاد یک آبجکت از نوع لیست با شناسه ی color آغاز می شود که در آن نام تعدادی رنگ را به صورت استرینگ ذخیره کرده ایم. سپس متغیر colorSelect را ایجاد کرده ایم تا نام رنگ مورد نظر خود را در آن ذخیره کنیم. آن گاه برنامه وارد لوپی می شود که در آن از کاربر درخواست می شود نام رنگ مورد نظر خود را وارد کند تا به متغیر colorSelect ارجاع داده شود. تا زمانی که کاربر کلمه ی Quit را وارد نکند شرط لوپ while هم چنان برقرار است و از کاربر درخواست می شود نام رنگ مورد نظر خود را وارد کند.
به شرط قرار گرفته در لوپ while در این مثال دقت کنید. متغیر colorSelect به یک استرینگ منتسب شده است و فانکشن ()upper با دستور ()colorSelect.upper روی آن اعمال شده است. خروجی این دستور همان استرینگ منتسب شده به colorSelect است با این تفاوت که تمام حروف آن به شکل بزرگ درآمده اند. بنابراین تفاوتی ندارد که کاربر هر کدام از حروف کلمه ی Quit را به شکل بزرگ وارد کند یا کوچک چون در نهایت تمام حروف کلمه ی وارد شده با استفاده از فانکشن ()upper به شکل بزرگ در می آیند و با کلمه ی QUIT مقایسه می شوند (به عبارت دیگر، تمامی نمونه های quit, Quit, qUIT, quiT و … ابتدا به QUIT تبدیل شده سپس در برنامه مورد استفاده قرار می گیرند.) به خاطر داشته باشید که فانکشن ()lower هم می تواند با اثر کردن روی یک آبجکت از جنس استرینگ، تمام حروف آن را به حالت کوچک درآورد. برای مثال داریم:
>>> var = "LowerCase" >>> var.lower() 'lowercase'
حال شرط دستور if را در داخل بدنه ی لوپ while در نظر بگیرید: colors.count(colorSelect) >= 1. در این دستور شرطی، فانکشن ()count که متغیر colorSelect را به عنوان آرگومان ورودی گرفته است روی لیست colors اعمال کرده است. خروجی فانکشن ()count یک عدد صحیح است و عملکرد آن به این صورت است که درون لیست colors را برای یافتن مقدار آرگومان خود یا همان متغیر colorSelect جستجو می کند و هر بار که مقدار این متغیر را به عنوان یکی از اقلام لیست درون آن پیدا کند مقدار خروجی خود را که به صورت پیش فرض برابر با صفر است یک واحد افزایش می دهد. در نهایت زمانی که جستجو در میان تمام اقلام یک لیست به پایان رسید، تعداد تکرارهای یک آبجکت خاص درون لیست با یک عدد صحیح بزرگ تر یا مساوی صفر مشخص می شود.
در این شرط اگر نام رنگ انتخاب شده توسط کاربر حداقل یک بار در لیست آمده باشد شرط if اجرا می شود و پیغام «!The color exists in the list» به معنای «این رنگ در لیست وجود دارد!» در خروجی چاپ می شود در غیر این صورت شرط elif بررسی می شود و اگر کاربر به جای نام رنگ کلمه ی Quit را برای خروج از لوپ و پایان اجرای برنامه چاپ نکرده باشد دستور داخل بدنه ی آن چاپ می شود و به کاربر پیغام می دهد: «.The list doesn’t contain the color» یعنی «این لیست حاوی این رنگ نیست.» در صورتی که کاربر کلمه ی Quit را وارد کند، شرط لوپ دیگر برقرار نیست بنابراین مسیر اجرای برنامه از آن خارج می شود. برنامه ی بالا را یک بار اجرا می کنیم و خروجی آن را به ازای چند نمونه می بینیم:
======== RESTART: C:/SokanAcademy/SearchList.py ======== Please type a color name: Orange The color exists in the list! Please type a color name: Green The color exists in the list! Please type a color name: Purple The list doesn't contain the color. Please type a color name: qUiT >>>
تغییر پذیری و تغییر ناپذیری
فرض کنید که شما یک تکه کاغذ و یک مداد و پاک کن، به همراه یک خودکار در اختیار دارید و می خواهید متنی را روی این کاغذ یادداشت کنید. شما می دانید که اگر با خودکار روی کاغذ بنویسید دیگر امکان تغییر در متن نوشته شده را ندارید، در حالی که اگر با استفاده از مداد شروع به یادداشت کردن کنید، هر زمان که بخواهید می توانید با استفاده از پاک کن متن نوشته ی خود را پاک کرده و تغییر دهید.
جالب است بدانید که این خاصیت متن های نوشته شده با مداد و خودکار در نوع داده های موجود در زبان پایتون نیز وجود دارد. به عبارت دیگر، برخی از این انواع داده ها تغییر پذیر و برخی دیگر از آن ها تغییرناپذیرند. برای مثال، همان طور که می دانید در زبان پایتون نمی توانیم یک شئ از نوع عددی یا استرینگی را تغییر دهیم، مثلاً مقدار عدد ۲ همیشه برابر با ۲ است و تنها کاری که می توانیم انجام دهیم این است که آن را به متغیرهایی با نام های متفاوت ارجاع دهیم؛ برای مثال یک بار برچسب num1 را به آن بزنیم، یعنی داشته باشیم num1 = 2 و بار دیگر متغیری با شناسه ی num2 یا هر شناسه ی دلخواه دیگری را به آن منتسب کنیم.
در زبان برنامه نویسی پایتون به اشیائی که دارای این خاصیت هستند Immutable یا «تغییر ناپذیر» گفته می شود. در مقابل، انواع داده یی Mutable یا «تغییر پذیر» قرار دارند و همان طور که از نام آن ها پیدا است، پس از ساخت شیئی از این نوع، مقدار این شئ در آینده قابل تغییر است.
به طور مثال، از میان دیتا تایپ های پایتون، لیست ها در دسته ی اشیاء تغییر پذیر قرار می گیرند. در آموزش های قبل دیدیم که چگونه می توانیم با استفاده از فانکشن هایی نظیر ()append()، insert، و ()remove اشیاء جدیدی را به یک لیست اضافه کنیم یا عضوی را از آن خارج کنیم و در نتیجه تغییراتی را در لیست ایجاد کنیم.
با این حال گاهی نیاز داریم تا لیستی ایجاد کنیم که محتویات آن غیر قابل تغییر باشند. چنین لیست هایی در زبان برنامه نویسی پایتون با نوع داده ی تاپل (Tuple) معرفی شده اند که مثل نوع داده ی list است با این تفاوت که تغییرپذیر نیست. برای تعریف یک تاپل، به صورت زیر عمل می کنیم:
>>> colorTuple = ('red', 'green', 'blue', 'yellow') >>> type(colorTuple) <class 'tuple'>
همان طور که می بینید متغیر colorTuple از نوع تاپل است و درست همانند یک لیست تعریف شده است با این تفاوت که اعضای آن به جای قرار گرفتن در میان کروشه های باز و بسته [ ] در میان پرانتزهای باز و بسته () قرار گرفته اند. همان طور که گفتیم، اشیائی از نوع تاپل غیر قابل تغییر هستند بنابراین فانکشن هایی مانند ()sort()، append، یا ()remove روی آن ها به هیچ وجه کار نمی کنند.
مجموعه داده
احتمالاً تا به حال با کسانی برخورد کرده اید که کلکسیونی از اشیاء مختلف مثل ماشین های قدیمی، تمبر، سکه، صفحه های گرامافون، دی وی دی و موارد دیگر را جمع آوری و نگهداری می کنند. در واقع این کلکسیون ها شامل اشیائی هستند که در یک گروه طبقه بندی می شوند. برای جمع آوری این اشیاء در کنار هم نیاز به امکاناتی خواهیم داشت؛ برای مثال، کلکسیون دارهای تمبر از آلبوم های مخصوص برای نگهداری طولانی مدت تمبرها استفاده می کنند. در زبان های برنامه نویسی از جمله پایتون نیز امکاناتی فراهم شده تا برنامه نویسان بتوانند Collection (کالکشن یا گردایه) ای از اشیاء متعلق به یک کلاس را در محلی گردآوری کنند.
پیش از این با مفهوم دنباله ها آشنا شدیم و دانستیم که دنباله ها مانند رشته یی از مقادیر مختلف که به صورت زنجیروار به یکدیگر متصل شده اند، تشکیل می شوند. برای مثال ساده ترین نوع دنباله ها، نوع داده ی استرینگ است که آبجکت های ساخته شده از روی این کلاس شامل زنجیره ای از کاراکترها هستند. پس از آن نیز با نوع داده ی لیست آشنا شدیم که می تواند شامل زنجیره ای از هر آبجکت دلخواه باشد. کالکشن ها نیز نوع دیگری از دنباله ها هستند که البته اندکی پیچیده تر از استرینگ ها و لیست ها می باشند که در این آموزش قصد داریم تا با برخی کالکشن های معروف در زبان برنامه نویسی پایتون آشنا شویم
تاپل (Tuple)
تاپل کالکشنی است که برای ساخت دنباله های پیچیده ی شبیه به لیست ها استفاده می شود که پیش از این با نحوه ی ایجاد یک آبجکت از نوع تاپل آشنا شدیم.
دیکشنری (Dictionary)
اگر با فرهنگ لغات یا دیکشنری ها کار کرده باشید، حتماً می دانید که در آن ها به ازای هر لغت معنای خاصی آورده شده است که با مراجعه به آن لغت می توانید به آن معنا دست پیدا کنید. در زبان پایتون هم زمانی که یک آبجکت از نوع دیکشنری ایجاد می کنیم، می توانیم داده هایی را به شکل یک جفت <<کلید:مقدار>> (<<key:value>>) ذخیره کنیم. زمانی که به هر کلید یک مقدار را نسبت می دهیم، به راحتی می توانیم با جستجوی کلید مورد نظر به مقدار آن برسیم؛ مشابه همان عملیاتی که در زمان یافتن معنای
یک لغت در دیکشنری انجام می دهیم.
اِستک (Stack)
استک یا پشته ساختاری برای نگهداری موقتی داده ها است که داده ها درون آن به صورت LIFO یا Last In-First Out سازماندهی می شوند. برای درک بهتر این نوع سازماندهی دیتا، میله ای را تصور کنید که می توان دیسک هایی را روی آن قرار داد. اگر چند دیسک را روی میله قرار دهیم و بعد بخواهیم دیسک ها را از روی میله یک به یک خارج کنیم، ابتدا باید آخرین دیسک قرار داده شده روی میله را برداریم و بعد به همین ترتیب پیش برویم تا به اولین دیسک برسیم. در ساختار استک نیز آخرین داده ای که درون آن قرار می گیرد اولین داده ای خواهد بود که از آن خارج می شود.
دیکشنری
در آموزش قبل آشنایی مختصری با نوع داده ی دیکشنری پیدا کردیم و دانستیم که آبجکت هایی از این نوع، درست همانند دیکشنری های واقعی کار می کنند؛ یعنی مانند لغات و معنای آن ها در دیکشنری،
این آبجکت ها نیز حاوی جفت های مختلفی از کلید:مقدار هستند. در حقیقت دلیل اصلی استفاده از دیکشنری، پیدا کردن راحت تر یک مقدار با استفاده از کلید مرتبط با آن است. دیکشنری ها هم مانند لیست ها، آبجکت هایی تغییرپذیر هستند؛ بنابراین برنامه نویسان می توانند بر اساس نیاز خود، محتوای آن ها را تغییر دهند. فرآیند ایجاد یک آبجکت از نوع دیکشنری شبیه به ساخت یک لیست است با این تفاوت که هر آیتمی که درون آن قرار داده می شود باید به صورت یک جفت کلید و مقدار باشد.برای نمونه قطعه کد زیر را در نظر بگیرید:
menu = {"breakfast":"egg", "lunch":"rice", "dinner":"salad"}
در این جا یک آبجکت از نوع دیکشنری ساخته ایم که ۳ آیتم در آن قرار گرفته است. دقت کنید کهکلیدها و مقادیر چگونه با هم جفت شده اند. ابتدا کلید می آید و پس از آن علامت دو نقطه (:) و سپس مقدار منتسب شده به کلید قرار داده می شود. در این جا کلیدها استرینگ هایی با مقادیر breakfast، lunch، و dinner هستند.
برای انتخاب کلیدها باید دو نکته ی کلی را مدنظر قرار داد:
۱- کلیدها باید یکتا باشند. برای نمونه در مثال بالا نباید دو کلید با شناسه ی یکسان breakfast قرار دهیم، چرا که در این صورت مفسر پایتون آخرین مقداری را که به کلید مورد نظر منتسب شده است را در نظر می گیرد و سایر مقادیر را نادیده می گیرد. بنابراین بهتر است از همان ابتدا به هر کلید تنها یک مقدار را منتسب کنیم.
۲- کلیدها باید از نوع آبجکت های تغییرناپذیر باشند. برای نمونه، در مثال بالا برای انتخاب کلیدها از نوع داده ی استرینگ استفاده کردیم که پیش از این گفتیم از آبجکت ها یا اشیاء تغییرناپذیر در زبان پایتون هستند. با فراخوانی نام دیکشنری، می توانیم به محتوای آن دست پیدا کنیم:
>>> menu>>> menu {'dinner': 'salad', 'breakfast': 'egg', 'lunch': 'rice'} {'dinner': 'salad', 'breakfast': 'egg', 'lunch': 'rice'}
حال اگر بخواهیم با استفاده از یک کلید به مقدار آن در این دیکشنری دسترسی پیدا کنیم به شکل زیر عمل می کنیم:
>>> menu['lunch'] 'rice'
همان طور که می بینید ابتدا شناسه ی منتسب شده به آبجکت دیکشنری که در این جا menu است می آوریم و سپس کلید مورد نظر را در میان علامت های [ ] قرار می دهیم. اگر بخواهیم به لیستی از کلیدهای مربوط به یک آبجکت دیکشنری دسترسی پیدا کنیم، از فانکشنی تحت عنوان ()keys استفاده می کنیم. برای مثال در این جا داریم:
>>> menu.keys() dict_keys(['dinner', 'breakfast', 'lunch'])
از طریق حلقه یی از جنس for نیز می توان به مقادیر مربوط به هر یک از کلیدهای بالا دسترسی پیدا کرد:
>>> for item in menu.keys(): print ("We have " + menu[item] + " for " + item + ".")
خروجی حاصل از دستور مرکب بالا به شکل زیر است:
We have salad for dinner. We have egg for breakfast. We have rice for lunch
گفتیم که نوع داده ی دیکشنری تغییرپذیر است. برای تغییر در محتوای یک آبجکت دیکشنری، می توان به شکل زیر عمل کرد:
>>> menu["lunch"] = "meat" >>> menu {'dinner': 'salad', 'breakfast': 'egg', 'lunch': 'meat'}
در این جا با استفاده از کلید مورد نظر آیتم مورد نظر را از دیکشنری انتخاب کرده ایم و مقدار جدیدی را به آن منتسب کرده ایم. هم چنین برای ایجاد تغییر در محتوای یک آبجکت دیکشنری می توان از فانکشن ()update به صورت زیر استفاده کرد:
>>> menu.update({"breakfast":"milk" , "snack":"nut"}) >>> menu {'dinner': 'salad', 'breakfast>>> menu.update({"breakfast":"milk" , "snack":"nut"}) >>> menu {'dinner': 'salad', 'breakfast': 'milk', 'snack': 'nut', 'lunch': 'meat'}': 'milk', 'snack': 'nut', 'lunch': 'meat'}
فانکشن ()update که روی یک آبجکت از نوع دیکشنری -در این جا menu- فراخوانی می شود، یک شیء دیکشنری با حداقل یک جفت کلید و مقدار را به عنوان آرگومان ورودی می گیرد و در صورتی که کلیدهای موجود در آرگومان فانکشن در دیکشنری menu باشند، مقدار آن ها را جایگزین مقدار جدید می کند و در غیر اینصورت آیتم جدید را با استفاده از جفت کلید و مقدار جدید به دیکشنری menu اضافه می کند.
برای مثال در این جا کلید breakfast از قبل در دیکشنری menu وجود داشت، بنابراین فقط مقدار آن آپدیت شده است، اما قبلاً آیتمی با کلید snack در این دیکشنری وجود نداشته و فانکشن update این جفت کلید و مقدار جدید را به آن اضافه می کند.
کلاس ها
در آموزش های قبل تا حدودی با مفهوم آبجکت و کلاس آشنا شدیم و با تعدادی از کلاس های تعریف شده در زبان پایتون کار کردیم. در حقیقت کلاس ها مانند ظرفی هستند که مجموعه ای از داده ها و کدهای
مرتبط را در کنار هم در یک جا نگهداری می کنند و آن گاه به سایر قسمت های برنامه امکان نمونه سازی از روی آن ها را می دهند.
زمانی که شما از کلاس های از پیش نوشته شده استفاده می کنید، آن ها مانند یک جعبه سیاه عمل می کنند؛ شما لازم نیست بدانید یک کلاس چگونه نوشته شده است، بلکه کافی است امکان ایجاد نمونه ای از آن کلاس را داشته باشید، داده های خود را وارد کنید و خروجی مد نظر خود را از کلاس دریافت کنید.
برای مثال زمانی که در برنامه ی خود از تابع ()append در کلاس list استفاده می کنیم لازم نیست بدانیم این فانکشن چطور طراحی و پیاده سازی شده است، بلکه تنها آرگومان های مورد نیاز را وارد این فانکشن
می کنیم و آن را روی یک آبجکت از کلاس list اثر می دهیم. در این شرایط کلاس لیست در پشت پرده کارهای لازم را انجام می دهد و نتیجه را برمی گرداند یا اصطلاحا return می کند.
در فرآیند کدنویسی یک اپلیکیشن گاه نیاز است که شما کلاس های اختصاصی خودتان را ایجاد کنید.
کلاس بندی کدها به برنامه نویس کمک می کند تا از پیچیدگی و درهم تنیدگی کدها اجتناب کند و کدهای مرتبط را در قالب کلاس های مختلف نگهداری کرده و در زمان نیاز، از آن کلاس های نمونه سازی کند و با
از طریق نمونه ی ساخته شده از کلاس از امکانات آن استفاده کند. در این فصل خواهیم دید که چطور می توان کلاس های دلخواه خود را در زبان برنامه نویسی پایتون ساخته سپس آبحکت های مختلفی از روی آن ها ایجاد کنیم.
پیش از هر چیز باید کمی در مورد مفهوم Object (آبجکت یا شیء) بدانیم. جدای از فضای برنامه نویسی اگر از شما سؤال شود که در دنیای واقعی یک شیء چیست، خواهید گفت “هر چیزی که ماهیت فیزیکی داشته باشد یک شیء است.” شما می توانید کارهایی را روی اشیاء انجام دهید، می دانید هر شیء چه شکل و رنگ و اندازه ای دارد، چه کارهایی می توان با آن انجام داد و غیره. در حقیقت ما می توانیم اشیاء
را از روی صفات یا خصوصیت آن ها شناسایی کنیم. بنابراین برای اشیاء واقعی
– کارهایی وجود دارد که می توانیم روی آن ها یا با آن ها انجام دهیم،
– چیزهایی که می توانیم آن اشیاء را با آن ها توصیف کنیم.
در مورد آبجکت ها یا بهتر بگوییم اشیاء مورد استفاده در زبان های برنامه نویسی نیز شرایط یکسانی صدق می کند. در زبان پایتون خصوصیاتی که اشیاء با آن ها توصیف می شوند Attribute (اَتریبیوت یا خصوصیت) نامیده می شوند و کارهایی که روی اشیاء انجام می شود Method (متد) نامیده می شوند.
برای نمونه، اگر بخواهیم اپلیکیشنی را در زبان پایتون پیاده سازی کنیم که لازم است شیئی مانند توپ را در آن شبیه سازی کنیم، این شیء صفاتی مانند اندازه، جنس، رنگ و وزن خواهد داشت و متدهایی مانند شوت کردن، باد کردن، پرتاب کردن و … را می توان روی آن اجرا کرد. فرض کنیم برای نشان دادن آبجکت یا شیء مورد نظر، خود از شناسه ی ball استفاده کنیم (قبلاً گفتیم که هر شیء نیاز به یک شناسه دارد که با آن معرفی می شود.) در این صورت، ویژگی های توپ مد نظر به صورت زیر خواهد بود:
ball.color ball.size ball.weight
و هم چنین متدهای زیر را می توانیم برای توپ در نظر بگیریم:
Ball.kick() Ball.throw() Ball.inflate()
همان طور که گفتیم هدف ما این است که اشیائی از انواع مختلف را در برنامه ی خود بسازیم و از آن ها استفاده کنیم. ساخت یک شیء در زبان پایتون دو مرحله دارد. در مرحله ی اول لازم است که مشخص کنیم یک شیء خاص چه خصوصیاتی دارد و چه کارهایی می تواند انجام دهد؛ در حقیقت ابتدا باید اتریبیوت ها و متدهای آن را تعریف کنیم.
اما تعریف این موارد، منجر به ایجاد یک شیء نخواهد شد. این کار مثل آن است که نقشه ی یک خانه را بکشیم که نشان می دهد خانه ی ما به چه شکل است اما این نقشه «تکه کاغذی بیش نخواهد بود»و حقیقتاً یک خانه قابل سکونت نیست، بلکه می توان برای ساخت یک نمونه خانه ی واقعی از آن استفاده کرد.
در واقع از این نقشه نه تنها برای ساخت یک خانه، بلکه برای ساخت هر تعداد خانه ی دلخواه می توان استفاده کرد. کلاس های پایتون نیز دقیقاً مانند یک نقشه هستند که می توان ابتدا کلاس ها را ایجاد کنیم
و آن گاه از روی آن ها به تعداد مورد نیاز آبجکت ایجاد کنیم. اجازه دهید در یک مثال نحوه ی تعریف یک کلاس در زبان پایتون را بررسی کنیم. قطعه کد زیر وظیفه ی ایجاد کلاسی با نام MyClass را بر عهده دارد:
class MyClass: MyVar = 0
برای تعریف یک کلاس لازم نیست پیچیدگی خاصی وجود داشته باشد. اولین خط از کلاس ساده ی بالا با کلمه ی کلیدی class آغاز می شود که به مفسر پایتون اعلام می کند در حال تعریف یک کلاس هستیم.
پس از کیورد class، نام دلخواهی آمده است که با شناسه ی MyClass مشخص شده است. این کدها را در فایلی تحت عنوان MyClass.py ذخیره می سازیم. تعریف هر کلاس دیگری نیز در زبان پایتون به همین
شکل خواهد بود. پس از نام کلاس از علامت : استفاده می کنیم و آن گاه از خط بعد محتویات کلاس را با رعایت تورفتگی نسبت به خط شروع تعریف کلاس می نویسیم. در این جا کلاس تعریف شده تنها شامل یک متغیر به نام MyVar است که مقدار ۰ را به آن اختصاص داده ایم. حال هر نمونه ی ساخته شده از این کلاس شامل این متغیر با مقدار اولیه ی ۰ خواهد بود.
اکنون که کلاس دلخواه خود را تعریف کردیم، می خواهیم وارد مرحله ی دوم نمونه سازی شویم. فرض کنید می خواهیم شیء نمونه ای از کلاس MyClass با نام myInstance ایجاد کنیم. برای این کار کافی است قطعه کد زیر را وارد کنیم:
myInstance = MyClass()
با این کار نمونه ای از کلاس MyClass را ایجاد کردیم و به شیء myInstance ارجاع دادیم. دقت داشته باشید که این کد نباید در داخل بدنه ی تعریف کلاس صورت گیرد. حال قطعه کد زیر را امتحان می کنیم:
print(myInstance.MyVar) به عنوان خروجی سورس کد فوق داریم:
اگر متغیر MyVar را به عنوان یک اتریبیوت کلاس MyClass در نظر بگیریم، شیء myInstance نیز این اتریبیوت را دارد و همان طور که می بینید برای دسترسی به آن کافی است نام شیء را بیاوریم و در ادامه ی آن یک دات (.) و سپس نام اتریبیوت را وارد کنیم.
در این مثال، از آنجا که در کلاس مورد نظر به اتریبیوت MyVar مقدار ۰ را داده بودیم بنابراین برای شیء myInstance که نمونه ای از آن کلاس است هم مقدار اولیه ی این اتریبیوت همان ۰ است. با این وجود ما می توانیم این مقدار اولیه را برای این شیء تغییر دهیم. برای این کار کافی است به شکل زیر عمل کنیم:
myInstance.MyVar = 100 print(myInstance.MyVar)
نتیجه به صورت زیر خواهد بود:
۱۰۰ <<<
در واقع ما با این کار، مقدار اولیه ی اتریبویت MyVar را اصطلاحا Override (اورراید یا بازنویسی) کرده ایم.
ابجکت ها
در آموزش قبل با مفهوم کلاس در زبان Python آشنا شدیم و دانستیم که تعریف یک کلاس مانند یک
الگوی مشترک است که می توان از روی آن ها آبجکت های مختلف را نمونه سازی کرد. بر اساس دانسته
های خود، کلاسی ساده تحت عنوان ShapeClass.py به شکل زیر پیاده سازی می کنیم:
class Shape: size
همان طور که در کد فوق ملاحظه می شود، ابتدا کلیدواژه ی class را نوشته و نامی دلخواه همچون
Shape به معنی «شکل» برای کلاس خود در نظر می گیریم و یک علامت : هم پس از آن قرار می دهیم.
یک متغیر هم تحت عنوان size به معنی «اندازه» با در نظر گرفتن تورفتگی ایجاد کرده ایم که دارای
هیچ نوع مقدار اولیه یی نیست. حال می توانیم از روی کلاس Shape به صورت زیر نمونه سازی کنیم:
my_rect = Shape() my_circle = Shape()
در حقیقت زمانی که ما دستور ()Shape را فراخوانی می کنیم، متد () __new__ برای ساخت آبجکت
جدید و ()__init__ برای مقداردهی اولیه به آن فراخوانی می شوند؛ بنابراین اگر بخواهیم در زمان
تعریف یک شیئ مقادیر اولیه ای را به اتریبیوت های آن آبجکت منتسب کنیم، باید از متد ()__init__
استفاده کنیم. برای مثال کلاس Shape را به صورت زیر بازنویسی می کنیم:
class Shape: size = 2 def __init__(self, name, color): self.name = name self.color = color
اولین آرگومانی که به این متد و دیگر متدهای کلاس داده می شود self است که نماینده ی نمونه ی
ایجاد شده از روی کلاس است، و پس از آن آرگومان هایی به متد ()__init__ داده می شود که می خواهیم
در زمان ایجاد هر آبجکت جدید از این کلاس آن ها را مقداردهی کنیم. برای مثال، در کد نمونه
آرگومان های name و color به این متد داده شده است و در بدنه ی متد ()__init__ دستور self.name = name مشخص می کند که اتریبیوت name برای آبجکت نمونه سازی شده از این کلاس باید به مقدار آرگومان name منتسب شود و دستور self.color = color نیز اتریبیوت color را برای آبجکت نمونه سازی شده به مقدار آرگومان color منتسب می کند. حال اگر بخواهیم آبجکت های جدیدی را از این کلاس
ایجاد کنیم به صورت زیر عمل می کنیم:
shape1 = Shape('Circle','Yellow') shape2 = Shape('Square','Green')
دو آبجکت shape1 و shape2 با دستورات بالا ایجاد و اتریبیوت های name و color برای آن ها
مقدار دهی می شوند. حال می توانیم مانند آن چه در آموزش قبل توضیح داده شد، با استفاده از
عملگر . به مقدار اتریبیوت های این دو شیء دسترسی پیدا کنیم:
>>> print(shape1.name) Circle >>> print(shape2.color) Green
همان طور که می بینید، این مقادیر برابر با مقادیر آرگومان هایی هستند که در زمان تعریف آبجکت ها از
آن ها استفاده کردیم. شما می توانید در هر زمان که خواستید اتریبیوت جدیدی را به یک آبجکت اضافه کنید، یا اتربیوت های قبلی آن را تغییر دهید، یا حذف کنید (به عبارت دیگر صفتی را که به آبجکت
نسبت داده بودید از آن بگیرید.) برای مثال، کدهای زیر را در نظر بگیرید:
shape1.color = 'blue' shape1.radius = 20 del shape1.name)
در دستور اول مقدار جدیدی را به اتریبیوت color متعلق به آبجکت shape1 منتسب می کنیم. در دستور دوم اتریبیوت جدیدی را با شناسه ی radius و مقدار ۲۰ به آبجکت shape1 منتسب می کنیم و در نهایت
در دستور سوم با استفاده از کیورد del و سپس فراخوانی اتربیوت name متعلق به آبجکت shape1
این اتریبیوت را از آبجکت مد نظر حذف می کنیم. حال خروجی کدهای زیر را می بینیم:
>>> print(shape1.color) blue >>> print(shape1.radius) ۲۰ >>> print(shape1.name) Traceback (most recent call last): File "C:/SokanAcademy/MyClass.py", line 19, in print(shape1.name) AttributeError: 'Shape' object has no attribute 'name'
همان طور که می بینید در دو دستور اول، آخرین مقادیر منتسب شده به اتریبیوت های آبجکت shape1
در خروجی چاپ شده اند اما خروجی دستور پرینت سوم خطایی است که اعلام می کند آبجکت
shape1 اتریبیوتی با شناسه ی name ندارد و این خطا به درستی نمایش داده شده است چرا که ما
پیش از این با دستور del این اتریبیوت را از آبجکت مورد نظر حذف کرده بودیم. علاوه بر روش اشاره
شده، می توانیم از فانکشن های زیر نیز برای مدیریت اتریبیوت های یک آبجکت استفاده کنیم:
کاربرد | فانکشن |
(برای دسترسی به اتریبیوت های یک آبجکت | getattr(obj, name[default]) |
برای بررسی این که یک آبجکت اتریبیوت خاصی را دارد یا خیر | (hasattr(obj, name |
برای مقداردهی به یک اتریبیوت متعلق به آبجکتی خاص. اگر این اتریبیوت موجود باشد مقدار جدیدی می گیرد و در غیر اینصورت جدیدی با مقدار داده شده به آبجکت منتسب می شود. | setattr(obj, name,(value |
برای حذف یک اتریبیوت از یک آبجکت | (delattr(obj, name |
کاربرد این فانکشن ها را بر روی آبجکت های بالا ببنید:
>>>print(hasattr(shape2, 'radius')) # Returns true if 'radius' attribute exists False >>>print(getattr(shape1, 'radius')) # Returns value of 'radius' attribute ۲۰ >>>setattr(shape2, 'radius', 8) # Set attribute 'radius' at 8 >>>delattr(shape1, 'color') # Delete attribute 'color'
خروجی دستور اول False است، چون هرگز اتریبیوت radius را به آبجکت shape2 منتسب نکردیم.
خروجی دستور دوم نیز مقدار منتسب شده به اتریبیوت radius متعلق به آبجکت shape1 است.
دستور سوم اتریبیوت radius را با مقدار ۸ به آبجکت shape2 منتسب می کند و دستور آخر هم
اتریبیوت color را از آبجکت shape1 حذف می کند.
اتریبیوت
پس از تعریف یک کلاس در برنامه ی پایتون، اتریبیوت های از پیش ساخته ای به آن کلاس افزوده می شود. این اتریبیوت ها کارکردهای متنوعی دارند که با برخی از آن ها آشنا خواهیم شد.
برای این منظور برنامه ی زیر را بررسی خواهیم کرد:
class Student: 'Common base class for all students' count = 0 def __init__(self, name, family): self.name = name self.family = family Student.count += 1; def displayCount(self): print("Total Student : ", Student.count) def displayStudent(self): print("Name : ", self.name, ", family: ", self.salary) print("Student.__doc__:", Student.__doc__) print("Student.__name__:", Student.__name__) print("Student.__module__:", Student.__module__) print("Student.__bases__:", Student.__bases__) print("Student.__dict__:", Student.__dict__)
در این برنامه ابتدا کلاس Student تعریف و سپس از فانکشن پرینت برای چاپ مقدار اتریبیوت های
از پیش تعریف شده برای این کلاس استفاده شده است. اولین اتریبیوت __doc__ است که داکیومنت
مربوط به کلاس را نشان می دهد که در مورد کلاس Student همان کامنتی است که در خط اول
بدنه ی تعریف کلاس آمده است:
print("Student.__doc__:", Student.__doc__) >>> Student.__doc__: Common base class for all students
همان طور که می بینید برای استفاده از اتریبیوت های از پیش ساخته در کلاس ها باید نام کلاس را
به همراه یک دات (.) و در ادامه ی آن نام اتریبیوت را بیاوریم. اتریبوت بعدی __name__ است که
دربرگیرنده ی نام کلاس است:
print("Student.__name__:", Student.__name__) >>> Student.__name__: Student
اتریبیوت __module__ نام ماژولی که کلاس در آن تعریف شده است را نشان می دهد:
print("Student.__module__:", Student.__module__) >>>Student.__module__: __main__
اتریبیوت __bases__ یک شیء تاپل است که کلاس های پایه ای که کلاس جدید از آن ها ارث بری کرده
است را نشان می دهد که آن ها را با علامت , از هم جدا می کند. در این جا تنها یک کلاس object به
عنوان کلاس پایه استفاده شده است و خروجی این دستور به صورت زیر است:
print("Student.__bases__:", Student.__bases__) >>>Student.__bases__: (<class 'object'>,)
اتریبیوت دیگر __dict__ ، یک شیء دیکشنری است که تمام اتریبیوت های کلاس در آن ذخیره شده
است. برای مثال این شیء در کلاس Student به صورت زیر است:
print("Student.__dict__:", Student.__dict__) >>>Student.__dict__: {'__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Student' objects>
ماژول ها
به طور کلی، منظور ازماژول، بخشی از یک چیز است؛ به عبارت دیگر، وقتی می گوییم چیزی ماژولار است یعنی از بخش های مختلف تشکیل شده است یا می توان آن را به بخش های مختلف تقسیم بندی کرد.
سازه های ساخته شده با Lego مثال آشکاری از یک چیز ماژولارند به طوری که شما می توانید قطعات مختلف لگو را انتخاب کنید و با آن ها چیزهای متفاوتی بسازید:
به خاطر داشته باشید:
در پایتون ماژول ها بخش های کوچکی از یک برنامه ی بزرگ تری هستند به طوری که هر Module (ماژول یا بخش) یک فایل جداگانه روی هارد کامپیوتر شما است. شما می توانید یک برنامه ی بزرگ را انتخاب کنید و آن را به چندین ماژول یا فایل جداگانه تقسیم کنید، یا به شکلی دیگر یک ماژول کوچک را انتخاب کنید و با افزودن کدهای دیگر، آن را تبدیل به یک برنامه ی بزرگ کنید. ممکن است این سوال پیش بیاید که چرا لازم است برنامه ها ماژولار نوشته شوند و چرا تمام کدهای برنامه را در یک فایل نمی نویسیم؟ دلایل مختلفی برای این کار وجود دارند که مهم ترین آن ها عبارتند از:
– ماژول بندی کدها باعث می شود فایل ها کوچک تر شوند و پیدا کردن یک قطعه کد در آن ها راحت تر باشد؛ برای مثال تعریف یک فانکشن در یک فایل کوچک کاری به مراتب آسان تر است تا جستجوی آن
در یک فایل حاوی هزاران خط کد!
– زمانی که یک ماژول را ایجاد می کنید می توانید در برنامه های مختلف از آن ها استفاده کنید. برای مثال زمانی که به یک فانکشن پرکاربرد احتیاج دارید، با قرار دادن آن در یک ماژول جداگانه، می توانید در اپلیکیشن های مختلف از آن استفاده کنید بدون آن که نیاز به بازنویسی آن داشته باشید.
– شما همیشه نیاز ندارید که تمام ماژول ها را با هم در یک اپلیکیشن استفاده کنید. ماژولار بودن یک اپلیکیشن به این معنا است که می توانید برای انجام کارهای مختلف از ترکیب های متفاوتی از ماژول ها استفاده کنید، درست مانند زمانی که با یک مجموعه از لگوها، بچه ها سازه های مختلفی ایجاد می کنند.
بنابراین با وجود این دلایل، ماژولار کردن برنامه ها منطقی به نظر می رسد و می توان فانکشن های شبیه به هم را در یک ماژول در کنار هم آورد یا تمام فانکشن های مورد نیاز در یک برنامه را درون یک ماژول جا داد. اکنون باید ببینیم که چطور می توان یک ماژول ساخت. یک ماژول در زبان پایتون تنها یک فایل است. برای شروع کار، کدهای زیر را درون فایلی با نام MyModule.py ذخیره می کنیم:
# this is the file "MyModule.py" # we're going to use it in another program def celsiusToFahrenheit(celsius): fahrenheit = ((celsius * 9.0) / 5 ) + 32 return Fahrenheit
با ذخیره ی این کد یک ماژول ساخته می شود که درون آن تنها یک فانکشن ()celsiusToFahrenheit قرار دارد که وظیفه ی آن تبدیل دما از درجه ی سانتی گراد به فارنهایت است.
اکنون می خواهیم فانکشن تعریف شده در ماژول فوق را یک برنامه ی دیگر فراخوانی کنیم. پیش از این، یاد گرفتیم که چگونه با پاس دادن پارامترها یا آرگومان های مورد نیاز یک فانکشن می توانیم آن را فراخوانی کنیم تا خروجی های مورد انتظار را برگرداند؛ تنها تفاوت در این جا این است که برنامه ی جدیدی که قرار است در آن فانکشن ()celsiusToFahrenheit را فراخوانی کنیم در فایل یا ماژولی جداگانه قرار دارد، بنابراین برای این کار لازم است به مفسر پایتون اعلام کنیم که می خواهیم از کدام ماژول استفاده کنیم.
در چنین مواردی در پایتون از کیورد import (ایمپورت به معنی وارد کردن) استفاده می کنیم که امکان استفاده از سایر ماژول ها و امکانات آن ها را در یک برنامه ی دیگر برای ما فراهم می کند. برای این کار کیورد import و در ادامه ی آن نام ماژول را می آوریم، برای مثال می نویسیم import MyModule. اکنون یک پنجره ی جدید در ویرایشگر آیدل باز می کنیم و کدهای برنامه ی اصلی را در آن وارد می کنیم:
import MyModule celsius = float(input ("Enter a temperature in Celsius: ")) fahrenheit = MyModule.celsiusToFahrenheit(celsius) print("That's ", fahrenheit, " degrees Fahrenheit")
در خط اول این برنامه با آوردن کیورد import ماژول MyModule که در فایلی با نام MyModule.py ذخیره شده بود را برای استفاده وارد برنامه ی کرده ایم. اکنون می توانیم با استفاده از نام این ماژول در هر جای برنامه فانکشن درون آن را فراخوانی کنیم. سپس از کاربر می خواهیم عددی را به عنوان آرگومان فانکشن وارد کند و آن را در متغیر celsius ذخیره می کنیم. آن گاه فانکشن celsiusToFahrenheit را فراخوانی کرده و این متغیر را به آن پاس می دهیم.
خروجی فانکشن مورد نظر در متغیر Fahrenheit ذخیره شده است تا برای چاپ در خط بعد از آن استفاده شود. برنامه ی فوق را در فایلی با نام Modular.py ذخیره می کنیم. دقت داشته باشید برای درست کارکردن
برنامه در زمان اجرا باید آن را در همان دایرکتوری که فایل ایمپورت شده را ذخیره کرده بودیم قرار دهیم، چرا که در غیر این صورت، مفسر پایتون نمی تواند فایل ایمپورت شده را پیدا کند. یک نمونه خروجی
حاصل از اجرای برنامه به شکل زیر است:
Enter a temperature in Celsius: 65 That's 149.0 degrees Fahrenheit >>>
دقت داشته باشید که اگر دستور ایمپورت را از ابتدای این برنامه حذف کنیم با خطای زیر در هنگام اجرای آن روبه رو خواهیم شد:
Enter a temperature in Celsius: 54 Traceback (most recent call last): File "C:/Users/Admin/Desktop/Modular.py", line 3, in fahrenheit = MyModule.celsiusToFahrenheit(celsius) NameError: name 'MyModule' is not defined
همان طور که در خط آخر می بینیم، با ارور MyModule is not defined به معنی «MyModule تعریف نشده است» مواجه می شویم.
۴ Responses
لطفا آموزش زبان برنامه نویسی پایتون رو ادامه بدید خیلی عالی بود تشکر
سلام وقت بخیر
حتما در دستور کار قرار خواهیم داد.
ممنون بابت این مقاله جامع که آموزش مفاهیم بنیادی پایتون رو به زبان ساده توضیح دادین
ممنون از نگاه زیبای شما
پیشنهاد میکنم مقاله های هوش مصنوعی که به ادرس https://iracode.com/artificial-intelligence/ قابل مشاهده است رو هم ملاحظه نمایید.