کتاب آزاد آموزش پایتون

این کتاب تلاشی است برای آموزش زبان برنامه‌نویسی پایتون (Python) بر پایه‌ پیاده‌سازی استاندارد آن (CPython)، به شکلی کامل و ساده که بتواند هر دو شاخه از پایتون (نسخه‌های 3x و 2x) را البته با محوریت نسخه 3x پوشش دهد و همچنین برای افرادی که تاکنون سابقه‌ برنامه‌نویسی نداشته‌اند نیز کاربردی و مفید باشد. یادگیری پایتون نیازی به پیش‌زمینه برنامه‌نویسی ندارد و تنها پیش‌نیاز آن علاقه خوانندگان به فن برنامه‌نویسی است.

پیش‌گفتار

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


زیربنا:

درس ۰۱: آشنایی

این درس با بیان تاریخچه ایجاد پایتون شروع و با توصیفی کوتاه و شرح ویژگی‌های آن ادامه می‌یابد؛ در شرح ویژگی‌ها سعی شده است کمی نیز توضیحات غیرپایتونی برای درک بهتر موضوعات ارایه گردد. همچنین در مورد کارایی پایتون و این موضوع که چرا در حال حاضر دو شاخه متفاوت از این زبان وجود دارد نیز صحبت شده است. هدف این درس ایجاد یک پیش‌زمینه‌ بدون ابهام از پایتون است! به این امید که مفید باشد و بتواند شما را به یادگیری این زبان تشویق کند 😉.

سطح: پایه



تاریخچه

داستان [1] پایتون از اواخر سال ۱۹۸۲ میلادی آغاز می‌شود، سالی که آقای روسوم پس از پایان دانشگاه به عنوان یک برنامه‌نویس وارد تیم توسعه‌ زبان ABC در مرکز CWI واقع در آمستردام هلند می‌شود. ABC یک زبان برنامه‌نویسی تفسیر‌شده (Interpreted) با اهداف آموزشی است که از اواخر دهه هفتاد میلادی، تحت پروژه‌ای در این مرکز آغاز شده بود. وی چهار یا پنج سال بعد، زمانی که از پروژه‌ زبان ABC نتیجه‌ مطلوب حاصل نمی‌گردد از آن خارج و به تیم توسعه‌ سیستم عامل آمیب می‌پیوندد. این موضوع از آن جهت دارای اهمیت است که در هنگام کار بر روی این سیستم عامل بود که آقای روسوم به فکر ایجاد یک زبان اسکریپتی (Scripting Language) جدید می‌افتد.

در دسامبر سال ۱۹۸۹ میلادی، تعطیلات کریسمس فرصتی می‌شود تا آقای روسوم به ایده سرگرم کننده‌ [2] خود بپردازد. البته پس از آن نیز زمان زیادی از وقت‌های آزاد خود را برای پیشرفت پروژه‌ای که ”Python“ نامیده بود صرف می‌کند. در این مسیر، تجربه‌ کار بر روی زبان ABC و همینطور مطالعات وی بر روی زبان‌ Modula-3 نقش فراوانی داشته است، در‌ واقع او یک نسخه‌ شخصی از بخش‌های مورد علاقه‌ خود از ABC ایجاد نمود. او یک ماشین مجازی ساده، یک تجزیه‌کننده (پارسرParser) ساده و یک سیستم زمان‌اجرا (Runtime System) ساده ایجاد کرد؛ یک زبان با نحو (سینتکس Syntax) اولیه که از تو‌رفتگی (Indentation) برای بلاک‌بندی بهره می‌برد و از انواع داده [3] دیکشنری، لیست، رشته و اعداد پشتیبانی می‌کرد و بر خلاف ABC توسعه‌پذیر می‌بود.

یک سال بعد آقای روسوم از پایتون در پروژه‌ آمیب استفاده می‌کند؛ نتیجه‌ مطلوب و نیز بازخورد آن در بین همکارانش موجب می‌شود تا وی به بسیاری از بهینه سازی‌های اولیه در پایتون اقدام نماید. این روند ادامه می‌یابد تا اینکه سرانجام در ماه دوم از سال ۱۹۹۱ میلادی این زبان را با نسخه 0.9.0 و تحت پروانه‌ای مشابه با پروانه‌ MIT از طریق یکی از «گروه‌های خبری» (یوزنت Usenet) با عنوان alt.sources منتشر می‌سازد که با استقبال بالایی نیز رو به رو می‌گردد.

منشا انتخاب نام پایتون توسط آقای روسوم برخلاف تصور عمومی یا آنچه که از لوگوی آن مشاهده می‌شود به نوع خاصی از مار مربوط نمی‌شود!؛ در حقیقت این نام برگرفته از یک سریال کمدی تولید انگلستان با عنوان ”Monty Python’s Flying Circus“ می‌باشد که پخش اصلی آن در طی سال‌های ۱۹۶۹ تا ۱۹۷۴ میلادی از شبکه‌ BBC One بوده است.

توصیفی کوتاه

سادگی و خوانایی از ویژگی‌های بارز زبان برنامه‌نویسی پایتون است، آنچنان ساده که حتی کودکان نیز قادر به آموختن آن هستند و قدرت در کنار این سادگی و خوانایی، معجزه‌ پایتون می‌باشد. از نگاه هر برنامه‌نویسی، برنامه‌های پایتون مجموعه‌ای از کد‌های زیبا هستند، بدون هیچ آشفتگی و پیچیدگی. این زبان به جای این که برنامه‌نویس را درگیر فهم ساختارش کند، به ابزاری قدرتمند برای تحقق تمام آنچه که در فکر برنامه‌نویس است تبدیل می‌شود، اگر در اجرای نخست کدهای پایتون خود هیچ خطایی نگرفتید؛ تعجب نکنید! و اگر هم گرفتید، خوشحال باشید!. این زبان به شدت دوست داشتنی است 😍. ilovepython#

زبان برنامه‌نویسی پایتون همانطور که اشاره شد در سال ۱۹۹۱ میلادی توسط آقای روسوم خلق شده و توسعه‌ آن نیز زیر نظر مستقیم اوست. آقای روسوم زاده‌ سال ۱۹۵۶ میلادی و نخستین دارنده‌ عنوان BDFL (دیکتاتور خیرخواه جاویدان)‌ می‌باشد و هم اکنون (سال ۲۰۱۵) در شرکت Dropbox مشغول به کار است. (صفحه شخصی)

توسعه‌ پایتون با عصر توسعه و محبوبیت زبان‌های متن باز دیگری همچون Tcl ،Perl و Ruby هم‌ زمان بوده که این امر به پیشرفت و توسعه‌ آن کمک زیادی کرده است.

پایتون یک جامعه‌ کاربری بسیار بزرگ و پویا به همراه خود دارد که عامل پیشرفت و توسعه‌ بسیار مهمی برای هر زبان برنامه‌نویسی به شمار می‌رود. این جامعه هر ساله با برپایی همایش‌های گوناگون در سراسر جهان به تبادل آموخته‌ها می‌پردازد. یکی از رایج‌ترین این همایش‌ها PyCon (پای‌کان) می‌باشد که خوشبختانه ‌در ایران (PyCon Iran یا PyIran) نیز برگزار می‌شود.

این زبان تاکنون توسط شرکت یا سازمان‌های مطرح زیادی مورد استفاده قرار گرفته و در برنامه‌های کاربردی زیادی نیز از آن استفاده شده است که از جمله این موارد می‌توان به: reddit ،Pinterest ،Instagram (شبکه‌های اجتماعی) / Google (موتور جستجوگر و نیز سرویس یوتیوب) / Yahoo (سرویس نقشه) / IBM ،Intel ،Cisco ،Seagate (تست سخت‌افزار) / Dropbox (سرویس میزبانی ابری فایل) / EVE Online (بازی‌های آنلاین) / NASA ،Los Alamos (امور علمی) / iRobot (رباتیک) / Pixar ،Industrial Light and Magic ،Walt Disney (ساخت فیلم‌های انیمیشن) / BitTorrent (اشتراک فایل نظیر به نظیر) / CIA (وب‌سایت) / PayPal (سیستم انتقال پول آنلاین) / Mercurial (سیستم کنترل نسخه) / ESRI (نقشه‌برداری در برنامه GIS) و بسیاری دیگر [4] اشاره نمود. (پایتون در stackshare)

یک نکته مهم در مورد زبان برنامه‌نویسی پایتون، انواع پیاده‌سازی‌ (Implementation)‌ آن است. تا‌کنون از این زبان پیاده‌سازی‌های گوناگون و با اهداف متفاوتی توسعه یافته است که از این بین می‌توان به Jython (خاص ماشین مجازی جاوا)، IronPython (خاص چارچوب NET. مایکروسافت)، PyPy (با هدف سرعت اجرای بیشتر)، Stackless (با هدف اجرای بهتر برنامه‌های چند‌نخی) و البته CPython اشاره نمود. [5]

CPython (سی‌پایتون) پیاده‌سازی استاندارد و اصلی زبان پایتون می‌باشد که با استفاده از زبان برنامه‌نویسی C توسعه می‌یابد. توسط CPython می‌توانید علاوه بر کتابخانه‌ پایتون از کتابخانه‌‌ زبان‌های C و ++C نیز بهره ببرید.

توجه داشته باشید، پایتون (Python) نام یک زبان برنامه‌نویسی است و CPython (یا دیگر پیاده‌سازی‌‌های زبان پایتون) در واقع برنامه‌ایست که توسط آن می‌توان کد منبع (سورس کد Source Code) یک برنامه به زبان پایتون را اجرا نمود. به بیانی دیگر CPython یک پردازنده‌ برای زبان پایتون است.

ویژگی‌ها

پایتون یک زبان برنامه‌نویسی رایگان، متن باز (Open Source) و با بیانی کامل‌تر، آزاد است که هم‌‌اکنون (یعنی از نسخه‌ 2.1 و جدیدتر) پروانه‌ آن توسط «بنیاد نرم‌افزار پایتون» PSF اداره می‌گردد. پروانه‌ پایتون سازگار با پروانه‌ GPL3 است، با این حال به برنامه‌نویس این اجازه را می‌دهد که بتواند برنامه‌ای با سورس بسته (Closed Source) تولید نماید.

زبان پایتون از اجزای بسته نرم‌افزاری LAMP نیز به شمار می‌رود. این بسته عبارت است از: Linux ~ سیستم عامل / Apache ~ وب سرور / MySQL یا MariaDB ~ پایگاه‌ داده / Python یا Perl یا PHP ~ زبان برنامه‌نویسی.

این زبان خیلی پیش‌تر از آنکه حتی Eric Raymond و Bruce Perens از Open Source صحبت کنند، متن باز بوده است.

پایتون یک زبان برنامه‌نویسی همه منظوره (General-Purpose) است به این معنی که می‌توان از آن در توسعه طیف گسترده‌ای از انواع برنامه‌ها در حوزه‌های نرم‌افزاری گوناگون بهره برد؛ از جمله در توسعه برنامه‌های تحت وب و برنامه‌هایی با قابلیت «واسط گرافیکی کاربر» (GUI).

پایتون یک زبان برنامه‌نویسی به همراه مجموعه‌ بزرگی از قابلیت‌های از پیش آماده و قابل حمل است که به عنوان کتابخانه‌ استاندارد آن شناخته می‌شود. همچنین در کنار این کتابخانه‌ می‌توان از طیف بسیار وسیعی از کتابخانه‌های شخص ثالث (Third-Party) پایتون [6] نیز بهره برد. کتابخانه‌های شخص ثالث ابزارهای مفیدی را در امور فروانی همچون: برنامه‌نویسی علمی ~ NumPy ،SciPy / پردازش زبان‌های طبیعی ~ NLTK / ارتباط درگاه سریال ~ PySerial / ایجاد بازی ~ PyGame ،Pyglet ،PyOpenGL ،PySoy / هوش مصنوعی ~ PyBrain / ایجاد وب سایت ~ Django ،Flask ،Bottle ،CherryPy / پردازش تصویر ~ PIL/Pillow ،PythonMagick / واسط گرافیکی کاربر ~ PyGtk ،PyQt ،WxPython / کار با اسناد rdflib ~ pdf / رمزنگاری ~ PyCrypto ،pyOpenSSL ،cryptography و بسیاری دیگر… که مدام در حال توسعه هستند و بر تعداد و تنوع آن‌ها نیز افزوده می‌شود را در اختیار برنامه‌نویسان پایتون قرار می‌دهند.

پایتون یک زبان برنامه‌نویسی پویا (Dynamic) بوده و نیز از قابلیت مدیریت خودکار حافظه برخوردار است. این زبان شباهت‌هایی با TCL ،Perl ،Ruby ،PHP یا دیگر زبان‌های برنامه‌نویسی پویا دارد. در این نوع زبان‌ها بر‌خلاف زبان‌های ایستا (Static) مانند C++ ،C و Java نیازی به تعریف صریح نوع متغیرها [7] (Variables) نیست و همچنین نوع متغیر در طول برنامه قابل تغییر است. در زبان‌های پویا متغیرها از خود نوعی ندارند و تصمیم گیری برای تخصیص نوع در «زمان اجرا» (RunTime) انجام می‌پذیرد.

بر خلاف زبان C، در پایتون اختصاص و آزاد‌سازی حافظه (Memory) به صورت خودکار انجام می‌شود. پایتون برای آزاد‌سازی حافظه از دو روش «شمارش ارجاع» (Reference Counting) و «زباله روبی» [8] (Garbage Collection) بهره می‌گیرد. (البته فراموش نشود که صحبت در مورد پیاده‌سازی CPython است)

با اینکه پایتون یک زبان پویاست ولی در عین حال یک زبان «وابسته شدید به نوع» (Strongly Typed) نیز می‌باشد. در این نوع زبان‌ها (به مانند Java) تغییر ناگهانی و خودکار نوع داده (یا شی) انجام نمی‌شود؛ به عنوان نمونه چنانچه در پایتون عمل جمع بین یک نوع داده عددی مانند 3 و یک نوع داده غیر عددی مانند "7" صورت گیرد، یک Exception یا استثنای TypeError گزارش می‌گردد. در مقابل، زبان‌های «وابسته ضعیف به نوع» (Weak Typed) قرار دارند؛ در این زبان‌ها (به مانند Perl) نوع بر حسب موقعیت به صورت خودکار تغییر داده می‌شوند. در این مورد زبان‌های برنامه‌نویسی رفتارهای متفاوتی دارند،‌ به عنوان نمونه حاصل عبارت "7" + 3 در زبان Perl با تبدیل (Convert)‌ خودکار نوع داده غیر عددی "7" به عدد (7)، مقدار 10 محاسبه می‌گردد.

Tip

استثنا‌ در واقع وضعیت یا خطایی (Error) است که در برنامه پیش‌بینی شده و بروز آن‌ به مانند یک اعتراض گزارش می‌شود. از طرفی در برنامه برای هر اعتراض، چگونگی رسیدگی به آن نیز تعریف می‌شود.

پایتون یک زبان برنامه‌نویسی سطح بالا (High-Level) به مانند C ،Ruby ،PHP و Java است که به وسیله‌ آن عمل برنامه‌نویسی به آسانی و با سرعتی بالا انجام می‌پذیرد و بر‌خلاف زبان برنامه‌نویسی سطح پایینی (Low-Level) مانند Assembly، برنامه‌نویس را درگیر مسایل خاص موجود در این سطح به مانند کار با ثبات‌ها (Registers)، آدرس‌های حافظه و غیره… نمی‌سازد.

Tip

بر اساس یک دسته‌بندی رایج [9]، زبان‌های برنامه‌نویسی را می‌توان به نسبت درگیر ساختن برنامه‌نویس با مفاهیم سخت‌افزاری یا میزان سطح انتزاع (Abstraction) برنامه‌نویس از سخت‌افزار، در دو سطح دسته‌بندی نمود: ۱. پایین ~ زبان ماشین و Assembly (اسمبلی) ۲. بالا ~ Java ،C++ ،C و غیره…

Note

میزان انتزاع تمام زبان‌های برنامه‌نویسی سطح بالا به یک نسبت نمی‌باشد؛ به عنوان نمونه میزان انتزاع زبان پایتون بیشتر از Java و سطح انتزاع Java نیز بسیار بیشتر از زبان C است:

Machine < Assembly < C < C++ < Java < Python

Tip

تنها زبان قابل فهم و اجرا برای هر ماشینی (یا رایانه‌ای)، زبان ماشین (Machine Language) خاص آن است و تمامی برنامه‌های نوشته شده در هر سطحی از انتزاع که باشند، پیش از اجرا می‌بایست به این زبان ترجمه شوند. بدیهی است که نیاز این پردازش اضافی به نسبت از سرعت اجرای برنامه می‌کاهد. عمل ترجمه برای کدهای اسمبلی توسط اسمبلر (Assembler) و برای باقی زبان‌ها توسط کامپایلر (Compiler) یا مفسر (Interpreter) انجام می‌پذیرد.

پایتون یک زبان برنامه‌نویسی چند‌ الگویی (Multi-Paradigm) است و برنامه‌نویس را مجبور به رعایت الگوی خاصی نمی‌کند. این زبان از الگوهای: دستوری (Imperative) یا رویه‌ای (Procedural)، تابعی (Functional) و شی‌گرایی (Object-Oriented) پشتیبانی می‌کند؛ البته همانظور که گفته شد نمی‌توان پایتون را به صورت خالص (Pure) متعلق به هر یک از این الگوها دانست [10].

جدا از پشتیبانی الگوی برنامه‌نویسی شی‌گرا، ساختار پایتون به صورت کامل شی‌گراست و هر چیزی در این زبان یک شی (Object) است؛ در آینده بیشتر در این مورد صحبت خواهیم کرد.

پایتون (پیاده‌سازی CPython) به عنوان یک زبان تفسیر‌شده (Interpreted) شناخته می‌شود. با یک تعریف کلی در این نوع زبان‌ها کار خواندن سورس کد برنامه، ترجمه به زبان ماشین و در نهایت اجرای آن توسط یک مفسر انجام می‌گیرد. در پایتون عمل ترجمه و اجرای سورس کد را می‌توان در دو مرحله متوالی خلاصه نمود:

۱- کامپایل سورس کد به بایت‌کد (ByteCode)

۲- تفسیر بایت‌کد به زبان ماشین و اجرای آن

به این صورت که ابتدا سورس کد برنامه‌ به یک زبان میانی نزدیک به زبان ماشین با نام بایت‌کد ترجمه می‌شود و سپس بایت‌کد حاصل به ماشین مجازی (Virtual Machine) - به عنوان موتور زمان‌اجرای پایتون - فرستاده و توسط آن تفسیر و اجرا می‌گردد.

Note

با این که پایتون (پیاده‌سازی CPython) به عنوان یک زبان تفسیر‌شده شناخته می‌شود ولی در زمان‌اجرا (RunTime) برای ترجمه‌ سورس کد به بایت‌کد از یک کامپایلر استفاده می‌کند.

تفاوت عملکرد کامپایلر و مفسر

به صورت خیلی کلی، کوتاه و ساده:

یک کامپایلر (در زبان‌های کامپایل‌شده) تمامی سطرهای سورس کد برنامه را به صورت یکجا خوانده و سپس با ساخت یک فایل جدید و مستقل از سورس کد با نام «کد مقصد یا آبجکت کد» (Object Code) یا فایل اجرایی (Executable) عمل ترجمه به زبان ماشین را پایان می‌بخشد. برنامه حاصل از کامپایلر توانایی هر چند بار اجرا در رایانه مقصد، بدون نیاز به کامپایل دوباره را دارد، اما فاقد حمل‌پذیری بوده و کاربر نهایی نیز به هیچ عنوان توانایی دسترسی به سورس کد برنامه و تغییر یا ویرایش آن را نخواهد داشت. اما یک مفسر (در زبان‌های تفسیر‌شده) سورس کد برنامه را به صورت سطر به سطر می‌خواند و هر سطر را به صورت جداگانه به زبان ماشین ترجمه و سپس بلافاصله آن را اجرا می‌کند. به این صورت که هنگامی یک سطر در حال اجراست در همان لحظه سطر بعدی در حال ترجمه به زبان ماشین می‌باشد. برنامه‌های نوشته شده با زبان‌های برنامه‌نویسی تفسیر‌شده برای هر بار اجرا در رایانه هدف نیاز به تفسیر دوباره دارند. این تفاوت عملکرد گرچه باعث کاهش سرعت اجرای برنامه‌های تفسیر‌شده نسبت به برنامه‌های کامپایل‌شده می‌شود ولی خواندن سطر به سطر کدها در مفسر علاوه بر قابلیت تشخیص خطای بهتر، این امکان را بوجود می‌آورد که هر کاربری بتواند حتی در زمان اجرای برنامه سورس کد را ویرایش و تغییر دهد؛ این دسته از زبان‌ها در مواقعی که پیوسته نیاز به افزودن ویژگی‌های متفاوت به برنامه است بسیار مورد توجه قرار گرفته‌اند.

Note

ماشین مجازی پایتون (CPython VM) به صورت یک حلقه تکرار است که دستورات بایت‌کد را یکی یکی می‌خواند، به زبان ماشین تفسیر و بلافاصله اجرا می‌کند.

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

Tip

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

ماشین مجازی، بسته‌ایست نرم‌افزاری که قابلیت نصب بر روی انواع ماشین‌ها را داراست و وظیفه‌ آن ایجاد یک ماشین مجزا (بر روی ماشین مقصد) برای اجرای مستقل کدها (بایت‌کدها) می‌باشد. به این نوع ماشین مجازی «ماشین مجازی پردازش» [11] گفته می‌شود.

بر همین اساس، هم اکنون سورس کد یک برنامه به زبان پایتون بدون نیاز به هیچ تغییری در تمام سیستم‌های عامل‌ مطرح قابل اجراست.

پایتون یک زبان برنامه‌نویسی توسعه‌پذیر (Extensible) است. کدهای نوشته شده با پایتون را می‌توان به دیگر سورس کدهای این زبان افزود و همچنین می‌توان از کتابخانه‌ها و کدهای نوشته شده با دیگر زبان‌های برنامه‌نویسی در میان کدهای پایتون استفاده کرد (مانند C و ++C در پیاده‌سازی CPython یا Java در پیاده‌سازی Jython).

پایتون دارای دستور زبانی تمیز و خوانایی (Readability) بالای کد است. خوانایی در طراحی پایتون مورد تاکید بوده و در کنار شی‌گرایی از مهم‌ترین ویژگی‌های یک کد به جهت استفاده مجدد می‌باشد. پایتون به مانند زبان ABC از روش «تو‌رفتگی» بوسیله‌ فضاهای خالی برای بلاک‌بندی [12] استفاده می‌کند. در پایتون اجباری به استفاده از نقطه ویرگول (Semicolon) ; و برخی پرانتز گذاری‌ها نمی‌باشد و البته وجود انواع داده (Data Types) - البته به بیانی درست‌تر «انواع شی» - متنوع و نیز پویایی پایتون موجب کمتر شدن حجم کد‌نویسی و صرفه‌جویی در زمان توسعه نسبت به زبان‌هایی به مانند C++ ،C و حتی Java می‌شود. تحقیقات نشان می‌دهند: کاری که یک برنامه‌نویس پایتون می‌تواند در مدت زمان دو ماه به انجام برساند، دو برنامه‌نویس ++C در مدت یک سال قادر به تکمیل آن نخواهند بود!

پایتون یک زبان حساس به حرف (Case Sensitive) است. در این نوع زبان‌ها (مانند C ،C++ ،Java ،Perl و غیره…) بین حروف کوچک (Lowercase) و بزرگ (Uppercase) به مانند a و A تفاوت وجود دارد. با توجه به این موضوع، مفسر پایتون بین کلمات True ،true و TRUE تمایز می‌گذارد.

کارایی

معمولا افراد در مواجه با یادگیری زبان پایتون نگرانی‌هایی در مورد کارایی (Performance) برنامه‌های توسعه یافته با این زبان خواهند داشت به خصوص در جایگاه مقایسه با زبان Java، به هر حال پایتون یک زبان تفسیر‌شده است و در اجرا سرعت کمتری نسبت به زبان‌های کامپایل‌شده مانند C و Java خواهد داشت. معمولا کارایی بالا برابر با سرعت بالاست ولی قضاوت در مورد کارایی به این سادگی درست نیست!

در هر پروژه‌ای بسته به چیزی که می‌خواهیم می‌بایست انتخاب نماییم. اگر مبنای کارایی برای یک پروژه در سرعت بالای اجرا باشد (مانند برنامه‌های سیستمی)؛‌ زبان C همیشه بهترین انتخاب است ولی اگر مبنا در سرعت بالای توسعه و صرفه جویی در منابع از جمله هزینه باشد انتخاب مناسب پایتون است. گاهی نیز بهترین کارایی با استفاده ترکیبی از زبان‌های متفاوت به دست می‌آید.

در بسیاری از کاربردها سرعت پایتون کاملا قابل قبول است، وجود بایت‌کد‌ موجب افزایش سرعت در اجراهای بعدی برنامه می‌شود و نکات برنامه‌نویسی زیادی برای بهبود سرعت اجرا در پایتون وجود دارد که در این کتاب به تدریج اشاره خواهد شد. نباید فراموش کرد که یکی از مهمترین عامل‌های کارایی داشتن الگوریتمی بهینه است و البته نوشتن ماژول‌ها به زبان C نیز موجب افزایش قابل توجه کارایی پایتون می‌شود - پایتون کند است اگر اشتباه استفاده شود - با این وجود در حالت عادی اگر هزار مورد وجود داشته باشد که پایتون برای آن‌ها بهترین انتخاب باشد، سرعت یکی از آن‌ها نخواهد بود و برای توسعه برنامه‌هایی که سرعت اجرا نقش بسیار تعیین کننده‌‌ای دارد باید از زبان‌های دیگری استفاده نمایید.

لازم است به این نکته هم توجه داشته باشیم که تمام این صحبت‌ها در مورد پیاده‌سازی CPython از زبان پایتون بوده و پیاده‌سازی‌های دیگری نیز از زبان پایتون با هدف سرعت بالای اجرا (به مانند PyPy) توسعه یافته است.

نسخه‌ها

هم اکنون دو شاخه از پایتون به صورت موازی (Parallel) در کنار یکدیگر در دسترس هستند: نسخه‌های 2x و 3x.

در یک سیر تاریخی، نسخه‌ پایدار 2.0 در شانزدهم اکتبر سال ۲۰۰۰ میلادی و در ادامه‌ نسخه 1.6 منتشر (Release) می‌شود؛ پس از آن نیز توسعه‌ پایتون به همان صورت پیشین ادامه می‌یابد تا این که در دسامبر سال ۲۰۰۸ میلادی نسخه‌ای از پایتون با شماره‌ 3.0 که از آن با عنوان ”Python 3000“ یا ”Py3K“ نیز یاد می‌شود، با رویکرد شکستن «سازگاری با نسخه‌های پیشین» (Backward Compatibility) منتشر می‌گردد. به بیان دیگر: مفسر نسخه‌های جدید (3x) پایتون قادر به اجرای سورس کدی که بر پایه‌ مفسر نسخه‌های پیشین تهیه شده است، نخواهد بود. (که این اتفاق در جامعه پایتون بسیار بحث برانگیز بوده و هست!)

ظاهرا آقای روسوم خیلی پیش از این زمان نیاز به ایجاد یک سری تغییرات در ساختار و سینتکس این زبان را احساس کرده بود. شاید نخستین نشانه‌ از لزوم ایجاد تغییرات در پایتون را بتوان از صحبت‌های ایشان در همایش متن باز اوریلی (OSCON) سال ۲۰۰۲ با عنوان «پشیمانی‌های پایتون» (Python Regrets) دریافت کرد. به هر صورت تیم توسعه‌ پایتون در پی رفع این نیاز، از بین حفظ گذشته‌ پایتون و پایبندی به فلسفه‌ سادگی آن؛ دومی را انتخاب می‌کند، ویژگی‌های کهنه کنار گذاشته و ویژگی‌های جدید جایگزین می‌گردند.

با انتشار یک نسخه‌ جدید به صورت معمول می‌بایست توسعه‌ نسخه‌ قدیمی متوقف شود، ولی از آنجا که زیر‌ساخت شرکت‌های بزرگی به پایتون وابسته بوده (مانند Google) و ارتقا نسخه برای آن‌ها حداقل بسیار زمان‌بر خواهد شد، برنامه‌ها و کتابخانه‌های کوچک و بزرگ بسیار زیادی توسط کاربران جامعه‌ پایتون برای نیاز‌های ریز و کلان گوناگونی توسعه یافته است که سازگار شدن تمام آن‌ها با نسخه‌ جدید پایتون بعید به نظر می‌رسد و از همه مهم‌تر خود برنامه‌نویسان پایتون می‌باشند که پس از سال‌ها اکنون مجبور هستند کارهای دیروز خود را با سینتکس و در مواقعی حتی با کتابخانه و ماژول‌هایی متفاوت به انجام برسانند؛ تیم توسعه‌ پایتون، برای پر کردن شکاف به وجود آمده بین دیروز و امروز پایتون یا به بیانی هموار کردن مسیر مهاجرت به نسخه‌ جدید پایتون،‌ علاوه بر اینکه از پیش سعی کرده بود تا ویژگی‌های جدید و سینتکس نسخه‌ 3.0 را به نسخه‌ 2.6 (که دو ماه زودتر منتشر شده بود) پورت (Port) کند، به توسعه‌ نسخه قدیمی پایان نمی‌دهد و نسخه‌ دیگری را با شماره‌ 2.7 در سوم جولای ۲۰۱۰، تقریبا یک سال پس از انتشار نسخه‌ 3.1 به همراه بسیاری از ویژگی‌های جدید آن منتشر می‌سازد.

بر طبق سند [13] PEP 404، هرگز نسخه‌ای با شماره‌ 2.8 به صورت رسمی منتشر نخواهد شد و نسخه‌ 2.7 با یک پشتیبانی طولانی مدت، نقطه‌ پایان نسخه‌ قدیمی پایتون خواهد بود. ابتدا قرار شد از این نسخه به مدت پنج سال پشتیبانی (تلاش برای رفع باگ‌ها) شود ولی چند ماه پیش، این زمان به ده سال یعنی تا سال ۲۰۲۰ افزایش یافت.

نسخه‌ پایدار (Stable) پایتون با قالب A.B.C؛ مانند 3.4.2 شماره‌‌گذاری و منتشر می‌شود. عدد A، بخش اصلی (Major) شماره نسخه است و زمانی افزایش می‌یابد که واقعا تغییرات بزرگ و زیادی در زبان پایتون ایجاد شده باشد. عدد B، بخش جزئی (Minor) شماره نسخه را نشان می‌دهد و با ایجاد یک سری تغییرات مهم در زبان پایتون افزایش خواهد یافت. عموما شماره‌ نسخه‌ پایتون تنها به صورت A.B نشان داده می‌شود، زیرا عدد C تنها با رفع اشکال (Bug) احتمالی نسخه‌ منتشر شده افزایش می‌یابد (از عدد صفر) که این امر نیز شامل همه‌ نسخه‌های پایتون نمی‌شود.

کدام نسخه؟ برای شروع یادگیری و اهداف آموزشی نسخه‌ 3x مناسب است و در صورت نیاز تنها با مطالعه‌ مقایسه بین این دو نسخه می‌توانید با نسخه‌ قدیمی نیز آشنا شوید. همچنین اگر قصد توسعه‌ برنامه‌های دسکتاپ را داشته (یعنی زمانی که محدود به نسخه‌ نصب شده بر روی سرور نیستید) یا مواقعی که در ایجاد برنامه‌ خود نیازی به کتابخانه‌هایی که هنوز (اوایل ۲۰۱۵) با نسخه‌ 3x سازگار نشده‌اند (مانند Twisted) را ندارید؛‌ استفاده از نسخه‌ 3x بسیار خوب است. به هر حال تلاش می‌شود که این کتاب بتواند به دور از آشفتگی هر دو نسخه را پوشش دهد.

پی‌نوشت

[1]برگرفته از نوشته‌های وبلاگ [The History of Python] و همینطور مصاحبه‌ [The Making of Python]
[2]”…در دسامبر سال ۱۹۸۹ دنبال یک پروژه‌ برنامه‌نویسی به عنوان سرگرمی می‌گشتم تا اوقات فراغت به وجود آمده از تعطیلات کریسمس را پر کنم. دفتر کارم (یک آزمایشگاه تحقیقاتی دولتی در آمستردام) بسته بود، ولی یک رایانه‌ شخصی داشتم و چیزی بیش از این هم در اختیارم نبود. تصمیم گرفتم تا مفسری برای یک زبان اسکریپتی جدید بنویسم. قبلا در مورد آن فکر کرده بودم: از نسل زبان ABC و جذاب برای هکرهای Unix/C. نام پایتون را برای عنوان کاری این پروژه انتخاب کردم، کمی گستاخانه ( و یک طرفدار بزرگ Monty Python’s Flying Circus)…“ - نقل از آقای روسوم [منبع]
[3]در دروس آینده به انواع داده (Data Types) در زبان پایتون به صورت کامل پرداخته می‌شود. البته خواهید دید که این مبحث در پایتون با عنوان «انواع شی» ارايه می‌گردد.
[4]برای مشاهده‌ موارد استفاده بیشتر پایتون می‌توانید به صفحه‌های [درباره پایتون] و [ویکی پایتون] مراجعه نمایید.
[5]موارد بیشتر در [ویکی پایتون]
[6]این‌ها در واقع ماژول یا کتابخانه‌هایی هستند که توسط افراد و تیم‌هایی مستقل و خارج از مجموعه‌ اصلی توسعه‌ پایتون، ایجاد و توسعه داده می‌شوند. برای دانستن بیشتر می‌توانید به [ویکی پایتون] مراجعه نمایید.
[7]متغیر در پایتون، نامی است که به یک شی (Object) در حافظه اشاره می‌کند. (در دروس آینده به آن پرداخته خواهد شد)
[8]از نسخه 2.0 و جدیدتر به پایتون (پیاده‌سازی CPython) افزوده شده است.
[9]دسته‌بندی رایج دیگر، بر مبنای نسل (Generation) است. زبان‌های نسل اول زبان‌های ماشین، نسل دوم زبان‌های اسمبلی، نسل سوم زبان‌های سطح بالایی مانند C# ،C++ ،C ،Lisp ،Cobol ،Fortran و Java هستند. زبان‌های نسل چهارم آن‌هایی هستند که برای کاربرد‌هایی خاص طراحی شده‌اند مانند NOMAD برای تولید گزارش، SQL برای پرس و جوهای (Queries) پایگاه‌ داده و Postscript برای قالب‌بندی متن. اصطلاح زبان نسل پنجم به زبان‌های مبتنی بر منطق و شرط (logic- and constraint-based) مانند Prolog و OPS5 گفته می‌شود. (آورده شده از کتاب: کامپایلرها… نوشته Aho و…، ویرایش دوم، صفحه ۱۳) - زبان پایتون یک زبان همه منظوره است و در دسته زبان‌های نسل سوم قرار می‌گیرد،‌ هر چند که نسبت به برخی از زبان‌های این نسل سطح بالاتری دارد.
[10]با توجه به نوشته‌ Jeremy Jones با عنوان Python’s (Weak) Functional Programming Paradigm.
[11]منظور از ماشین مجازی در اینجا ”Process Virtual Machine“ است و نباید با «ماشین مجازی سیستمی» (System Virtual Machine) اشتباه گرفته شود.
[12]برای نمونه: این کار در زبان Pascal توسط کلمات Begin و End، در زبان‌های C و Java توسط آکولاد { } صورت می‌گیرد.
[13]

PEPs یا Python Enhancement Proposals (طرح‌های توسعه‌ پایتون) در واقع مجموعه اسنادی است که تیم توسعه‌ پایتون از آن‌ها برای توصیف شیوه‌ طراحی، ویژگی‌های جدید یا منطق، فرآیند و راهبردهای آینده پایتون استفاده می‌کنند. فهرست: PEP 0

در این میان شیوه استاندارد کد‌نویسی در زبان پایتون توسط سندی با نام (PEP8 (Style Guide for Python Code بیان می شود که به تدریج در دروس آتی بیان خواهد شد. این سند قالب کدنویسی که هر برنامه‌نویس حرفه‌ای پایتون انتظار دارد از کدهای شما ببیند را ترسیم می‌کند.



😊 امیدوارم مفید بوده باشه

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

درس ۰۲: نصب و راه‌اندازی

در این درس به چگونگی نصب و راه‌اندازی پایتون در دو سیستم عامل ویندوز و گنولینوکس پرداخته و در پایان نیز توضیح مختصری از «سیستم مدیریت بسته» پایتون ارایه شده است.

سطح: پایه



دانلود

برای ترجمه و اجرای سورس کد ایجاد شده به زبان پایتون لازم است «بسته نصبی پایتون» (همان CPython یا اگر ساده بگوییم: پایتون) که شامل مفسر، کتابخانه استاندارد، برنامه IDLE (ویرایشگر پیش‌فرض پایتون) و… است را دانلود و بر روی سیستم عامل نصب نماییم.

Note

پایتون (Python) نام یک زبان برنامه‌نویسی است. به این معنی که ساختاری برای بیان ایده‌ها یا فرمان‌های برنامه‌نویس به ماشین می‌باشد. برای فهماندن فرمان‌های پایتونی به ماشین، مانند هر زبان سطح بالای دیگری نیاز به یک «پردازنده‌ زبان» (Language Processor) است. برنامه‌ CPython پردازنده استاندارد زبان پایتون است که از آن به صورت ساده با همان نام Python یاد می‌شود.

در هر سیستم عاملی ممکن است پایتون از پیش نصب باشد (خصوصا در گنولینوکس) که در صورت رضایت از نسخه‌ موجود، دیگر لزومی به دانلود و نصب آن نخواهد بود؛ برای آگاهی یافتن از این موضوع می‌توانید دستور python --version را در خط فرمان سیستم عامل وارد نمایید؛ البته در ویندوز به دلیل اینکه عملکرد این دستور وابسته به دستکاری متغیر Path می‌باشد، بهتر است از مسیر Control Panel >‌ Programs and Features اقدام نمایید.

Tip

Path یکی از «متغیر‌های محیطی» (Environment Variables) سیستم عامل است. این متغیر حاوی فهرست دایرکتوری‌هایی می‌باشد که سیستم عامل در آن‌ها به دنبال یک فایل اجرایی هم نام با دستور وارد شده در خط فرمان می‌گردد.

هم اکنون این بسته بر پایه دو نسخه‌ متفاوت پایتون (2x و 3x) از صفحه‌ دانلود آن، متناسب با نوع سیستم عامل و معماری پردازنده قابل دانلود است (اندازه:‌ تقریبا بین ۱۲ تا ۲۵ مگابایت) که برای نصب در ویندوز به شکل یک فایل نصبی (با قالب msi) و متناسب با دو معماری 32 (x86) و 64 (AMD64 ،EM64T ،x64 ،x86-64) بیتی منتشر می‌گردد و در صورت نیاز برای نصب آن در گنو‌لینوکس می‌بایست سورس کد آن (که به زبان C است) را دانلود نمایید.

Note

امکان نصب نسخه‌های متفاوت پایتون (حتی از یک شاخه) در کنار یکدیگر وجود دارد.

در هنگام نگارش این درس دو نسخه‌ 2.7.9 و 3.4.2 جدیدترین نسخه‌های منتشر یافته‌ پایتون هستند. برای دسترسی به جدید‌ترین ویژگی‌ها، پیشنهاد می‌شود همیشه جدیدترین نسخه‌ موجود از پایتون را دانلود نمایید.

نصب در ویندوز

درست به مانند هر برنامه‌ دیگری در ویندوز، نصب به راحتی تنها با چند بار کلیک بر روی دکمه‌ Next به پایان می‌رسد. پیشنهاد می‌شود مسیر پیش‌فرض نصب (مثلا برای نصب نسخه‌ 3.4.2:‌ \C:\Python34) را تغییر ندهید.

در هنگام نصب نسخه‌‌ای که قصد دارید از آن به صورت نسخه‌ پیش‌فرض پایتون خود استفاده نمایید، به این نکته توجه داشته باشید که در مرحله‌ سفارشی‌سازی (Customize) گزینه‌ افزودن خودکار مسیر مفسر پایتون به متغیر Path ویندوز را فعال نمایید (همانند تصویر پایین). در این صورت با وارد کردن دستور python در خط فرمان ویندوز، مفسر پایتون (این نسخه) فراخوانی می‌شود. برای شروع، با وارد کردن دستور python –V یا python --version می‌توانید از نسخه‌ پایتون نصب شده آگاهی یابید:

_images/l02-install-python-on-windows.png
> python --version
python 3.4.2

در صورت تنظیم نبودن متغیر Path می‌بایست از طریق پنجره خط فرمان و دستور cd به مسیر نصب مفسر پایتون وارد شوید:

> python --version
'python' is not recognized as an internal or external command, operable program or batch file.

> cd C:\Python34\

> python --version
python 3.4.2

البته امکان دستکاری Path در هر زمانی وجود دارد:

مسیر Control Panel > System > Advanced system settings > Advanced را طی کرده و سپس با کلیک بر روی Environment Variables پنجره‌ جدیدی باز می‌گردد که در قسمت System variables آن Path را پیدا و انتخاب نمایید. بر روی Edit در پایین همان پنجره کلیک کرده و عبارت ;C:\Python34;C:\Python34\Scripts (برای نسخه 3.4) یا ;C:\Python27;C:\Python27\Scripts (برای نسخه 2.7) را به ابتدای متن موجود در قسمت Variable value پنجره‌ جدید وارد و سپس بر روی دکمه‌ OK کلیک نمایید. :)

_images/l02-add-path-on-windows.png

Caution

در ویندوز از کاراکتر نقطه‌ ویرگول (سمی‌کالن Semicolon) یا ; برای جدا‌سازی مسیر دایرکتوری‌ها در متغیر path استفاده می‌گردد. C:\Python34 از عبارت یاد شده، مشخص کننده‌‌ مسیر مفسر پایتون (python.exe) است و با توجه به افزوده شدن pip (سیستم مدیریت بسته‌‌ پایتون) به بسته نصبی پایتون از نسخه‌ 3.4 به بعد، C:\Python34\Scripts نیز به منظور ایجاد امکان دسترسی و فراخوانی آن (pip.exe یا pip3.exe یا pip3.4.exe - فرقی ندارند) افزوده می‌شود.

اگر بخواهیم بر روی یک ویندوز از هر دو شاخه پایتون نسخه‌ای یا حتی چند نسخه‌ متفاوت از هر یک به مانند نسخه‌های 2.6، 2.7، 3.3 و 3.4 را نصب نماییم؛ یک راه خوب برای فراخوانی مفسر پایتونِ هر یک از آن‌ها در خط فرمان ویندوز، استفاده از راه‌انداز پایتون (Python Launcher) می‌باشد. در این راهکار نیازی به دستکاری متغیر Path نیست و از دستور py به جای دستور python استفاده می‌شود؛ به این صورت که با دستور py یا py -2 مفسر آخرین نسخه‌ موجود از شاخه 2x پایتون و با دستور py -3 نیز مفسر آخرین نسخه‌ موجود از شاخه 3x پایتون فراخوانی می‌گردد. برای فراخوانی مفسر دیگر نسخه‌ها هم می‌بایست نسخه‌ آن‌ها به صراحت ذکر گردد (مانند: py -3.3 و py -2.6):

> py --version
2.7.9
> py -2 --version
2.7.9
> py -2.6 --version
2.6.6
> py -3 --version
3.4.2
> py -3.3 --version
3.3.5

نصب در گنولینوکس

پایتون معمولا در توزیع‌های گنولینوکس از پیش نصب می‌باشد (بر روی برخی نیز از هر دو شاخه آن نسخه‌ایی نصب است؛ به مانند: Ubuntu و Fedora). برای اطمینان کافی است دستورات python2 --version (برای نسخه 2x) و python3 --version (برای نسخه 3x) را در خط فرمان سیستم عامل وارد نمایید؛ به عنوان نمونه وضعیت نسخه‌های پایتون در Ubuntu 14.04 به صورت پایین است:

user> python --version
python 2.7.6

user> python2 --version
python 2.7.6

user> python3 --version
python 3.4.0

Note

از آنجا که هنوز (اوایل ۲۰۱۵) نسخه‌ 2x، نسخه‌ پیش‌فرض پایتون در اکثر توزیع‌های گنولینوکس است، بنابراین دستور python --version نیز موجب فراخوانی مفسر پایتون نسخه‌ 2x و نمایش نسخه‌ آن می‌شود.

Arch Linux نخستین توزیع از گنولینوکس است که نسخه‌ 3x را به عنوان نسخه پیش‌فرض پایتون خود قرار داده است.

در دستورات یاد شده به جای version-- می‌توان از V- (حرف v بزرگ انگلیسی) نیز استفاده نمود.

اکنون با فرض اینکه توزیع مورد استفاده‌‌، از پیش فاقد نسخه‌ 3x بوده یا اینکه نسخه‌ نصب شده آنقدر قدیمی است که می‌بایست آن را ارتقا (Upgrade) داد؛ پس از دانلود سورس کد نسخه‌ جدید (در این زمان فایل: Python-3.4.2.tar.xz) به صورت زیر عمل خواهیم کرد (نصب نسخه‌ 2x نیز به همین شکل است):

نخست می‌بایست تمام بسته‌های پیش‌نیاز در سیستم عامل نصب گردند. برای این منظور می‌توانید دستورات پایین را (متناسب با نوع توزیع خود) در خط فرمان سیستم عامل وارد نمایید:

در Fedora:

user> sudo dnf update
user> sudo dnf install make automake autoconf pkgconfig glibc-devel gcc gcc-c++ bzip2 bzip2-devel tar tcl tcl-devel tix tix-devel tk tk-devel zlib-devel ncurses-devel sqlite-devel openssl-devel openssl readline-devel gdbm-devel db4-devel expat-devel libGL-devel libffi-devel gmp-devel valgrind-devel systemtap-sdt-devel xz-devel libX11-devel findutils libpcap-devel

در Ubuntu:

user> sudo apt-get update
user> sudo apt-get install build-essential
user> sudo apt-get install make automake autoconf pkg-config libc6-dev gcc g++ bzip2 libbz2-dev tar tcl tcl-dev tix-dev tk tk-dev zlib1g-dev libncursesw5-dev libsqlite3-dev libssl-dev openssl libreadline-dev libgdbm-dev db4.8-util libexpat1-dev libgl-dev libffi-dev libgmp3-dev valgrind systemtap-sdt-dev xz-utils libX11-dev findutils libpcap-dev

پس از اطمینان از نصب بسته‌های پیش‌نیاز به مسیری که سورس کد پایتون (پس از دانلود) در آن قرار دارد رفته (در اینجا: دایرکتوری Downloads) و فایل سورس کد را از حالت فشرده خارج نمایید. حاصل کار یک دایرکتوری جدید با نامی مشابه Python-3.4.2 است که با استفاده از دستور ls قابل مشاهده است؛ اکنون می‌بایست از طریق خط فرمان و دستور cd وارد مسیر آن شوید.

user> cd Downloads/
user> ls
Python-3.4.2.tar.xz

user> tar xf Python-3.4.2.tar.xz

user> ls
Python-3.4.2  Python-3.4.2.tar.xz

user> cd Python-3.4.2/

در پایان دستورات پایین را به ترتیب وارد نمایید:

user> sudo ./configure
user> sudo make
user> sudo make install

اگر پیش از این نسخه‌ای از شاخه 3x پایتون نصب باشد (مانند 3.3)، دستور سطر سوم موجب جایگزین شدن نسخه‌ جدید (3.4) با آن می‌شود؛ این دستور در مواقع ارتقا نسخه پایتون مفید است. چنانچه قصد دارید همچنان به نسخه‌ پیشین نیز دسترسی داشته باشید، دستور make altinstall را جایگزین make install نمایید. به عنوان نمونه وضعیت نسخه‌ 3x پایتون، در زمان‌ قبل و بعد از نصب نسخه‌ جدید به همراه مسیر نصب آن در Fedora 20 آورده شده است. به تفاوت عملکرد دو دستور make altinstall و make install توجه نمایید:

گرفتن نسخه‌های از پیش نصب:

user> python --version
Python 2.7.5

user> python2 --version
Python 2.7.5

user> python3 --version
Python 3.3.2

گرفتن مسیر و نسخه‌ پایتون 3x پس از نصب نسخه 3.4.2 با استفاده از دستور make altinstall :

user> which python3
/usr/bin/python3

user> which python3.4
/usr/local/bin/python3.4

user> python3 --version
Python 3.3.2

user> python3.4 --version
Python 3.4.2

گرفتن مسیر و نسخه‌ پایتون 3x پس از نصب نسخه 3.4.2 با استفاده از دستور make install :

user> which python3
/usr/local/bin/python3

user> which python3.4
/usr/local/bin/python3.4

user> python3 --version
Python 3.4.2

user> python3.4 --version
Python 3.4.2

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

user> sudo ./configure --prefix=/opt/python3.4
user> sudo make
user> sudo make install

Caution

عبارت opt/python3.4/ در سطر یکم، مشخص کننده‌‌ محل نصب پایتون است که به دلخواه خود کاربر تعیین می‌گردد.

در صورت استفاده از این روش، مفسر پایتون نسخه نصب شده را می‌توان مشابه هر یک از دو دستور زیر (با ذکر مسیر نصب - در اینجا: opt/python3.4/)‌ فراخوانی نمود:

user> /opt/python3.4/bin/python3 --version
Python 3.4.2
user> /opt/python3.4/bin/python3.4 --version
Python 3.4.2

برای راحتی در فراخوانی می‌توانید نشانی دایرکتوری مفسر پایتون را به متغیر محیطی Path سیستم عامل اضافه نمایید. برای این کار فایل پنهان bashrc. (البته چنانچه از پوسته پیش‌فرض یعنی bash استفاده می‌کنید) موجود در دایرکتوری home (مسیر ~) را توسط یک ویرایشگر متن، باز نموده و عبارتی مشابه پایین را در آن وارد و سپس تغییر ایجاد شده را ذخیره (Save) نمایید:

export PATH=$PATH:/opt/python3.4/bin

اکنون برای فراخوانی پایتون نصب شده دیگر نیازی به وارد کردن مسیر آن نمی‌باشد ولی به خاطر داشته باشید به دلیل وجود نسخه 3x ای که از پیش نصب بوده (در اینجا: 3.3.2) لازم است نسخه جدید را با ذکر صریح نسخه فراخوانی نمایید:

user> python3 --version
Python 3.3.2
user> python3.4 --version
Python 3.4.2

Note

به صورت کلی برای فراخوانی پایتون نسخه 3x از یکی از دستورات python3.4 ،python3 یا python3.x که x بیانگر بخش جزئی نسخه پایتون می‌باشد و برای نسخه 2x نیز از دستورات python2.7 ،python2 ،python یا python2.x استفاده می‌گردد. در این راستا چنانچه پایتون در مسیری خاص نصب گردد لازم است مسیر آن به متغیر Path اضافه شود. برای فراخوانی pip و IDLE هر نسخه نیز از همین رویه پیروی می‌شود.

سیستم مدیریت بسته

pip (پِپ) سیستم مدیریت بسته‌‌ پایتون است. pip ابزاری است مبتنی بر خط فرمان که از آن برای نصب، حذف، بروز رسانی و در کل مدیریت بسته‌های (یا کتابخانه‌ها‌ی شخص ثالث) پایتون استفاده می‌گردد. برنامه‌نویس پس از یافتن بسته‌ مورد نیاز خود در PyPI یا وب‌سایت‌ها و سرویس‌های دیگری به مانند github.com و bitbucket.com می‌تواند به وسیله دستور pip در خط فرمان، اقدام به نصب آن در پایتون نماید.

Tip

PyPI (پای‌پِ) یا مخزن بسته‌های پایتون (Python Package Index) محلی است که بسیاری از کتابخانه‌ها یا برنامه‌های شخص ثالث پایتون در آن نگه داری می‌شود. کاربران پایتون می‌توانند از طریق PyPI پروژه (یا بسته) خود را منتشر یا اقدام به جستجو و دانلود بسته‌های مورد نیاز خود نمایند.

pip از زمان انتشار نسخه‌ 3.4 به بسته‌ نصبی پایتون افزوده شده است و به همراه آن نصب می‌شود ولی در صورت نیاز به pip برای نسخه‌های قدیمی‌تر، می‌بایست آن را به صورت جداگانه‌ نصب نمایید.

Note

نسخه 2.7.9 پایتون پس از نسخه 3.4 منتشر شده است؛ بنابراین با نصب این نسخه و نسخه‌های جدیدتر آن از شاخه 2x پایتون نیز pip در دسترس خواهد بود.

برای نصب pip لازم است تا فایل get-pip.py را دانلود نمایید.

سپس به وسیله‌ دستوری مشابه python get-pip.py در خط فرمان، با سطح کاربری Administrator (در ویندوز) یا root (در گنولینوکس) می‌توانید اقدام به نصب pip نمایید. فراموش نشود، در زمان نصب نیاز به اتصال اینترنت می‌باشد.

Note

منظور از python در دستور python get-pip.py، فراخوانی مفسر پایتون نسخه‌ایست که قصد داریم pip را در آن نصب کنیم.

برای نمونه؛ با فرض دانلود بودن get-pip.py و قرار داشتن آن در دایرکتوری Downloads سیستم عامل،‌ برای نصب pip در نسخه 3x (مثلا قدیمی!) پایتون به صورت پایین عمل می‌نماییم:

در گنولینوکس:

user> cd Downloads/
user> sudo python3 get-pip.py

[...]
Successfully installed [...]

user> pip3 --version
pip 7.0.1 [...]

در ویندوز:

> cd Downloads\
> python get-pip.py

[...]
Successfully installed [...]

> pip --version
pip 7.0.1 [...]

توجه داشته باشید که پیش از این، محل نصب پایتون نسخه 3x به ترتیبی که گفته شد به متغیر Path ویندوز افزوده بودیم و cmd نیز به صورت Administrator اجرا شده است.

کار با pip بسیار آسان است. به عنوان نمونه برای نصب Bottle که یک وب فریم‌ورک (Web Framework) برای پایتون است از دستور pip install bottle استفاده می‌گردد. با وارد کردن این دستور، Bottle در PyPI (به عنوان مخزن پیش‌فرض pip) جستجو می‌شود و پس از یافتن، ابتدا دانلود، سپس نصب و به دایرکتوری site-packages پایتون افزوده می‌شود.

در ادامه برخی از دستورات رایج pip آورده شده است. برای کسب دانش بیشتر از چگونگی استفاده‌ pip می‌توانید به اسناد آن مراجعه نمایید.

  • نصب آخرین نسخه از یک بسته:

    # pip install [package name]
    
    root> pip install SomePackage
    
  • نصب یک نسخه خاص از یک بسته:

    # pip install [package name]==[version]
    
    root> pip install SomePackage==1.0.4
    
  • حذف یک بسته:

    # pip uninstall [package name]
    
    root> pip uninstall SomePackage
    
  • بروز رسانی یک بسته:

    # pip install --upgrade [package name]
    
    root> pip install --upgrade SomePackage
    

    برای بروز رسانی خود pip نیز از همین الگو استفاده می‌شود: pip install --upgrade pip

    البته در ویندوز می‌بایست از دستور python -m pip install -U pip استفاده نمایید.

    به جای upgrade-- می توانید از U- نیز استفاده نمایید.


  • گرفتن فهرست تمام بسته‌های نصب شده:

    user> pip list
    
  • گرفتن فهرست تمام بسته‌هایی که می‌بایست بروز رسانی شوند:

    user> pip list --outdated
    
  • مشاهده جزییات یک بسته نصب شده:

    # pip show [package name]
    
    user> pip show SomePackage
    
  • نصب تمام بسته‌هایی که درون یک فایل متنی به مانند requirements.txt مشخص شده است (فایل نمونه):

    root> pip install -r requirements.txt
    


😊 امیدوارم مفید بوده باشه

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

درس ۰۳: ایجاد و اجرای پروژه

این درس به چگونگی ایجاد پروژه‌‌های برنامه‌نویسی پایتون و اجرای آن‌ها اختصاص یافته است. درس با بیان تعاریف و رسم ساختار معمول یک پروژه شروع و اشاره‌ای نیز به ساختار پروژه‌های قابل انتشار در PyPI می‌شود. در بخش یکم تلاش شده است که تصویر کاملی از ساختار یک پروژه در ذهن خواننده ایجاد و از این طریق او با تعاریف «بسته»، «ماژول» و «اسکریپت» در زبان پایتون آشنا شود. در دو بخش‌ بعدی نیز ضمن اشاره به دو شیوه‌ اجرای دستورات پایتون، به شیوه ایجاد اسکریپت و چگونگی اجرای آن تمرکز شده است؛ چرا که پروژه‌های پایتون به این شیوه اجرا می‌گردند. در ادامه هم به روند اجرای کد توسط مفسر پایتون و همچنین معرفی بایت‌کد توجه و در نهایت نیز به معرفی virtualenv و pyvenv پرداخته شده است.

سطح: پایه



ساختار پروژه

نخستین گام در توسعه‌ یک برنامه پایتون ایجاد یک پروژه است که پس از آن نوشتن کدها یا ایجاد سورس کد (Source code) برنامه آغاز می‌شود.

سورس کد یک پروژه به زبان پایتون در قالب یک یا چند «ماژول» (Module) توسعه می‌یابد که در سورس کدهایی با بیش از یک ماژول بهتر است ماژول‌هایی که از نظر منطقی با یکدیگر مرتبط هستند را درون دایرکتوری‌هایی مجزا قرار دهیم که به این نوع دایرکتوری‌ها در زبان پایتون «بسته» (Package) گفته می‌شود.

Tip

یک یا چند ماژول درون یک دایرکتوری مشخص تشکیل یک بسته را می‌دهند و هر بسته خود می‌تواند حاوی بسته‌(های) دیگری باشد.

Note

از نسخه 3.3 پایتون با افزوده شدن ویژگی جدیدی به نام «بسته فضانام» (Namespace Package - PEP 420)، تعریف بسته پایتون به دو شاخه «بسته عادی» (Regular Package) که همان تعریف قدیمی از بسته می‌باشد و بسته فضانام گسترش یافته است. [در درس مربوط به ماژول‌ها بیشتر توضیح داده خواهد شد]

در تعریف زبان پایتون دو نوع ماژول وجود دارد:

۱- Pure Module (ماژول ناب)، همان تعریف عادی از ماژول پایتون است؛ فایل‌هایی با پسوند py که کد (تعاریف و دستورات) پایتون در آن‌ها نوشته می‌شوند.

۲- Extension Module (ماژول توسعه)، ماژول‌هایی که توسط زبان‌های برنامه‌نویسی دیگری به غیر از پایتون ایجاد شده‌اند. از درس یکم به خاطر داریم که پایتون یک زبان توسعه‌پذیر است و در کنار آن می‌توان از کد‌های نوشته شده با دیگر زبان‌های برنامه‌نویسی استفاده نمود: به مانند C و ++C در پیاده‌سازی CPython یا Java در پیاده‌سازی Jython یا #C در پیاده‌سازی IronPython - [ایجاد و استفاده از این نوع ماژول در درسی جداگانه بررسی خواهد شد.]

Note

از این پس هر جایی از کتاب که گفته شود «ماژول» منظور Pure Module خواهد بود، مگر اینکه نام «ماژول توسعه» به صراحت ذکر گردد.

در ایجاد یک پروژه از پایتون هیچ اجباری به رعایت ساختار خاصی نیست و حتی سورس کد یک پروژه می‌تواند تنها شامل یک ماژول باشد. به عنوان نمونه، شمای پایین از پروژه فرضی SampleProject را در نظر بگیرید:

SampleProject
.
├── sample_project.py
├── module_one.py
└── pakage/
    ├── __init__.py
    ├── module_two.py
    └── module_three.py

Tip

در پایتون هر بسته‌ (عادی) می‌بایست حاوی فایل ویژه‌‌‌ init__.py__ باشد که البته الزامی به کدنویسی درون این فایل وجود ندارد. این فایل دایرکتوری خود را به عنوان یک بسته (محلی برای یافتن ماژول‌ها) به مفسر پایتون معرفی می‌کند.

در ایجاد سورس کد باید به صورتی عمل شود که با اجرای یک ماژول‌ مشخص تمام برنامه اجرا گردد. این ماژول معمولا هم نام پروژه در نظر گرفته و با عنوان «اسکریپت» (Script) از آن یاد می‌شود (اینجا:‌ sample_project.py). در واقع اسکریپت، ماژولی است که با هدف اجرای برنامه توسعه می‌یابد و ایجاد سورس کد نیز از آن شروع می‌گردد. از طرفی همانطور که می‌دانیم یکی از ویژگی‌های پایتون امکان برنامه نویسی ماژولار (Modular) است به این صورت که می‌توان کد‌های خود را بر حسب نیاز در ماژول‌هایی جداگانه نوشت و با وارد کردن (Import) آن‌ها در اسکریپت (یا ماژول‌های دیگر) از کد درون آن‌ها استفاده نمود. با این منطق می‌شود سورس کد یک پروژه از پایتون را تنها شامل یک اسکریپت تصور کرد که می‌تواند توسط تعدادی ماژول گسترش یابد؛ البته ممکن است ماژول‌ها نیز بر حسب نیاز در بسته‌هایی جداگانه قرار گرفته باشند.

Tip

[PEP 8]: در نام‌گذاری ماژول‌ها تنها از حروف کوچک استفاده می‌شود و در صورت نیاز می‌توان از کاراکتر خط زیرین (_) نیز استفاده نمود. نام بسته‌ها کوتاه بوده و از حروف کوچک تشکیل می‌گردد؛ استفاده از _ در نام بسته پیشنهاد نمی‌شود.

اکنون اطلاعات کافی برای شروع یک پروژه از پایتون را دارید ولی چنانچه می‌خواهید با ساختار مناسب پروژه‌ای که قرار است برای استفاده افراد دیگر از طریق PyPI یا سرویس‌هایی نظیر github.com منتشر شود (مانند یک کتابخانه کاربردی) آشنا شوید، ادامه این بخش را نیز مطالعه نمایید. در غیر این صورت می‌توانید به بخش بعدی از همین درس پرش نمایید.

جدا از سورس کد لازم است موارد دیگری نیز در ساختار این نوع پروژه‌ها در نظر گرفته شود؛ به ساختار پایین توجه نمایید:

SampleProject
.
├── docs/
├── LICENSE.txt
├── MANIFEST.in
├── README.rst
├── requirements.txt
├── sampleproject/
│   ├── __init__.py
│   ├── module_one.py
│   ├── pakage/
│   │   ├── __init__.py
│   │   ├── module_two.py
│   │   └── module_three.py
│   ├── sample_project.py
│   └── test/
├── setup.cfg
└── setup.py

ساختار ابتدایی تنها شامل سورس کد می‌بود ولی در این ساختار تمام سورس کد در قالب یک بسته پایتون بخشی از مجموعه بزرگتری است که در آن یک سری فایل به مانند requirements.txt ،README.rst و setup.py به همراه دو دایرکتوری docs و test افزوده شده است. در ادامه کمی از کاربرد این موارد توضیح داده می‌شود ولی تاکید می‌شود که در حال حاضر نیازی به رعایت این ساختار نیست و در انتهای کتاب با ایجاد یک پروژه عملی و قرار دادن آن بر روی github.com و PyPI به صورت کاربردی با آن‌ها آشنا خواهید شد. [برای کسب اطلاعات بیشتر می‌توانید از اسناد پایتون استفاده نمایید]

setup.py: این فایل مهم دو کارکرد دارد: ۱- پیکربندی پروژه که از طریق آرگومان‌های تابع آماده ()setup درون این فایل صورت می‌پذیرد. ۲- یک رابط خط فرمان برای اجرای دستورات کاربردی مرتبط با پروژه (الگویی مشابه: <python setup.py <commands).

فهرست این دستورات از طریق وارد کردن دستوری مشابه python setup.py --help-commands قابل مشاهده است.

setup.cfg: ساختاری شبیه به یک فایل ini داشته و در صورت نیاز گزینه‌های مربوط به دستورات خط فرمان setup.py در این فایل تعریف می‌گردند. برای مشاهده فهرست گزینه‌های یک دستور مشخص می‌توانید از الگوی <python setup.py --help <commands پیروی نمایید.

README.rst: تمام پروژه‌ها می‌بایست شامل سندی برای توصیف خود باشند. در پایتون برای ایجاد اسناد معمولا از زبان نشانه‌گذاری reStructuredText استفاده می‌گردد و به همین دلیل این اسناد پسوند rst دارند که البته اجباری به این مورد نیست و می‌توانید برای ایجاد این فایل از Markdown (پسوند md) نیز استفاده نمایید.

MANIFEST.in: معمولا از این فایل برای معرفی فایل‌های غیر پایتونی موجود در پروژه استفاده می‌شود. زمانی که قصد ایجاد «سورس توزیع» یا sdist از پروژه را داشته باشید (دستوری مشابه: python setup.py sdist) تنها فایل‌های مشخصی از پروژه شناسایی می‌شوند و شناساندن باقی فایل‌ها (در صورت وجود) می‌بایست توسط این فایل (البته با الگویی خاص) انجام گیرد.

requirements.txt: از این فایل برای معرفی کتابخانه‌های خاصی که در پروژه استفاده شده‌اند و در زمان نصب یا اجرای سورس کد، وجود یا نصب بودن آن‌ها نیز ضروری است، استفاده می‌گردد.

LICENSE.txt: این فایل پروانه‌ انتشار پروژه را شامل می‌شود و اغلب حاوی یک کپی از متن پروانه‌های متن باز رایج به مانند MIT ،GPL یا BSD می‌باشد.

Note

لازم است تمامی فایل‌های یاد شده و دایرکتوری docs در بالاترین شاخه از دایرکتوری پروژه قرار داده شوند.

docs: در این دایرکتوری اسناد (راهنما، آموزش و…) پروژه قرار داده می‌شوند. ایجاد این اسناد توسط Sphinx در درسی جداگانه بررسی خواهد شد.

test: این دایرکتوری محل نگهداری برنامه تست پروژه می‌باشد. ایجاد تست پروژه نیز در درسی جداگانه بررسی می‌گردد. این دایرکتوری می‌تواند هم در بالا ترین شاخه از پروژه و هم در داخل دایرکتوری سورس کد قرار داده شود.

با ایجاد یک توزیع (Distribution) از این ساختار و انتشار آن [که در آینده خواهید آموخت]، امکان نصب پروژه از طریق pip به وجود می‌آید. معمولا به جای واژه «توزیع» از واژه «بسته» (Package) استفاده می‌گردد؛ همانطور که pip نیز «سیستم مدیریت بسته پایتون» نامیده می‌شود و هیچگاه نباید آن را با مفهوم «بسته» که تا پیش از این مطرح شده است اشتباه گرفت.

ایجاد سورس کد

برای ایجاد فایل‌های سورس کد (ماژول‌ها و اسکریپت) نیاز به هیچ برنامه یا ابزار خاصی نیست و تنها با استفاده از یک ویرایشگر ساده متن (مانند برنامه Notepad در ویندوز) می‌توانید آن‌ها را ایجاد و ویرایش نمایید.

در ادامه پروژه‌ای به نام FirstProject که سورس کد آن تنها شامل یک اسکریپت است را ایجاد می‌نماییم. وظیفه این اسکریپت فرستادن حاصل عبارت 4÷(6×5-50) به خروجی (Output) خواهد بود.

برنامه‌ ویرایشگر متن پیش‌فرض سیستم عامل را اجرا نموده و به کمک آن یکی از کدهای پایین را (متناسب با نسخه پایتون مورد نظر خود) در فایلی با نام مشابه first_project و پسوند py نوشته و بر روی دیسک (در مسیر دایرکتوری Documents سیستم عامل) ذخیره می‌نماییم.

برای نسخه 2x، ساختار FirstProject و محتوای فایل first_project_2x.py را به صورت پایین در نظر می‌گیریم:

FirstProject
.
└── first_project_2x.py
1
2
3
4
5
6
7
#-*- coding: utf-8 -*-

# Python 2.x
# File Name: first_project_2x.py
# This script prints a value to the screen.

print "(50-5×6)÷4 =", (50-5*6)/4

و برای نسخه 3x، ساختار FirstProject و محتوای فایل first_project_3x.py را به صورت پایین در نظر می‌گیریم:

FirstProject
.
└── first_project_3x.py
1
2
3
4
5
# Python 3.x
# File Name: first_project_3x.py
# This script prints a value to the screen.

print("(50-5×6)÷4 =", (50-5*6)/4)

در بخش بعدی به اجرای سورس کد FirstProject خواهیم پرداخت؛ در این بخش بهتر است کمی به بررسی کدهای آن بپردازیم:

متن ماژول‌های پایتون 2x به صورت پیش‌فرض از استاندارد یونیکد (Unicode) پشتیبانی نمی‌کنند و توسط اسکی (ASCII) کدگذاری (Encoding) می‌شوند که تنها امکان استفاده از ۱۲۸ کاراکتر را می‌دهد. می‌توان با افزودن سطری مطابق الگوی -*- coding: encoding -*-# در ابتدای ماژول‌های پایتون (سطر یکم یا دوم) شیوه کدگذاری را به شکل دلخواه تعیین نماییم. [PEP 263]

بر همین اساس کدگذاری اسکریپت first_script_2x.py را به دلیل استفاده از کاراکترهایی خارج از مجموعه ASCII (÷ و ×) به UTF-8 تغییر داده‌ایم. پایتون 3x به صورت پیش‌فرض از استاندارد یونیکد پشتیبانی می‌کند.

در زبان پایتون هر متنی که بعد از کاراکتر ”Number sign“ یا # (در همان سطر) قرار بگیرد توسط مفسر پایتون نادیده گرفته می‌شود و تاثیری در روند ترجمه و اجرای کدها ندارد، به این نوع متن‌ «توضیح» (کامنت Comment) گفته می‌شود و از آن برای مستندسازی (Documentation) ماژول یعنی ارایه توضیح در مورد بخشی از کد استفاده می‌گردد. ارایه توضیح نقش زیادی در خوانایی ماژول دارد و کمک می‌کند تا افراد دیگر - حتی خودتان - بتوانند عملکرد کدهای ماژول (یا اسکریپت) شما را بفهمند.

Note

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

سطرهای خالی (Blank Lines) نیز توسط مفسر پایتون نادیده گرفته می‌شوند و تاثیری در روند ترجمه و اجرای کدها ندارند. استفاده درست از سطرهای خالی بر خوانایی کدهای ماژول می‌افزاید.

روش رایج فرستادن داده به خروجی (اینجا:‌ چاپ بر روی صفحه نمایش) در پایتون، استفاده از دستور print (در نسخه 2x) یا تابع ()print (در نسخه 3x) است. بارزترین تفاوت نسخه 3.0 پایتون با نسخه‌های پیش از خود،‌ تبدیل دستور print به تابع (Function) می‌باشد. برای تابع، داده درون پرانتز قرار داده می‌شود. [در درسی جداگانه به بررسی تابع‌ها در پایتون خواهیم پرداخت]

دستور (یا تابع) print توانایی دریافت هر تعداد داده و از هر نوع را دارد و در صورت دریافت یک عبارت محاسباتی (Arithmetic) یا منطقی (Logical) ابتدا حاصل آن را محاسبه یا ارزیابی کرده و پس از تبدیل به نوع داده string در خروجی قرار می‌دهد. در هنگام فرستادن چندین داده گوناگون به خروجی می‌بایست آن‌ها را توسط کاما (Comma) از یکدیگر جدا نماییم. در اینجا نیز print دو داده برای فرستادن به خروجی دریافت کرده است؛ یک نوع داده string و یک عبارت محاسباتی.

به دنباله‌ای از کاراکترها که بین دو نماد نقل قول (Quotation) یا " " محصور شده‌ باشند، string گفته می‌شود.

اجرای سورس کد

در حالت کلی به دو شیوه می‌توان به زبان پایتون کد نوشت و اجرا نمود: ۱- به حالت تعاملی (Interactive) با مفسر پایتون ۲- با ایجاد اسکریپت پایتون.

شیوه تعاملی: در این روش می‌بایست ابتدا دستور فراخوانی مفسر پایتون (حالت عمومی دستور: python) را در رابط خط فرمان سیستم عامل وارد نمایید؛ توسط این دستور خط فرمان وارد حالت تعاملی پایتون می‌شود و اکنون به سادگی می‌توانید شروع به کد‌نویسی نمایید. در این حالت هر کدی که وارد شود بلافاصله اجرا شده و در صورت لزوم نتیجه آن نیز نمایش داده می‌شود. از آنجا که در این روش امکان برگشت و ویرایش کدهای وارد شده وجود ندارد، در عمل زیاد کارآمد نبوده و از آن بیشتر در مواردی مانند گرفتن نتیجه‌ قطعه کدهای کوچک، اهداف آموزشی، دریافت راهنمایی یا ماشین حساب! استفاده می‌گردد. چگونگی کار با حالت تعاملی پایتون در درس بعدی بررسی می‌شود.

user> python
Python 2.7.9 (default, Jan 12 2015, 12:41:47)
[GCC 4.9.2 20141101 (Red Hat 4.9.2-1)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> a = 3
>>> b = 2
>>> a * b
6
>>>

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

برای اجرای اسکریپت می‌بایست در خط فرمان سیستم عامل دستور فراخوانی مفسر پایتون را به همراه نام کامل اسکریپت (نشانی + نام + پسوند) وارد نمایید.

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

user> python2 Documents/FirstProject/first_project_2x.py
(50-5×6)÷4 = 5
user> python3 Documents/FirstProject/first_project_3x.py
(50-5×6)÷4 = 5.0

اگر به حاصل عبارت 4÷(6×5-50) در خروجی دو اسکریپت دقت کرده باشید حتما متوجه تفاوت آن شده‌اید. پایتون 2x حاصل تقسیم دو عدد صحیح (Integer) را به صورت یک عدد صحیح محاسبه و از مقدار بعد از ممیز (در صورت وجود) صرف نظر می‌کند ولی پایتون 3x همواره حاصل تقسیم را به صورت یک عدد اعشاری (Floating Point) و با دقتی بیشتر بر می‌گرداند. باز هم در این مورد صحبت خواهیم کرد.

نتیجه اجرای دو اسکریپت یاد شده در هر سیستم عاملی همان است که در بالا مشاهده می‌نمایید. چنانچه کاربر سیستم عامل ویندوز هستید به این نکته توجه داشته باشید که به دلیل وجود کاراکترهای خاصی (÷ و ×) که قرار است توسط print بر روی خط فرمان نمایش داده شوند و همچنین عدم پشتیبانی پیش‌فرض خط فرمان ویندوز از کدگذاری UTF-8، به هنگام اجرای اسکریپت خطایی گزارش می‌شود که ارتباطی با کد پایتون ندارد. در این مواقع پیشنهاد می‌شود از پایتون 3x و برنامه PowerShell استفاده نموده و پیش از اجرای اسکریپت دستور chcp 65001 را وارد نمایید - به صورت پایین:

PS > chcp 65001
Active code page: 65001

PS > python Documents\FirstProject\first_script_3x.py
(50-5×6)÷4 = 5.0

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

معمولا در گنولینوکس سطری به مانند پایین به ابتدای اسکریپت‌های پایتون (فقط در سطر یکم) اضافه می‌کنند، در این صورت به هنگام اجرا دیگر نیازی به فراخوانی مفسر پایتون نبوده و تنها می‌بایست پس از تغییر حالت (Mode) اسکریپت مورد نظر به حالت اجرا (توسط دستور chmod)، آن را به روش معمول در یونیکس اجرا نماییم:

1
#!/usr/bin/env python3

env یک دستور شل (Shell) یونیکس است که در زمان اجرای اسکریپت مفسر پایتون را می‌یابد و نشانی آن را جایگزین می‌کند. به جای استفاده از env می‌توان نشانی مفسر پایتون مورد نظر را به صورت صریح مانند usr/bin/python3/!# نوشت که البته در مواردی که پایتون به صورت جداگانه نصب شده باشد (نشانی مفسر در این حالت: usr/local/bin/python3/)، کارایی ندارد و موجب شکست در اجرا می‌گردد.

اکنون برای نمونه اگر اسکریپت first_script_2x.py را برای اجرا در گنولینوکس کامل‌تر سازیم:

1
2
3
4
5
6
7
8
#!/usr/bin/env python
#-*- coding: utf-8 -*-

# Python 2.x
# File: first_project_2x.py
# This script prints a value to the screen.

print "(50-5×6)÷4 =", (50-5*6)/4

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

user> chmod +x Documents/FirstProject/first_project_2x.py

user> Documents/FirstProject/first_project_2x.py
(50-5×6)÷4 = 5
user> cd Documents/FirstProject/

user> chmod +x first_project_2x.py

user> ./first_project_2x.py
(50-5×6)÷4 = 5

Note

نباید نماد !# (shebang) را با نماد کامنت در پایتون (#) اشتباه گرفت.


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

  • PyDev: یک IDE کامل، متن باز و رایگان است که برای پلتفرم Eclipse ارایه می‌شود.
  • PyCharm: محصولی از شرکت فوق‌العاده JetBrains است که البته نسخه کامل آن فروشی است ولی نسخه کامیونیتی (Community) آن رایگان و متن باز می‌باشد که از بسیاری ویژگی‌ها و امکانات ویژه برخوردار است. (مقایسه نسخه‌ها)
  • NetBeans: یک IDE کامل، متن باز و رایگان است که طرفداران بسیاری دارد. NetBeans به صورت پیش‌فرض از پایتون پشتیبانی نمی‌کند و باید پلاگین مربوط به آن نصب گردد. (صفحه راهنمای نصب)

Tip

IDE یا Integrated development environment به ابزارهایی گفته می‌شود که علاوه‌بر یک ویرایشگر متن پیشرفته، امکانات بسیار کاربردی دیگری را نیز به مانند دیباگر (Debugger) در اختیار برنامه‌نویس قرار می‌دهد.

پشت صحنه اجرا

زمانی که اقدام به اجرای یک اسکریپت می‌کنید؛ ابتدا، اسکریپت و تمام ماژول‌های وارد شده در آن به بایت‌کد کامپایل و سپس بایت‌کد‌های حاصل جهت تفسیر به زبان ماشین و اجرا، به ماشین مجازی فرستاده می‌شوند. آنچه ما از آن به عنوان مفسر پایتون (پیاده‌سازی CPython) یاد می‌کنیم در واقع ترکیبی از یک کامپایلر و یک ماشین مجازی است. تصویر پایین به خوبی روند اجرای کدهای پایتون را نمایش می‌دهد.

_images/l03-interpreter.png

بایت‌کد هر ماژول‌ پایتون در قالب فایلی با پسوند pyc که یاد‌آور py Compiled است، ذخیره می‌گردد. این فایل در یک زیردایرکتوری با نام __pycache__ داخل همان دایرکتوری ماژول ذخیره می‌شود و نام گذاری آن نیز با توجه به نام ماژول و نسخه‌ مفسر پایتون مورد استفاده، انجام می‌گیرد (نمونه: module.cpython-34.pyc). مفسر پایتون از این فایل ذخیره شده جهت افزایش سرعت اجرا در آینده بهره خواهد برد؛ به این صورت که در نوبت‌های بعدی اجرا چنانچه تغییری در کدهای ماژول یا نسخه‌ مفسر پایتون صورت نگرفته باشد، مفسر با بارگذاری فایل بایت‌کد از کامپایل مجدد سورس کد به بایت‌کد صرف نظر می‌کند.

Note

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

بایت‌کد سورس کدهایی که تنها شامل یک اسکریپت هستند در حافظه‌ (Memory) نگهداری می‌شود.

Note

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

Note

در نسخه‌های پیش از 3.2، دایرکتوری __pycache__ ایجاد نمی‌گردد و فایل بایت‌کد با نامی برابر نام ماژول و در همان دایرکتوری قرار داده می‌شود (نمونه: module.pyc). در این شیوه قدیمی علاوه بر وجود بی‌نظمی در میان فایل‌ها، تمایز بین ترجمه‌ نسخه‌های متفاوت مفسر پایتون نیز ممکن نمی‌باشد.

کدنویسی در حالت تعاملی را در درس بعدی خواهید آموخت ولی به یاد داشته باشید که مفسر پایتون محیط کدنویسی در این حالت را به مانند یک اسکریپت در نظر می‌گیرد.

ایجاد محیط مجازی

حالتی را در نظر بگیرید که در ایجاد پروژه‌های مختلف به نسخه‌های متفاوتی از برخی کتابخانه‌ها نیاز دارید؛ در این صورت چگونه می‌توانید چندین نسخه‌ متفاوت از یک کتابخانه‌ را در پایتون نصب نمایید؟ برای نمونه، فرض نمایید می‌خواهیم بر روی توسعه دو وب‌سایت؛ یکی توسط نسخه جدید (1.8) وب فریم‌ورک جنگو (Django) و دیگری بر روی یک نسخه قدیمی (0.96) از آن کار کنیم، ولی نمی‌توانیم!؛ زیرا که نمی‌شود هر دوی این نسخه‌ها را با هم در پایتون (دایرکتوری site-packages) نصب داشت. در این وضعیت راه حل ایجاد محیط‌هایی مجازی (Virtual Environments) برای توسعه پروژه‌های مورد نظر است؛ محیطی که توسعه و اجرای هر پروژه پایتون را به همراه تمام وابستگی‌های (Dependencies) آن از پروژه‌های دیگر جدا یا ایزوله (isolate) می‌کند. در ادامه به بررسی دو ابزار رایج در این رابطه می‌پردازیم.

virtualenv

در اینجا برای نصب virtualenv (ویرچوال اِنو) از pip استفاده می‌کنیم. [برای اطلاعات بیشتر به درس پیش مراجعه نمایید] - پیش از شروع هر نصبی بهتر است pip را آپدیت نماییم؛ این مراحل را در سیستم عامل گنو لینوکس به صورت پایین دنبال می‌کنیم:

user> sudo pip install -U pip

[...]
Successfully installed pip[...]

user>

نصب virtualenv:

user> sudo pip install virtualenv

[...]
Successfully installed virtualenv[...]

user>

Note

چنانچه بر روی سیستم عاملی هر دو نسخه 2x یا 3x نصب است؛ این موضوع که virtualenv را توسط pip کدام نسخه نصب نمایید، اهمیت چندانی ندارد. چرا که امکان استفاده از آن برای دیگر نسخه‌ها نیز وجود دارد.

اکنون برای ایجاد یک محیط مجازی از دستور virtualenv ENV استفاده می‌شود که منظور از ENV در آن، نشانی دایرکتوری دلخواهی است که قصد داریم محیط مجازی در آن ایجاد گردد:

user> virtualenv Documents/SampleENV/

دستور بالا موجب ایجاد یک محیط مجازی در مسیر /Documents/SampleENV سیستم عامل، بر پایه مفسر پایتونی که از pip آن برای نصب virtualenv استفاده کردیم می‌شود و چنانچه بخواهیم محیط مجازی خود را بر پایه‌ نسخه‌ موجود دیگری از پایتون ایجاد نماییم، لازم است با استفاده از گزینه python-- نشانی مفسر آن مشخص گردد [صفحه راهنما]:

user> virtualenv --python=python2 ENV
user> virtualenv --python=python3 ENV
user> virtualenv --python=/opt/python3.3/bin/python ENV

در نمونه کد‌ بالا، نسخه‌های 2.7 و 3.4 پایتون از پیش بر روی سیستم عامل نصب بوده و نسخه 3.3 توسط کاربر در مسیر opt/python3.3/ نصب شده است.

مثالی دیگر برای کاربران ویندوز:

> virtualenv --python=C:\Python25\python.exe Documents\SampleENV\

اکنون می‌توانیم در پروژه خود به کتابخانه‌ها، pip، دایرکتوری site-packages و مفسری اختصاصی دسترسی داشته باشیم. البته پیش از شروع کار با یک محیط مجازی می‌بایست آن را activate (فعال) و پس از اتمام کار نیز آن را deactivate (غیر فعال) نماییم. فعال کردن در اینجا به معنای تنظیم متغیر Path سیستم عامل بر روی مفسر محیط مجازی مورد نظر است که با غیر فعال کردن، این وضعیت از بین می‌رود.

در گنولینوکس:

user> cd Documents/SampleENV/
user> source bin/activate
(SampleENV)$
(SampleENV)$ deactivate
user>

در ویندوز:

> cd Documents\SampleENV\
> Scripts\activate.bat
(SampleENV)>
(SampleENV)> deactivate.bat
>

pyvenv

در نسخه‌های 3x پایتون و از 3.3 به بعد ماژولی با نام venv برای ایجاد محیط مجازی به کتابخانه استاندارد پایتون افزوده شده است که می‌توان از آن به جای نصب virtualenv استفاده نمود؛ برای این منظور از دستور pyvenv (پای وی اِنو) و با الگویی مشابه pyvenv ENV استفاده می‌گردد.

در گنولینوکس:

user> pyvenv Documents/SampleENV/

user> cd Documents/SampleENV/
user> source bin/activate
(SampleENV)$
(SampleENV)$ deactivate
user>

در ویندوز:

> C:\Python34\python C:\Python34\Tools\Scripts\pyvenv.py Documents\SampleENV\

یا

> C:\Python34\python -m venv Documents\SampleENV\

[در درس بعد با ساختار نمونه کد بالا آشنا می‌شوید]

> cd Documents\SampleENV\
> Scripts\activate.bat
(SampleENV)>
(SampleENV)> deactivate.bat
>


😊 امیدوارم مفید بوده باشه

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

درس ۰۴: برنامه‌نویسی تعاملی

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

سطح: پایه



حالت تعاملی

از درس پیش به خاطر داریم که کدهای پایتون را می‌توان به دو روش اجرا نمود: ۱- ایجاد اسکریپت و معرفی آن به مفسر پایتون که در همان درس بررسی شد ۲- به شکل تعاملی با مفسر پایتون که موضوع همین درس است.

پایتون یک زبان برنامه‌نویسی با قابلیت «حالت تعاملی» (Interactive Mode) است؛ این قابلیت که مبتنی بر خط فرمان است، امکانی را برای پردازش و اجرای کدهای (دستورها، عبارت‌ها [1] و تعریف‌ها) زبان پایتون فراهم می‌آورد. کدنویسی در این حالت به مانند زمانی است که یک اسکریپت را ایجاد می‌نمایید؛ ولی با هر بار فشردن کلید Enter صفحه کلید، مفسر پایتون آن را به صورت خودکار اجرا می‌کند.

البته حالت تعاملی محدودیت‌هایی دارد که خواهید دید ولی از برخی زوایا بسیار مناسب و کاربردی است؛ به عنوان نمونه ممکن است قصد آزمودن یکی از قابلیت‌های زبان پایتون را داشته باشید یا اینکه بخواهید خروجی یک قطعه کد کوتاه را مشاهده نمایید که در این صورت ایجاد اسکریپت و سپس اجرای آن می‌تواند کار پر زحمتی به نظر برسد!،‌ از طرفی دریافت راهنمایی نیز از دیگر مزایای آن است که در یادآوری، شناخت و کسب آگاهی از موارد زبان پایتون (کلمه‌های کلیدی، تابع‌ها، کلاس‌ها، ماژول‌ها و…) بسیار کاربردی و مفید می‌باشد، حتی برخی نیز از این حالت پایتون به عنوان یک ماشین حساب بهره می‌گیرند!.

برای ورود به حالت تعاملی پایتون از دستور فراخوانی مفسر (حالت عمومی: python) - به شکل تنها و بدون آرگومان‌ - در رابط خط فرمان سیستم عامل، استفاده می‌شود.

ورود به حالت تعاملی پایتون 2x - ویندوز:

> cd C:\\Python27
> python
Python 2.7.9 (default, Dec 10 2014, 12:28:03) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>

ورود به حالت تعاملی پایتون 3x - گنولینوکس:

user> python3
Python 3.4.2 (default, Jan 25 2015, 20:02:16)
[GCC 4.9.2 20141101 (Red Hat 4.9.2-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

پس از ورود یک پیغام نمایش داده می‌شود؛ در این پیغام ضمن ارایه اطلاعات پایه در مورد مفسر پایتون و سیستم عامل، پیشنهاد می‌شود که جهت یافتن اطلاعات بیشتر در مورد زبان برنامه‌نویسی پایتون از دستورهای ویژه‌ایی استفاده نمایید:

  • ()license: باعث نمایش چندین صفحه مرتبط با تاریخ توسعه و پروانه‌های پایتون می‌گردد که البته از طریق - صفحه تاریخچه و پروانه پایتون - نیز قابل مشاهده است. برای مرور از کلید Enter و خروج از کلید q صفحه کلید استفاده نمایید.
  • credits: فهرستی از سازمان‌ها و شرکت‌های مشارکت کننده در توسعه زبان پایتون را نمایش می‌دهد.
  • copyright: فهرست کپی‌رایت زبان پایتون از ابتدا تا کنون را نمایش می‌دهد.
  • help: این دستور کاربرد زیادی دارد که در ادامه بررسی می‌شود. با استفاده از این دستور می‌توان در مورد اشیا و اجزای مختلف موجود در زبان پایتون راهنمایی گرفت.

در حالت تعاملی پایتون، به صورت پیش‌فرض هر سطر توسط نماد <<< مشخص می‌شود و از آنجا که امکان وارد کردن دستورهای چند سطری (مانند تابع‌ها) نیز وجود دارد؛ سطرهای مربوط با بدنه یک دستور توسط نماد ... مشخص می‌گردند.

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

>>> print("(50-5×6)÷4 =", (50-5*6)/4)
(50-5×6)÷4 = 5.0

>>> def func():
...     print("(50-5×6)÷4 =", (50-5*6)/4)
...
>>> func()
(50-5×6)÷4 = 5.0

Caution

در پایتون برای تعریف یک تابع از کلمه کلیدی def استفاده می‌گردد که به دنبال آن نام و سپس پارامتر‌های تابع (در صورت نیاز) که درون پرانتز قرار می‌گیرند، آورده می‌شود. بعد از کاراکتر دو‌نقطه (Colon یا :) و در سطرهای بعدی با رعایت یکنواخت تورفتگی، دستورهای بدنه تابع نوشته می‌شوند. با فراخوانی تابع (وارد کردن نام تابع) بدنه تابع اجرا می‌گردد. چنانچه در تعریف تابع پارامترهایی نیز در نظر گرفته شده باشد، در هنگام فراخوانی می‌بایست مقدار متناظر آن‌ها نیز مشخص شود (درون پرانتز جلوی نام تابع) - در کد بالا تابع func فاقد پارامتر بوده بنابراین در هنگام فراخوانی آن مقداری ارسال نشده است. [فقط برای آگاهی اولیه - تابع‌ پایتون در درسی جداگانه بررسی خواهد شد]

Note

برای پایان دادن به دستورهای چند سطری می‌بایست سطر پایانی را خالی رها کرده و کلید Enter را بفشارید.

برای پاک کردن صفحه از کلید‌های ترکیبی Ctrl–L استفاده نمایید. به منظور خروج نیز می‌توانید عبارت ()quit را وارد کرده یا از کلیدهای ترکیبی Ctrl–D در گنولینوکس و Ctrl–Z با یک Enter پس از آن در ویندوز استفاده نمایید.

از مزایای حالت تعاملی این است که در بیشتر مواقع برای مشاهده نتیجه، نیازی به استفاده از print نمی‌باشد:

>>> a = 2
>>> a
2

>>> (50-5*6)/4
5.0

و چنانچه مشغول انجام محاسبات ریاضی هستید می‌توانید از یک متغیر خاص با نام _ (خط زیرین: Underscore) استفاده نمایید؛ این متغیر همواره به آخرین مقدار [2] محاسبه شده اشاره دارد:

>>> 5 * 6
30
>>> _
30
>>> 50 - _
20
>>> _ / 4
5.0

مثالی دیگر - در کاربرد ریاضی، برخی تابع‌ها توسط ماژول math از کتابخانه استاندارد پایتون در دسترس هستند [اسناد پایتون]:

>>> import math

>>> math.sqrt(36)
6.0

>>> math.pow(3, 2)
9.0

>>> math.radians(90)
1.5707963267948966

>>> math.sin(_)
1.0

برای وارد کردن یک ماژول به اسکریپت (یا ماژولی دیگر) از دستور import استفاده می‌گردد. در یک درس جداگانه به صورت کامل صحبت خواهد شد ولی برای ادامه این درس تا همین حد بدانید که برای فراخوانی تابع‌های موجود در یک ماژول import شده از الگوی «نام ماژول + نقطه + نام تابع مورد نظر» استفاده می‌گردد - در دستور import پسوند ماژول نوشته نمی‌شود.

مثالی دیگر - sys یکی از ماژول‌های مهم پایتون است؛ این ماژول امکان دسترسی به برخی از متغیرهای مورد استفاده مفسر (در زمان اجرا) و همچنین تابع‌هایی که با مفسر در ارتباط هستند را فراهم می‌آورد [اسناد پایتون]:

>>> import sys

>>> sys.version
'3.4.2 (default, Jan 25 2015, 20:02:16) \n[GCC 4.9.2 20141101 (Red Hat 4.9.2-1)]'

>>> sys.version_info
sys.version_info(major=3, minor=4, micro=2, releaselevel='final', serial=0)

>>> sys.platform
'linux'

>>> sys.getdefaultencoding()
'utf-8'

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

>>> import sys

>>> sys.exit("Error: Goodbye! :| ")
Error: Goodbye! :|

user>

دریافت راهنمایی

یکی از دستورهای پیشنهادی در پیغام ابتدایی حالت تعاملی، help بود که با وارد کردن آن متن پایین نمایش داده می‌شود:

>>> help
Type help() for interactive help, or help(object) for help about object.

به دو روش می‌توان از امکان راهنمایی استفاده کرد که در ادامه بررسی می‌شود.

Note

در هر دو روش برای مرور توضیحات طولانی از کلیدهای Enter (سطر به سطر) و Space (صفحه به صفحه) بهره بگیرید و برای خروج از توضیحات نیز از کلید q صفحه کلید استفاده نمایید؛ انتهای توضیحات نیز توسط عبارت (END) مشخص می‌شود.

روش یکم: رفتن به حالت راهنمای تعاملی

برای این منظور از دستور ()help استفاده می‌گردد - با وارد کردن این دستور ضمن نمایش پیغام خوش‌آمد گویی، نماد سطر (<<<) نیز به <help تغییر پیدا می‌کند:

>>> help()

Welcome to Python 3.4's help utility!

If this is your first time using Python, you should definitely check out
the tutorial on the Internet at http://docs.python.org/3/tutorial/.

Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules.  To quit this help utility and
return to the interpreter, just type "quit".

To get a list of available modules, keywords, symbols, or topics, type
"modules", "keywords", "symbols", or "topics".  Each module also comes
with a one-line summary of what it does; to list the modules whose name
or summary contain a given string such as "spam", type "modules spam".

help>

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

  • modules: نمایش فهرستی از نام تمامی ماژول‌های در دسترس
  • keywords:‌ نمایش تمام کلمه‌های کلیدی پایتون
  • symbols:‌ نمایش تمام نماد‌های معنادار در پایتون
  • topics: نمایش فهرستی از مباحث مربوط به پایتون
# Python 3.x

help> keywords

Here is a list of the Python keywords.  Enter any keyword to get more help.

False               def                 if                  raise
None                del                 import              return
True                elif                in                  try
and                 else                is                  while
as                  except              lambda              with
assert              finally             nonlocal            yield
break               for                 not
class               from                or
continue            global              pass

help> def

Function definitions
********************

A function definition defines a user-defined function object (see
section *The standard type hierarchy*):

[...]

A function definition is an executable statement.  Its execution binds
the function name in the current local namespace to a function object
(a wrapper around the executable code for the function).  This
function object contains a reference to the current global namespace
:

برای خروج از راهنمای تعاملی، quit (یا q) را وارد نماید.

روش دوم: فراخوانی تابع راهنما

در این روش از الگوی (help(object برای دریافت اطلاعات درباره یک شی (object)، به صورت مستقیم و بدون ورود به راهنمای تعاملی استفاده می‌شود - تنها کافی است نام شی مورد نظر را درون پرانتز قرار دهید (به جای واژه object):

>>> help(print)

Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.
(END)

>>>

Tip

print در نسخه 3x پایتون به صورت یک تابع تعریف شده است و تابع‌ها در پایتون یک نوع شی هستند.

از این روش با الگوی دیگری هم استفاده می‌شود. الگوی ("help("string یعنی قرار دادن نام موردی که می‌خواهید درباره آن اطلاعات بگیرید درون پرانتز به شکلی محصور با دو نماد نقل قول ( ” ” ) - این الگو عملکردی مشابه با روش قبل (روش یکم) دارد با این تفاوت که دریافت اطلاعات به صورت مستقیم و بدون ورود به راهنمای تعاملی انجام می‌پذیرد. در واقع برای به دست آوردن اطلاعات درباره موردی که شی نمی‌باشد (مانند هر یک از دستورهای symbols ،keywords ،modules و topics یا دستور print در پایتون 2x یا نام ماژول‌ها یا…) لازم است به این صورت اقدام گردد:

# Python 2.x

>>> help("keywords")

Here is a list of the Python keywords.  Enter any keyword to get more help.

and                 elif                if                  print
as                  else                import              raise
assert              except              in                  return
break               exec                is                  try
class               finally             lambda              while
continue            for                 not                 with
def                 from                or                  yield
del                 global              pass

>>> help("print")

The "print" statement
*********************

print_stmt ::= "print" ([expression ("," expression)* [","]]
                | ">>" expression [("," expression)+ [","]])

"print" evaluates each expression in turn and writes the resulting
object to standard output (see below).  If an object is not a string,
it is first converted to a string using the rules for string
conversions.  The (resulting or original) string is then written.  A
space is written before each object is (converted and) written, unless
the output system believes it is positioned at the beginning of a
line.  This is the case (1) when no characters have yet been written
to standard output, (2) when the last character written to standard
output is a whitespace character except "' '", or (3) when the last
write operation on standard output was not a "print" statement. (In
some cases it may be functional to write an empty string to standard
output for this reason.)

Note: Objects which act like file objects but which are not the
    built-in file objects often do not properly emulate this aspect of
    the file object's behavior, so it is best not to rely on this.

:

گزینه‌های فراخوانی

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

در پایتون 2x [اسناد پایتون]:

python [-BdEiOQsRStuUvVWxX3?] [-c command | -m module-name | script | - ] [args]

در پایتون 3x [اسناد پایتون]:

python [-bBdEhiIOqsSuvVWx?] [-c command | -m module-name | script | - ] [args]

همانطور که مشاهده می‌شود این دستور می‌تواند سه دسته آرگومان را بپذیرد:

دسته یکم (Options):

شامل برخی از حروف الفباست که به همراه یک کاراکتر خطِ فاصله (Dash) - بعد از دستور اصلی یعنی python می‌آیند؛ برخی از این گزینه‌ها به شرح زیر است:

  • q− (تنها در پایتون 3x) - در هنگام ورود به حالت تعاملی پایتون از نمایش پیغام ابتدایی صرف نظر می‌شود:

    user> python3 -q
    >>> 2 + 2
    4
    
  • Q- (تنها در پایتون 2x) - در هنگام اجرای یک اسکریپت و برای کنترل عملگرهای تقسیم / موجود در آن به کار می‌رود؛ به این صورت که پس از آن می‌بایست یکی از کلمه‌های warn ،new ،old و warnall ذکر گردد.

    • Qold: حاصل تقسیم دو عدد صحیح یک عدد صحیح باشد.
    • Qnew: حاصل تقسیم دو عدد صحیح یک عدد ممیز شناور باشد - مانند نسخه 3x پایتون.
    • Qwarn: حاصل تقسیم دو عدد صحیح یک عدد صحیح باشد، به همراه نمایش پیام هشدار به ازای هر عملگر.
    • Qwarnall: به مانند Qwarn است ولی به ازای تمام عملگرهای تقسیم به کار رفته در اسکریپت تنها یک پیام هشدار نمایش داده می‌شود.
    python -Qnew script.py
    
  • O- یا OO- - راه‌اندازی بهینه‌ساز (Optimization) پایه بایت‌کد، که می‌تواند تا حدودی موجب بهبود کارایی اسکریپت گردد. استفاده از گزینه OO- علاوه بر بهینه سازی، موجب دور انداختن مستندات [3] (Docstrings) موجود در اسکریپت نیز می‌شود:

    python -O script.py
    

    Tip

    در صورت استفاده از این گزینه‌ها، به جای فایل pyc. (بایت‌کد معمولی)، فایلی با پسوند pyo. (بایت‌کد بهینه شده) ایجاد می‌گردد.

  • B- - مفسر پایتون از ذخیره بایت‌کد ماژول‌های import شده بر روی دیسک خودداری می‌کند:

    python -B script.py
    
  • d- - برخی از گزارش‌های اضافه خطایابی (در صورت وجود) نمایش داده می‌شوند:

    python -d script.py
    
  • i- - پس از اجرای اسکریپت، خط فرمان به حالت تعاملی پایتون وارد می‌شود:

    python -i script.py
    
  • V- (برابر با version--) - نسخه پایتون نمایش داده می‌شود:

    python -V
    
  • ?- یا h- (برابر با help--) - فهرست گزینه‌های فراخوانی پایتون به همراه توضیحاتی کوتاه نمایش داده می‌شود:

    python -h
    
  • S- - از import شدن ماژول site جلوگیری می‌شود:

    python -S
    

    به صورت عادی ماژول site در زمان راه‌اندازی مفسر پایتون به صورت خودکار import می‌گردد و وظیفه آن گسترش sys.path است. به عنوان نمونه؛ این ماژول مسیر دایرکتوری site-packages را به sys.path اضافه می‌کند.

    دایرکتوری site-packages محل نگهداری بسته‌ها یا کتابخانه‌های شخص ثالثی است که با استفاده از pip اقدام به نصب آن‌ها در پایتون کرده‌ایم.

    هر زمان که ماژولی import می‌شود مفسر پایتون در داخل دایرکتوری‌های مشخصی به دنبال آن می‌گردد؛ این دایرکتوری‌ها در sys.path فهرست شده‌اند.

    برای نمونه - پایتون 3x در ویندوز:

    > python -q
    
    >>> import sys
    >>> sys.path
    ['', 'C:\\Python34', 'C:\\Windows\\SYSTEM32\\python34.zip', 'C:\\Python34\\DLLs', 'C:\\Python34\\lib', 'C:\\Python34\\lib\\site-packages']
    >>>
    

    برای نمونه - پایتون 3x در گنولینوکس:

    user> python3 -qS
    
    >>> import sys
    >>> sys.path
    ['', '/usr/local/lib/python34.zip', '/usr/local/lib/python3.4/', '/usr/local/lib/python3.4/plat-linux', '/usr/local/lib/python3.4/lib-dynload']
    >>>
    

    از گزینه S استفاده شده است و همانطور که مشاهده می‌نمایید دیگر از دایرکتوری site-packages خبری نیست!

    Tip

    نخستین دایرکتوری که مفسر در آن به دنبال نام ماژول می‌گردد؛ دایرکتوری حاوی اسکریپت است که در کدهای بالا (چون که مربوط به حالت تعاملی پایتون است) توسط '' مشخص شده است.

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

    می‌توانید با نوشتن مسیر دایرکتوری‌های دلخواه خود درون یک فایل متنی با پسوند pth. و قرار دادن آن درون دایرکتوری site-packages، این دایرکتوری‌ها را نیز به sys.path بیافزایید. برای نمونه فایل mypath.pth را (در سیستم عامل گنولینوکس) ایجاد می‌نماییم:

    user> cd /usr/local/lib/python3.4/site-packages
    user> sudo touch mypath.pth
    user> sudo chmod 777 mypath.pth
    

    فایل mypath.pth را با یک ویرایشگر متن باز کرده و مشابه پایین فهرست دایرکتوری‌های مورد نظر خود را در آن وارد می‌نماییم:

    /home/saeid/Documents
    /home/saeid/Documents/me
    

    اکنون تمام ماژول‌های موجود در این دایرکتوری‌ها قابل import هستند؛ به فهرست sys.path توجه نمایید:

    user> python3 -q
    
    >>> import sys
    >>> sys.path
    ['', '/usr/local/lib/python34.zip', '/usr/local/lib/python3.4', '/usr/local/lib/python3.4/plat-linux', '/usr/local/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/site-packages', '/home/saeid/Documents', '/home/saeid/Documents/me']
    >>>
    

    همین کار را می‌توان از طریق برنامه‌نویسی نیز انجام داد، البته پس از اتمام اجرای اسکریپت (در اینجا: خروج از حالت تعاملی) اثر آن از بین می‌رود:

    user> python3 -q
    
    >>> import sys
    >>> sys.path.append('/home/saeid/Documents')
    >>> sys.path.append('/home/saeid/Documents/me')
    

    تابع append دایرکتوری مورد نظر را به انتهای فهرست sys.path اضافه می‌کند. البته می‌توان با استفاده از تابع insert به جای append جایگاه دایرکتوری دلخواه خود را با استفاده از آرگومان نخست آن در sys.path مشخص نمود؛ با این کار دایرکتوری مورد نظر زودتر از دایرکتوری‌های بعد خودش توسط مفسر مورد جستجو قرار می‌گیرد - فایده این کار زمانی مشخص می‌شود که در دایرکتوری‌هایی مجزا، ماژولی با نام یکسان وجود داشته باشد؛ در این صورت ماژولی که زودتر توسط مفسر دیده شود به عنوان ماژول مورد نظر import می‌شود:

    user> python3 -q
    
    >>> import sys
    >>> sys.path.insert(1,'/home/saeid/Documents/me')
    >>> sys.path
    ['', '/home/saeid/Documents/me', '/usr/local/lib/python34.zip', '/usr/local/lib/python3.4', '/usr/local/lib/python3.4/plat-linux', '/usr/local/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/site-packages']
    >>>
    

    چند درس جلوتر خواهید آموخت که مقدار sys.path در واقع یک شی از نوع list است؛ append و insert نیز تابع‌هایی [4] هستند که توسط یک شی از نوع list می‌توانند فراخوانی گردند. در این مرحله تنها به یاد داشته باشید که موقعیت‌ها در یک شی از نوع list از عدد صفر شماره‌گذاری می‌گردند.

دسته دوم:

  • c command- - این الگو امکان اجرای دستورهای پایتون را بدون ورود به حالت تعاملی یا ایجاد اسکریپت، فراهم می‌سازد:

    user> python3 -c "import sys; print(sys.path)"
    ['', '/usr/local/lib/python34.zip', '/usr/local/lib/python3.4', '/usr/local/lib/python3.4/plat-linux', '/usr/local/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/site-packages']
    

    Note

    دستورها باید درون نمادهای نقل قول محصور باشند.

    استفاده از سمی‌کالن ( ; )‌ در پایان دستورهای پایتون اجباری نیست ولی چنانچه بخواهیم چند دستور را در یک سطر قرار بدهیم می‌بایست از آن استفاده نماییم.

  • m module-name- - این الگو امکان اجرای یک ماژول (از میان فهرست sys.path) را به عنوان ماژول __main__ فراهم می‌سازد.

    جالب‌ترین نمونه برای بیان کاربرد این الگو، اجرای ماژول SimpleHTTPServer است. زمانی که نیاز به راه‌اندازی سریع یک وب سرور را دارید و نمی‌خواهید خود را درگیر نصب و پیکربندی Apache یا دیگر وب سرور‌ها نمایید؛ می‌توانید از این ماژول پایتون بهره بگیرید. این ماژول امکانات یک وب سرور ساده را در اختیار شما قرار می‌دهد. البته این ماژول در نسخه 3x پایتون در ماژول http.server ادغام شده است.

    در پایتون 2x [اسناد پایتون]:

    user> python -m SimpleHTTPServer 8080
    

    در پایتون 3x [اسناد پایتون]:

    user> python3 -m http.server 8080
    

    Note

    در استفاده از این الگو نیز همانند زمان import، پسوند ماژول (py) نوشته نمی‌شود.

    می‌توان شماره پورت را وارد نکرد که در این حالت به صورت پیش‌فرض پورت 8000 در نظر گرفته می‌شود.

    ولی منظور از ماژول __main__ چیست؟

    هنگامی که ماژولی (برای نخستین بار) import می‌شود، مفسر پایتون به صورت خودکار تمام کد‌های درون آن را اجرا می‌کند. در مواردی ممکن است یک فایل py. حاوی کدهایی باشد که تنها می‌بایست در حالت اسکریپت به اجرا درآید؛ در این شرایط با import شدن فایل، این کد‌ها نیز اجرا می‌گردند که خواست برنامه‌نویس نمی‌باشد!. از طرفی در پایتون یک سری مقادیر و متغیرهای ویژه و از پیش تعریف شده به مانند __name__ وجود دارد. متغیر __name__ به نام ماژول اشاره دارد؛ در حالت اسکریپت (اجرای یک ماژول به صورت مستقیم - نمونه دستور: python script.py - درس پیش توضیح داده شد) مقدار __name__ برابر با یک مقدار ویژه به نام __main__ می‌گردد که از این موضوع می‌توان برای کنترل اجرای کدها استفاده کرد.

    معمولا کدهای اسکریپت به گونه‌ای نوشته می‌شوند که اجرای آن‌ها وابسته به اجرای یک تابع اصلی باشد که معمولا ()main نامیده می‌شود که در انتها بتوان با قرار دادن شرط برابری مقدار __name__ با __main__ برای اجرای تابع یاد شده، از اجرای کد‌های مورد نظر تنها در حالت اجرا به صورت اسکریپت (و نه در زمان import) مطمئن شد.

    1
    2
    3
    4
    5
    def main():
        print("this runs only when executed directly")
    
    if __name__ == '__main__':
        main()
    
  • script - این الگو (python script.py) بیان‌‌گر همان روش اجرای اسکریپت است که در درس پیش به صورت کامل راجب آن صحبت شد.

دسته سوم (Arguments):

همانطور که پیش از این نیز گفته شده بود می‌توان مقادیری را به عنوان آرگومان به اسکریپت در زمان به اجرا درآوردن آن ارسال نمود. این مقادیر از طریق sys.argv داخل کدهای اسکریپت قابل دسترس هستند. به نمونه اسکریپت پایین و اجرای آن توجه نمایید:

1
2
3
4
5
6
7
8
9
# file: Documents/script-argv-3x.py
# Python 3.x

import sys

print(sys.argv)
print(sys.argv[0])
print(sys.argv[1])
print(sys.argv[2])

اسکریپت بالا را با ارسال دو آرگومان arg_1 و arg_2 اجرا می‌نماییم:

user> python3 Documents/script-argv-3x.py arg_1 arg_2

['/home/saeid/Documents/script-argv-3x.py', 'arg_1', 'arg_2']
/home/saeid/Documents/script-argv-3x.py
arg_1
arg_2

مقدار sys.argv نیز یک شی از نوع list است: [… ,Ο, Ο, Ο] - برای دسترسی به عناصر موجود در شی list، از الگویی مشابه [object[index که در آن …,index=0,1,2,3 است، استفاده می‌گردد؛ به عنوان نمونه [sys.argv[0 به نخستین عنصر موجود در sys.argv اشاره دارد.

عضو نخست sys.argv یا [sys.argv[0 همواره حاوی نام اسکریپت است. البته به جز در مواقعی که از c- استفاده کرده‌ایم که در این صورت برابر مقدار 'c-' خواهد بود:

user> python3 -c "import sys; print(sys.argv)" 2
['-c', '2']

پی‌نوشت

[1]«عبارت» (Expression) یک قطعه از سینتکس است که می‌تواند به یک مقدار ارزیابی گردد، عبارت شامل «کلمه‌های کلیدی» (Keywords) نمی‌شود و «دستور» (Statement) بخشی از یک بلاک کد است که شامل کلمه‌های کلیدی بوده و کاری را به انجام می‌رساند. [کلمه‌های کلیدی در آینده بررسی می‌شوند.]
[2]درست این بود که به جای واژه «مقدار» (Value) از «شی» (Object) استفاده می‌شد؛ چرا که هر چیزی در پایتون یک شی است. به عنوان نمونه، عدد 5 یک شی از کلاس «اعداد صحیح» (Integers) می‌باشد.
[3]توضیحی است که در ابتدای تابع‌ها، کلاس‌ها و ماژول‌ها می‌آید و توسط مفسر نادیده گرفته نمی‌شود. [docstring در آینده بررسی می‌شود]
[4]واژه «تابع» در مفهوم شی، مناسب نیست. در تعریف شی‌گرا از واژه «متد» (Method) به جای «تابع» (Function) استفاده می‌گردد؛ ولی در این مرحله که هنوز به شی‌گرایی پرداخته نشده است، ترجیح داده شد تا از واژه «تابع» استفاده گردد.


😊 امیدوارم مفید بوده باشه

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

درس ۰۵: مفهوم شی‌گرایی

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

سطح: پایه



برنامه‌نویسی شی‌گرا

«برنامه‌نویسی شی‌گرا» (Object-Oriented Programming) یا به اختصار OOP یک الگو یا شیوه تفکر در برنامه‌نویسی است که برگرفته از دنیای واقعی بوده و از دهه ۱۹۶۰ میلادی مطرح گشته است. به زبانی که از این الگو پشتیبانی کند، «زبان شی‌گرا» گفته می‌شود؛ Simula 67 و Smalltalk نخستین زبان‌های برنامه‌نویسی شی‌گرا هستند. ایده شی‌گرایی در پاسخ به برخی از نیازها که الگوهای موجود پاسخ‌گو آن‌ها نبودند به وجود آمد؛ نیازهایی مانند: توانایی حل تمامی مسائل پیچیده (Complex)، «پنهان‌سازی داده» (Data Hiding)، «قابلیت استفاده مجدد» (Reusability) بیشتر، وابستگی کمتر به توابع، انعطاف بالا و…

رویکرد برنامه‌نویسی شی‌گرا «از پایین به بالا» (Bottom-Up) است؛ یعنی ابتدا واحدهایی کوچک از برنامه ایجاد می‌شوند و سپس با پیوند این واحدها، واحدهایی بزرگتر و در نهایت شکلی کامل از برنامه به وجود می‌آید. برنامه‌نویسی شی‌گرا در قالب دو مفهوم «کلاس» (Class) و «شی» (Object) ارایه می‌گردد. هر کلاس واحدی از برنامه است که تعدادی داده و عملیات‌ را در خود نگه‌داری می‌کند و هر شی نیز حالتی (State) مشخص از یک کلاس می‌باشد.

در برنامه‌نویسی شی‌گرا، هر برنامه در قالب موجودیت‌های کوچکی که در واقع همان اشیا هستند و با یکدیگر تعامل دارند در نظر گرفته می‌شود. برای داشتن این اشیا می‌بایست ابتدا کلاس‌های برنامه را تعریف نماییم؛ هر کلاس «رفتار» (Behavior) و «صفات» (Attributes) اشیایی که قرار است از آن ایجاد شوند را تعریف می‌کند. از یک کلاس می‌توان هر تعداد که بخواهیم شی ایجاد نماییم. هر شی بیانگر یک «حالت» یا یک «نمونه» (Instance) از کلاس خود است.

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

به هر شی کلاس، یک نمونه از آن کلاس گفته می‌شود و هر زمان که یک شی از کلاسی ایجاد می‌گردد در واقع یک نمونه از آن ساخته می‌شود. به این عمل در شی‌گرایی «نمونه‌سازی» (Instantiation) گفته می‌شود. بر همین اساس دو نوع کلاس در شی‌گرایی وجود دارد: ۱- کلاس‌های عادی که توانایی نمونه‌سازی دارند و به آن‌ها ”Concrete Class“ گفته می‌شود ۲- کلاس‌هایی که توانایی نمونه‌سازی ندارند و به آن‌ها ”Abstract Class“ گفته می‌شود.

یکی از مفاهیم دیگر در برنامه‌نویسی شی‌گرا، «کپسوله‌سازی» (Encapsulation) است. کپسوله‌سازی به معنی قرار دادن عناصر یک ساختار در قالب موجودیتی جدید می‌باشد. در برنامه‌نویسی شی‌گرا با ایجاد هر نمونه از کلاس، عناصر آن (صفات و رفتارها) در قالب یک موجودیت جدید به نام «شی» قرار می‌گیرد. کپسوله‌سازی در شی‌گرایی امکانی است برای پنهان‌سازی داده‌ها؛ در این شرایط اشیا بدون اینکه از درون یکدیگر و چگونگی کارکرد هم کوچکترین آگاهی داشته باشند به تعامل با یکدیگر می‌پردازند.

گفتیم هر کلاس از تعدادی داده و عملیات درون خود نگهداری می‌کند و همچنین گفتیم هر کلاس رفتار و صفات اشیایی که قرار است از آن ایجاد شوند را تعریف می‌کند؛ اکنون با ارایه تعریفی کامل‌تر خواهیم گفت که: هر کلاس از دو بخش «اعضای داده» (Data Members) و «توابع عضو» (Member Functions) تشکیل شده است. اعضای داده در واقع همان متغیر‌های درون کلاس هستند که خصوصیات یا صفات شی را بیان می‌کنند و در شی‌گرایی با عنوان «فیلد» (Field) یا «صفت» (Attribute) از آن‌ها یاد می‌شود. توابع عضو نیز عملیات یا کارهایی هستند که یک شی از کلاس قادر به انجام آن‌ها می‌باشد؛ می‌توان توابع عضو را بیانگر رفتار اشیا کلاس دانست. در شی‌گرایی به این توابع «متد» (Method) گفته می‌شود.

پس از نمونه‌سازی، شی حاوی تمامی اعضای داده و توابع عضوی است که توسط کلاس مربوط به آن تعریف شده است و برای دسترسی به آن‌ها از الگو: «نام شی + نقطه + نام صفت یا متد()» استفاده می‌گردد. همانند:

car_object.color
car_object.drive()

همانطور که در زمان پیاده‌سازی کلاس خواهید دید؛ با ایجاد هر نمونه از کلاس یک متد خاص در آن به صورت خودکار اجرا می‌گردد. این متد «سازنده» (Constructor) نام دارد و کار آن «مقداردهی اولیه» (Initialization) شی است. این کار موجب اطمینان از مقداردهی تمامی اعضای داده پیش از استفاده شی در برنامه می‌گردد.

برای مثال به کلاس خودرو برگردیم و برای آن صفات: رنگ بدنه، ظرفیت باک، بیشینه سرعت و متدهای: راندن، دریافت میزان سوخت، سوخت گیری، تنظیم سرعت، توقف را در نظر بگیریم. اکنون می‌توانیم با تنظیم صفات، نمونه‌ها یا اشیای مورد نظر خود را از این کلاس ایجاد نماییم. برای مثال: دو خودروی آبی با ظرفیت باک ۲۰ لیتر و بیشینه سرعت ۸۰ کیلومتر-ساعت یا یک خودروی صورتی با ظرفیت باک ۴۰ لیتر و بیشینه سرعت ۱۶۰ کیلومتر-ساعت که البته هر سه آن‌ها تمام متدهای کلاس را در خود دارند:

_images/l05-car-class-sample.jpg _images/l05-car-class-object-sample.jpg

تا به اینجا با مفاهیم «کلاس»، «صفت»، «متد»، «شی»، «نمونه‌سازی» و «کپسوله‌سازی» آشنا شده‌ایم؛ در ادامه به توضیح سه مفهوم مهم دیگر از برنامه‌نویسی شی‌گرا که عبارتند از: «وراثت» (Inheritance)، «چندریختی» (Polymorphism) و «انتزاع» یا «تجرید» (Abstraction) خواهیم پرداخت.

وراثت:

وراثت یکی از شکل‌های «قابلیت استفاده مجدد» کد بوده که برنامه‌نویس را قادر می‌سازد تا با ارث‌بری صفات و متدهای یک یا چند کلاس موجود، کلاس‌های جدیدی را ایجاد نماید.

برای نمونه فرض کنیم صاحب کلاس کارخانه خودروسازی مثال پیش، قصد تولید یک مدل خودرو جدید با رویکرد باربری دارد؛ بنابراین می‌بایست کلاسی جدید برای تولید آن تهیه نماید. ولی کلاس جدید علاوه‌بر صفات (ظرفیت بارگیری و..) و متدهای (انجام بارگیری، تخلیه بار و…) خاص خودش به صفات (رنگ بدنه، ظرفیت باک و…) و متدهای (راندن، سوخت گیری، توقف و…) مشابه در کلاس قبل هم نیاز دارد؛ در این حالت نیازی به تعریف مجدد آن‌ها نیست و می‌توان صفات و متدهای کلاس پیش را در کلاس جدید به ارث برد.

به کلاسی که از آن ارث‌بری می‌شود ”Parent Class“ یا ”Base Class“ (کلاس پایه) یا ”Superclass“ و به کلاسی که اقدام به ارث‌بری می‌کند ”Child Class“ (کلاس فرزند) یا ”Derived Class“ یا ”Subclass“ گفته می‌شود.

ارث‌بری توسط «نسبت هست-یک» (IS-A Relationship) بیان می‌شود؛ این نسبت می‌گوید کلاس فرزند یک نوع از چیزی است که کلاس پایه هست. کلاس A از کلاس B ارث‌بری دارد؛ در این حالت می‌گوییم: A is a type of B، یعنی درست است اگر بگوییم: «سیب» یک نوع «میوه» است یا «خودرو» یک نوع «وسیله نقلیه» است ولی توجه داشته باشید که این یک ارتباط یک‌طرفه از کلاس فرزند به کلاس پایه است و نمی‌توانیم بگوییم: «میوه» یک نوع «سیب» است یا «وسیله نقلیه» یک نوع «خودرو» است.

کلاس‌ها می‌توانند مستقل باشند ولی هنگامی که وارد رابطه‌های وراثت می‌شوند، یک ساختار سلسله مراتب (Hierarchy) به شکل درخت را تشکیل می‌دهند. برای نمونه به ساختار سلسله مراتب وراثت پایین که مربوط به برخی اشکال هندسی است توجه نمایید، پیکان‌ها نشانگر نسبت is-a هستند.

_images/l05-Inheritance-Hierarchy-Sample.png

در برنامه‌نویسی شی‌گرا نسبت دیگری نیز با عنوان «نسبت دارد-یک» (HAS-A Relationship) وجود دارد که بیانگر مفهومی به نام «ترکیب» (Composition) است که شکل دیگری از قابلیت استفاده مجدد کد می‌باشد ولی مفهومی متفاوت با وراثت دارد. این نسبت زمانی بیان می‌شود که درون یک کلاس (مانند: C) از کلاس دیگری (مانند: D) نمونه‌سازی شده باشد؛ یعنی شی کلاس C درون خودش شی‌ای از کلاس D را داشته باشد؛ در این حالت می‌گوییم: C has a D. به یاد دارید خواندیم کلاس خودرو از کلاس‌های کوچکتری ساخته شده است؛ مثلا کلاس موتور - یعنی درون این کلاس یک شی از کلاس موتور ایجاد شده است، اکنون می‌توانیم بگوییم: «خودرو» یک «موتور» دارد.

_images/l05-has-a-Sample.png

چندریختی:

مفهوم چندریختی بیانگر توانایی کلاس فرزند در تعریف متدهایی است که در کلاس پایه موجود می‌باشند. برای نمونه دو کلاس «ماهی» و «گربه» را که هر دو آن‌ها از کلاسی به نام «حیوانات» ارث‌بری دارند را در نظر بگیرید؛ در کلاس حیوانات متدی با عنوان «غذا خوردن» که عملی مشترک در میان تمام حیوانات است وجود دارد ولی از آنجا که چگونگی انجام آن در ماهی و گربه متفاوت است، بنابراین هر دو این کلاس‌ها نیاز دارند تا متد «غذا خوردن» مخصوص خود را داشته باشند - در این جاست که این متد در کلاس‌های فرزند بازتعریف می‌شود، به این عمل ”Method Overriding“ گفته می‌شود. با Override کردن یک متد، متد کلاس پایه زیر سایه متد مشابه در کلاس فرزند قرار می‌گیرد و از نظر اشیا کلاس فرزند پنهان می‌شود.

تجرید:

تجرید در برنامه‌نویسی شی‌گرا به همراه مفهوم چندریختی می‌آید و توسط دو مفهوم «کلاس‌های مجرد» (Abstract Classes) و «متدهای مجرد» (Abstract Methods) ارایه می‌گردد.

«کلاس مجرد» کلاسی است که شامل یک یا چند «متد مجرد» باشد و «متد مجرد» متدی است که اعلان (Declare) شده ولی بدنه آن ‌تعریف (Define) نشده است. کلاس‌های مجرد قابلیت نمونه‌سازی ندارند و نمی‌توان از آن‌ها شی ایجاد نمود؛ چرا که هدف از توسعه آن‌ها قرار گرفتن در بالاترین سطح (یا چند سطح بالایی) درخت وراثت، به عنوان کلاس پایه برای ارث‌بری کلاس‌های پایین‌تر می‌باشد. ایده طراحی کلاس مجرد در تعیین یک نقشه توسعه برای کلاس‌های فرزند آن است؛ تعیین صفات و متدهای لازم ولی واگذاردن تعریف متدها بر عهده کلاس‌های فرزند.

به عنوان نمونه سه کلاس «ماهی»، «گربه» و «کبوتر» را در نظر بگیرید. این کلاس‌ها جدا از رفتارهای خاص خود (مانند: «پرواز کردن» در کبوتر یا «شنا کردن» در ماهی)، در یک سری رفتار به مانند «نفس کشیدن»، «غذا خوردن» و… مشترک هستند. راه درستِ توسعه این کلاس‌ها تعیین یک «کلاس پایه» برای رفتارهای مشترک و ارث‌بری هر سه آن‌ها می‌باشد. ولی از آنجا که هر یک، این رفتارهای مشترک را به گونه‌ای دیگر انجام می‌دهد؛ راه درست‌تر آن است که یک «کلاس مجرد» به عنوان «کلاس پایه» آن‌ها در نظر بگیریم؛ در این حالت هر کدام از کلاس‌ها ضمن دانستن رفتارهای لازم می‌تواند آن‌‌ها را متناسب با خواست خود تعریف نماید.

اشیا در پایتون

علاوه‌بر اینکه پایتون یک زبان برنامه‌نویسی شی‌گراست، ساختار آن نیز بر مبنای شی‌گرایی توسعه یافته است و اینطور بیان می‌شود که هر چیزی در پایتون یک شی است. اشیا، انتزاعِ پایتون برای ارایه «انواع داده‌» (Data Types) هستند. به بیان دیگر تمام داده‌های یک برنامه پایتونی یا به صورت مستقیم یک شی است یا از روابط بین اشیا ایجاد می‌گردد. برای نمونه: 56، "!Hello World"، توابع و… حتی خود کلاس‌ها نیز توسط یک نوع شی ارایه می‌شوند.

هر شی در پایتون حاوی یک «شناسه» (identity)، یک «نوع» (type) و یک «مقدار» (value) است.

  • «شناسه» در زمان ایجاد شی به آن اختصاص می‌یابد و غیر قابل تغییر است. تابع ()id شناسه شی را به صورت یک عدد صحیح برمی‌گرداند که این مقدار در CPython بیانگر نشانی (Address) شی در حافظه (Memory) است:

    >>> id(5)
    140468674877440
    
    >>> num = 0.25
    >>> id(num)
    140468676592120
    
    >>> msg = "Hello World!"
    >>> id(msg)
    140468675425264
    
  • هر شی در پایتون دارای یک «نوع» یا ”type“ است که عملیات قابل پشتیبانی و نیز مقادیر ممکن برای شی را تعریف می‌کند. نوع هر شی توسط تابع ()type قابل مشاهده است و همانند شناسه غیر قابل تغییر می‌باشد:

    >>> # python 3.x
    >>> type(127)
    <class 'int'>
    
    >>> # python 2.x
    >>> type(127)
    <type 'int'>
    

    Caution

    تمام اعداد صحیح (Integers) در پایتون یک شی از نوع int می‌باشند. [با انواع آماده (Built-in) شی در پایتون توسط دروس آینده آشنا خواهید شد.]

  • «مقدار» برخی اشیا در پایتون قابل تغییر است که به این دسته از اشیا ”mutable“ (تغییر پذیر) گفته می‌شود؛ ولی مقدار برخی دیگر قابل تغییر نمی‌باشد (مانند اعداد: شی 127) که به آن‌ها اشیا ”immutable“ (تغییر ناپذیر) می‌گویند.

کلاس‌ها در پایتون

از نسخه 2.2 طراحی کلاس‌ها در پایتون تغییر کرد [New-style Classes] که البته ساختار قدیمی همچنان در نسخه 2x باقی مانده است. [مبنای آموزش در این کتاب طراحی جدید می‌باشد.]

در ساختار جدید مفهوم ”type“ برابر مفهوم ”class“ طراحی شده است. در این ساختار هر کلاس خود یک شی از کلاسی به نام ”type“ می‌باشد و همچنین تمامی کلاس‌ها از کلاسی به نام ”object“ ارث‌بری دارند:

>>> # Python 3.x
>>> num = 3

>>> num.__class__
<class 'int'>

>>> type(num)
<class 'int'>

>>> type(type(num))
<class 'type'>

>>> type(num).__class__
<class 'type'>

>>> type(num).__bases__
(<class 'object'>,)

Caution

صفت __class__ نام کلاس یک شی و صفت __bases__ نام کلاس‌های پایه یک کلاس را نمایش می‌دهد.

تعریف کلاس

در پایتون برای تعریف کلاس از کلمه کلیدی class استفاده می‌گردد؛ همانند الگو پایین:

class ClassName:
    <statement-1>
    .
    .
    .
    <statement-N>

کلمه کلیدی تعریف کلاس - class - یک دستور اجراپذیر (Executable Statement) است. یک کلاس پیش از اجرای دستور خود هیچ تاثیری در برنامه ندارد. این شرایط سبب می‌شود که حتی بتوان یک کلاس را در میان بدنه دستور شرط (if) یا درون بدنه یک تابع تعریف کرد. [در پشت صحنه]: با اجرای دستور تعریف کلاس، یک شی از نوع type در حافظه ایجاد می‌گردد و از نام کلاس برای اشاره به آن شی استفاده می‌شود.

بعد از کلمه کلیدی class نام کلاس (به دلخواه کاربر) نوشته می‌شود. سطر نخست تعریف مانند تمام دستورات مرکب (Compound) که به صورت معمول در چند سطر نوشته می‌شوند و سرآیند دارند، به کاراکتر : ختم می‌شود. از سطر دوم با رعایت یکنواخت تورفتگی دستورات بدنه کلاس نوشته می‌شوند:

>>> # Python 3.x

>>> class MyClassName:
...     pass
...
>>>

>>> type(MyClassName)
<class 'type'>

>>> MyClassName.__bases__
(<class 'object'>,)
>>>

Caution

در مواردی که هنوز نمی‌خواهیم دستورات مربوط به بدنه یک دستور به مانند کلاس را بنویسیم؛ می‌توانیم از دستور pass استفاده کنیم. با اجرای این دستور هیچ کاری انجام نمی‌شود.

>>> # Python 2.x

>>> class MyClassName(object):
...     pass
...
>>>

>>> type(MyClassName)
<type 'type'>

>>> MyClassName.__bases__
(<type 'object'>,)
>>>

تمامی کلاس‌ها در پایتون 3x به صورت ضمنی از کلاس object ارث‌بری دارند و نیازی به درج آن توسط برنامه‌نویس نیست؛ ولی در نسخه 2x چنانچه قصد داشته‌ باشیم از طراحی جدید کلاس‌ها پیروی کنیم، می‌بایست به صورت صریح از این کلاس ارث‌بری نماییم.

در بحث ارث‌بری نام کلاس(های) پایه مورد نظر درون پرانتز جلوی نام کلاس نوشته می‌شود. در صورت ارث‌بری از چند کلاس می‌بایست نام آن‌ها را توسط کاما (Comma) از یکدیگر جدا ساخت:

>>> # Python 3.x

>>> class ChildClassName(BaseClassNameOne, BaseClassNameTwo):
...     pass
...
>>>

>>> ChildClassName.__bases__
(<class '__main__.BaseClassNameOne'>, <class '__main__.BaseClassNameTwo'>)

Caution

همانطور که می‌دانیم،‌ __main__ اشاره به نام ماژول دارد.

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

>>> # Python 2.x

>>> class BaseClassNameOne(object):
...     pass
...
>>>

>>> class BaseClassNameTwo(object):
...     pass
...
>>>

>>> class ChildClassName(BaseClassNameOne, BaseClassNameTwo):
...     pass
...
>>>

>>> ChildClassName.__bases__
(<class '__main__.BaseClassNameOne'>, <class '__main__.BaseClassNameTwo'>)

برای دریافت نام تمام کلاس‌های پایه موجود در سلسله مراتب وراثت یک کلاس مشخص می‌توانیم از تابع ()getmro درون ماژول inspect استفاده نماییم [اسناد پایتون]؛ همانند پایین:

>>> # Python 3.x

>>> import inspect
>>> inspect.getmro(ChildClassName)
(<class '__main__.ChildClassName'>, <class '__main__.BaseClassNameOne'>, <class '__main__.BaseClassNameTwo'>, <class 'object'>)
>>> # Python 2.x

>>> import inspect
>>> inspect.getmro(ChildClassName)
(<class '__main__.ChildClassName'>, <class '__main__.BaseClassNameOne'>, <class '__main__.BaseClassNameTwo'>, <type 'object'>)

Caution

خروجی تابع ()getmro مرتب شده است؛ به این صورت که در یک سلسله مراتب از خود کلاس مورد نظر شروع می‌شود و به کلاس object پایان می‌یابد. کلاس‌های پایه هم سطح نیز بر اساس ترتیب نوشتن آن‌ها در کلاس فرزند مرتب می‌شوند.



😊 امیدوارم مفید بوده باشه

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

درس ۰۶: سینتکس

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

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

سطح: مقدماتی



سطرها

مفسر پایتون و همچنین کاربر، کدهای درون هر ماژول را در قالب تعدادی سطر می‌بینند؛ سطرهای فیزیکی (Physical Lines) و منطقی (Logical Lines). سطرهای فیزیکی در واقع همان سطرهایی است که توسط ویرایشگرهای متن شماره‌گذاری می‌شوند و به راحتی توسط کاربر قابل تشخیص هستند ولی سطرهای منطقی برداشت مفسر از اجزای برنامه است؛ هر سطر منطقی بیانگر یک دستور (Statement) پایتون است. برای نمونه دستور print در نسخه 2x پایتون را در نظر بگیرید:

1
2
msg = "Welcome!"
print msg

در نمونه کد بالا: سطر یکم، یک دستور انتساب (Assign) را نشان می‌دهد؛ این دستور مقدار سمت راست خودش را به متغیر msg نسبت می‌دهد. کم و بیش با دستور سطر دوم نیز آشنا هستید این دستور مقدار مربوط به متغیر دریافتی را بر روی خروجی نمایش می‌دهد. در اینجا دو دستور یعنی دو سطر منطقی وجود دارد که هر یک در قالب یک سطر فیزیکی پیاده‌سازی شده است.

هر چند که پیشنهاد می‌شود همیشه هر سطر فیزیکی تنها شامل یک سطر منطقی باشد ولی یک سطر فیزیکی را می‌توان شامل چند سطر منطقی نیز در نظر گرفت:

1
msg = "Welcome!"; print msg

در این حالت می‌بایست سطرهای منطقی (یا همان دستور‌ها)، توسط کاراکتر ; (Semicolon) از یکدیگر جدا گردند.

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

1
2
3
msg = "Python Programming \
Language."  # This is a message.
print msg

در نمونه کد بالا: دو سطر فیزیکی نخست از دید مفسر به شکل تنها یک سطر منطقی دیده می‌شود. در پایتون برای شکستن یک دستور در چند سطر فیزیکی از کاراکتر \ (Backslash) استفاده می‌گردد. البته توجه داشته باشید که از \ نمی‌توان برای شکستن سطر توضیح (Comment) استفاده کرد و همچنین نمی‌توان پس از آن هیچ توضیحی درج کرد.

Tip

[PEP 8]: طول هر سطر فیزیکی نباید از ۷۹ کاراکتر بیشتر شود. برای متن‌های طولانی نیز مانند توضیح (Comment) و Docstring طول هر سطر فیزیکی باید حداکثر ۷۲ کاراکتر در نظر گرفته شود.

برای خوانایی بیشتر بهتر است دستور‌های طولانی شکسته شوند. دستورهایی که شامل { }، [ ] و ( ) هستند را می‌توان بدون استفاده از \ شکست و در قالب چند سطر فیزیکی نوشت:

1
2
3
4
month_names = ['Januari', 'Februari', 'Maart',      # These are the
               'April',   'Mei',      'Juni',       # Dutch names
               'Juli',    'Augustus', 'September',  # for the months
               'Oktober', 'November', 'December']   # of the year

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

«سطرهای خالی» (Blank lines): سطری که تنها حاوی فضای خالی (Spaceها یا Tabها) باشد، توسط مفسر نادیده گرفته می‌شود و به بایت‌کد ترجمه نمی‌گردد. از این سطرها می‌توان برای خوانایی بیشتر کدها بهره گرفت - مانند سطر سوم در نمونه کد پایین:

1
2
3
4
def power(a, b):
    return a ** b

print power(2, 3)

مستند‌سازی

هر چند اساس طراحی زبان پایتون بر خوانایی بالای کد است ولی «مستندسازی» (Documentation) برنامه یعنی استفاده از امکاناتی همچون ارایه توضیح در کدها می‌تواند به درک و خوانایی هر چه بهتر کدهای برنامه برای مراجعات آینده برنامه‌نویس و افراد دیگری که می‌خواهند بر روی توسعه آن فعال باشند یا از آن استفاده کنند نیز بسیار مفید خواهد بود. در این بخش به بررسی دو امکان درج Comment و Docstring برای مستند‌سازی برنامه می‌پردازیم.

توضیح

یک «توضیح» (Comment) در زبان پایتون توسط کاراکتر # آغاز می‌شود و با پایان سطر فیزیکی هم پایان می‌پذیرد. توضیح‌ها نیز مانند سطرهای خالی توسط مفسر نادیده گرفته شده و به بایت‌کد ترجمه نمی‌شوند.

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

توضیح در پایتون تنها به شکل تک سطری تعریف شده است و برای درج توضیح‌هایی با بیش از یک سطر فیزیکی باید توجه داشت که هر سطر به صورت جداگانه می‌بایست با # آغاز شود.

Tip

[PEP 8]: متن توضیح‌ با یک فضای خالی (Space) بعد از # آغاز شود. در توضیح‌های چند سطری برای جداسازی پاراگراف‌ها از یک سطر توضیح بدون متن (سطری خالی که با # آغاز می‌شود) استفاده شود. هنگام درج توضیح در همان سطرهای دستور، توضیح حداقل به اندازه دو فضای خالی از انتهای دستور فاصله داده شود.

1
2
3
4
5
6
7
8
9
# A comment, this is so you can read your program later.
# Anything after the # is ignored by python.

print "I could have code like this."   # and the comment after is ignored

# You can also use a comment to "disable" or comment out a piece of code:
# print "This won't run."

print "This will run."

Docstring

در کنار «توضیح»؛ ”Docstring“ نیز امکان دیگری در پایتون برای ارایه توضیح بیشتر درباره کدهای برنامه است. متن Docstring توسط سه علامت نقل قول (""" یا ''') شروع و پایان می‌یابد [PEP 257] و معمولا از آن به عنوان نخستین دستور در ماژول، کلاس، تابع و متد استفاده می‌شود که در این شرایط Docstring توسط مفسر نادیده گرفته نمی‌شود و در زمان اجرا نیز با استفاده از صفت __doc__ قابل دستیابی است:

1
2
3
4
5
6
7
def complex(real=0.0, imag=0.0):
    """Form a complex number.

    Keyword arguments:
    real -- the real part (default 0.0)
    imag -- the imaginary part (default 0.0)
    """
>>> complex.__doc__
'Form a complex number.\n\n    Keyword arguments:\n    real -- the real part (default 0.0)\n    imag -- the imaginary part (default 0.0)\n    '

>>> print(complex.__doc__)
Form a complex number.

    Keyword arguments:
    real -- the real part (default 0.0)
    imag -- the imaginary part (default 0.0)

>>>

Caution

n\ بیانگر پایان سطر جاری و رفتن به سطر بعدی است - برای مشاهده درست این چنین متن‌هایی که حاوی n\ هستند می‌بایست از print استفاده نمایید.

مخاطب متن «توضیح‌» موجود در کد، کاربرانی می‌باشند که آن کد را توسعه می‌دهند در حالی که مخاطب اصلی Docstring‌ها کاربرانی است که از کد مربوط به آن استفاده می‌کنند بنابراین Docstring باید به توضیح چگونگی استفاده از کد (به صورت خاص: ماژول، تابع، کلاس و متد) بپردازد.

Docstring باید به عنوان دستور نخست درج گردد و این نکته برای یک ماژول در صورت وجود سطرهای اجرای مفسر و تعیین کد‌گذاری به صورت پایین در نظر گرفته می‌شود:

#!/usr/bin/env python
#-*- coding: utf-8 -*-

"""
Module docstring.
"""

import [...]
[...]

بسته‌ها (Packages) نیز می‌توانند Docstring داشته باشند؛ برای این منظور Docstring باید درون ماژول init__.py__ نوشته شود.

Tip

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

تورفتگی

بلاک‌بندی در زبان پایتون توسط «تورفتگی» (Indentation) سطرها مشخص می‌گردد؛ این عمل در زبان‌هایی مانند C توسط آکولاد { } انجام می‌شود. تورفتگی در واقع عبارت است از میزان فضای خالی (Spaceها و Tabها) هر دستور از ابتدای سطر فیزیکی خود. نکته مهم این است که تمام دستورهای موجود در یک بلاک می‌بایست به یک میزان فاصله نسبت به سرآیند خود تورفتگی داشته باشند:

1
2
3
4
5
6
// C

if (x > y) {
x = 1;
y = 2;
}
1
2
3
4
5
# Python

if x > y:
    x = 1
    y = 2

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

_images/l06-python-Indentation-block.png

Tip

[PEP 8]: در ایجاد تورفتگی استفاده از کلید Space نسبت به کلید Tab ترجیح داده می‌شود - برای هر مرتبه تورفتگی از چهار کلید Space استفاده نمایید.

روش رایج ایجاد تورفتگی استفاده از کلید Space است و سعی کنید هرگز به صورت ترکیبی از کلیدهای Sapce و Tab استفاده نکنید هر چند که در نسخه 3x پایتون امکان استفاده ترکیبی از این دو کلید وجود ندارد! اگر مایل به استفاده از کلید Tab هستید باید به صورت یکدست تمام تورفتگی‌های برنامه خود را فقط با استفاده از آن ایجاد نمایید.

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

1
2
3
4
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

در دستورهایی به مانند پایین نیز ایجاد تراز آرگومان‌ها هم حالت مناسبی است:

1
2
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

دستور

«دستور» (Statement) واحدی از کد است که شامل کلمه‌های کلیدی بوده، اجرا می‌گردد و کاری را به انجام می‌رساند. در پایتون دو نوع دستور وجود دارد:

دستورهای ساده (Simple Statements): دستورهایی هستند که تنها در یک سطر منطقی پیاده‌سازی می‌شوند. مانند دستور import، دستور pass، دستور انتساب، فراخوانی تابع و…

دستورهای مرکب (Compound Statements): گروهی از دستورها هستند که می‌توانند یک بخشی (مانند: دستور def - تعریف تابع) یا چند بخشی (مانند: دستور شرط if / elif / else) باشند؛ هر بخش (Clause) نیز شامل یک سرآیند (Header) و یک بدنه (Suite) است. هر سرآیند با یک کلمه کلیدی آغاز می‌شود و با یک : (Colon) نیز پایان می‌پذیرد. بدنه پس از سرآیند و با رعایت سطح تورفتگی بیشتر نسبت به آن نوشته می‌شود:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
def binary_search(seq, key):
    lo = 0
    hi = len(seq) - 1
    while hi >= lo:
        mid = lo + (hi - lo) // 2
        if seq[mid] < key:
            lo = mid + 1
        elif seq[mid] > key:
            hi = mid - 1
        else:
            return mid
    return False

شناسه

«شناسه» (Identifier) نامی است نمادین که به دلخواه کاربر تعیین و از آن برای شناسایی (identify) متغیر‌ها، توابع، کلاس‌ها، ماژول‌ها یا دیگر اشیا پایتون از یکدیگر استفاده می‌شود. انتخاب شناسه در پایتون نکاتی دارد که می‌بایست از سوی کاربر در نظر گرفته شود:

  • تنها با یکی از حروف بزرگ یا کوچک الفبا انگلیسی (A..Z یا a..z) یا کاراکتر _ (Underscore) شروع شود.
  • در ادامه می‌تواند هیچ یا چند حرف الفبا انگلیسی (کوچک و بزرگ)، کاراکتر _ و عدد (9..0) - با هر ترتیبی - آورده شود.
  • هیچ محدودیتی در طول شناسه وجود ندارد و می‌تواند از یک تا هر تعداد کاراکتر باشد.

با یک نگاه حرفه‌ای‌تر، ساختار لغوی (Lexical) شناسه به شکل پایین بیان می‌شود [اسناد پایتون]:

identifier  ::= (letter|"_") (letter | digit | "_")*

letter      ::= lowercase | uppercase
lowercase   ::= "a"..."z"
uppercase   ::= "A"..."Z"
digit       ::= "0"..."9"

Caution

در تعاریف regex: از پرانتز ( ) برای گروه‌بندی استفاده می‌شود. نماد | به معنی یا می‌باشد و از آن برای جدا‌سازی دو عبارت متفاوت استفاده می‌شود. نماد * به معنی صفر بار تکرار یا بیشتر می‌باشد. [درسی جداگانه به regex اختصاص خواهد یافت]

Tip

  • استفاده از کاراکترهای خاص به مانند .، !، @، #، $، % و… مجاز نمی‌باشد.
  • استفاده از «فاصله» (Space) مجاز نمی‌باشد.
  • استفاده از «خط تیره» (Hyphen) یعنی کاراکتر - برای جداسازی کلمه‌ها در نام ماژول مجاز است ولی پیشنهاد نمی‌شود.

برای نمونه - چند شناسه درست:

a    _p    __var    MyClass    get_length    getLength    var2    var_2    S01E16

برای نمونه - چند شناسه نادرست:

me@mail    get.length    2_var    6    $var    4pi

Tip

همانطور که از درس یکم می‌دانیم، پایتون یک زبان حساس به حرف (Case Sensitive) است و مفسر آن بین حروف کوچک (Lowercase) و بزرگ (Uppercase) به مانند a و A تمایز می‌گذارد.

برای نمونه، تمامی شناسه‌های CaR ،cAR ،CAr ،caR ،cAr ،Car ،car و CAR متفاوت با یکدیگر ارزیابی می‌شوند.

در پایتون از تکنیکی به نام Name Mangling استفاده می‌شود. توسط این تکنیک و تنها با شیوه انتخاب شناسه‌ها، نقشی خاص به آن‌ها داده می‌شود:

  • شناسه خصوصی (Private) ماژول: اگر شناسه‌ای با یک کاراکتر _ آغاز شود (و نه پایان پذیرد) توسط مفسر پایتون در این نقش ارزیابی می‌گردد. مانند: name_ (و نه: _name_ یا _name)
  • شناسه خصوصی کلاس: اگر شناسه‌ای با دو کاراکتر _ آغاز شود (و نه پایان پذیرد) توسط مفسر پایتون در این نقش ارزیابی می‌گردد. مانند: name__ (و نه: __name__ یا __name)

جدا از این مورد، در پایتون صفت‌ها (Attributes) و متدهای خاصی وجود دارد که از پیش تعریف گشته‌اند و برای مفسر مفهوم مشخصی دارند. شناسه این صفت‌ها و متدها با دو کاراکتر _ آغاز می‌شود و همینطور پایان می‌پذیرد؛ درست به مانند صفت‌های __class__ و __doc__ که پیش از این استفاده کردیم.

بنابراین به هنگام استفاده از کاراکتر _ در شناسه (به خصوص در ابتدای آن) باید آگاهی کافی داشته باشیم. [به موارد اشاره شده در آینده پرداخته خواهد شد.]

Tip

[PEP 8]: شیوه استاندارد انتخاب شناسه برای کلاس‌، تابع، متد و متغیر به صورت پایین است:

  • کلاس‌ها به شیوه PascalCase - یعنی تنها حرف نخست هر کلمه بزرگ باشد و کلمه‌ها بدون فاصله کنار هم قرار بگیرند - نام‌گذاری شوند. مانند: AnimalClass ،Animal.
  • نام انتخابی برای یک تابع و متد‌ نیز باید تنها شامل حروف کوچک باشد و برای جداسازی کلمه‌ها از _ استفاده شود. مانند: bubble_sort ،binary_search و… البته می‌توان از شیوه camelCase (همانند PascalCase با این تفاوت که حرف نخست کلمه یکم هم می‌بایست حرف کوچک باشد) نیز استفاده نماییم. مانند: bubbleSort ،binarySearch و…
  • نام‌ متغیرها تنها باید شامل حروف کوچک باشد که کلمه‌های آن توسط _ از یکدیگر جدا شده‌اند. مانند: body_color ،color و…

برای شناسه‌های تک حرفی توجه داشته باشید که از انتخاب حروف l (اِل کوچک) و I (آی بزرگ) اجتناب کنید زیرا این دو حرف در برخی فونت‌ها شبیه هم هستند و البته همینطور حرف O (اُ بزرگ) که می‌تواند شبیه به صفر باشد.

کلمه‌های کلیدی

نکته پایانی در مورد شناسه‌ها این است که: نمی‌توان یک شناسه را برابر با یکی از «کلمه‌های کلیدی» (keywords) پایتون انتخاب کرد. کلمه‌های کلیدی در واقع شناسه‌هایی هستند که از پیش برای مفسر پایتون تعریف شده‌اند و معنای مشخصی برای آن دارند. فهرست این کلمه‌های در پایتون به صورت پایین است:

>>> # Python 3.x

>>> help("keywords")
Here is a list of the Python keywords.  Enter any keyword to get more help.

False               def                 if                  raise
None                del                 import              return
True                elif                in                  try
and                 else                is                  while
as                  except              lambda              with
assert              finally             nonlocal            yield
break               for                 not
class               from                or
continue            global              pass
>>> # Python 2.x

>>> help("keywords")
Here is a list of the Python keywords.  Enter any keyword to get more help.

and                 elif                if                  print
as                  else                import              raise
assert              except              in                  return
break               exec                is                  try
class               finally             lambda              while
continue            for                 not                 with
def                 from                or                  yield
del                 global              pass

در کتابخانه استاندارد پایتون ماژولی به نام keyword وجود دارد [اسناد پایتون]:

>>> # Python 3.x

>>> import keyword

>>> keyword.iskeyword(a)
False

>>> keyword.iskeyword("def")
True

>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

Caution

تابع ()iskeyword بررسی می‌کند که آیا آرگومان دریافتی یکی از کلمه‌های کلیدی می‌باشد یا نه؛ در صورت تایید مقدار True را باز می‌گرداند. kwlist نیز در واقع یک شی لیست حاوی تمام کلمه‌های کلیدی است.

شاید کنجکاو باشید تعداد کلمه‌های کلیدی پایتون را بدانید؛ برای این منظور نیازی به شمارش دستی نیست!:

>>> # Python 3.x
>>> import keyword
>>> len(keyword.kwlist)
33

>>> # Python 2.x
>>> import keyword
>>> len(keyword.kwlist)
31

Caution

تابع ()len تعداد اعضای یک شی را باز می‌گرداند [اسناد پایتون].

برخی نکات:

  • در پایتون 3x: تنها کلمه‌های کلیدی True ،False و None با حرف بزرگ آغاز می‌شوند.
  • در پایتون 2x: کلمه‌های کلیدی True ،False و None تعریف نشده است.
  • در پایتون 3x: از آنجا که print به یک تابع تبدیل گشته، کلمه کلیدی print تعریف نشده است.

Tip

[PEP 8]: چنانچه می‌خواهید شناسه‌ای مشابه با یکی از کلمه‌های کلیدی انتخاب نمایید؛ می‌توانید این کار را با استفاده از یک _ در انتهای کلمه مورد نظر به انجام برسانید. مانند: _def

متغیر

یک «متغیر» (Variable) در بیشتر زبان‌های برنامه‌نویسی به مانند C بیانگر محلی در حافظه می‌باشد که مقداری در آن قرار گرفته است. برای نمونه سه دستور پایین را در نظر بگیرید:

int a = 1;

a = 2;

int b = a;

در نمونه کد بالا: دستور ;int a = 1 بیان می‌کند که محلی از حافظه به نام a برای نگهداری اعداد صحیح (integers) در نظر گرفته شود و مقدار 1 در آن قرار بگیرد؛ از این پس متغیر a معرف این نقطه از حافظه می‌باشد (درست به مانند یک جعبه) که اکنون حاوی مقدار 1 است (شکل پایین - یک). در ادامه دستور ;a = 2 موجب می‌شود مقدار پیشین متغیر a حذف (از جعبه خارج) و مقدار جدید یعنی 2 در آن قرار داده شود (شکل پایین - دو). توجه داشته باشید که در این دسته زبان‌ها، نوع (type) توسط متغیر تعیین می‌گردد و تلاش برای قرار دادن نوع داده دیگری به غیر از int در متغیر a (به مانند 3.7 یا "string") موجب بروز خطا در زمان کامپایل می‌گردد. دستور سوم:‌ ;int b = a در ابتدا موجب ایجاد یک محل جدید در حافظه با نام b و از نوع همان اعداد صحیح می‌شود و سپس مقدار درون متغیر a را درون آن کپی می‌کند؛ اکنون دو محل برای نگهداری نوع داده int در حافظه موجود است که هر دو حاوی مقدار 2 می‌باشند (شکل پایین - سه).

_images/l06-c-variable.png

ولی در پایتون:

یک متغیر چیزی نیست جز یک نام که به یک شی مشخص در حافظه ارجاع (یا اشاره) دارد. تعریف متغیر در پایتون بسیار ساده است و تنها با انتساب (Assign) شی به یک نام ایجاد می‌گردد. نمادِ =، عملگر (Operator) انتساب در پایتون است. در تعریف متغیر پایتون برخلاف آنچه در زبان C مشاهده کردیم ;int a،‌ نیازی به تعیین نوع برای آن نیست چرا که نوع (type) از روی شی تعیین می‌گردد و یک متغیر در طول زمان اجرا می‌تواند به شی‌هایی از انواع متفاوت ارجاع داشته باشد. برای نمونه سه دستور پایین را در نظر بگیرید:

a = 1

a = 2

b = a

مفسر با رسیدن به دستور a = 1، سه گام پایین را انجام می‌دهد:

  1. یک شی از نوع اعداد صحیح و مقدار 1 را در جایی از حافظه ایجاد می‌کند. چرا اعداد صحیح؟ نوع توسط شی تعیین می‌گردد و 1 عددی است صحیح!.
  2. متغیرِ (یا همان نامِ) a را در جایی دیگر از حافظه ایجاد می‌کند (البته در صورتی که قبلا ایجاد نشده باشد).
  3. یک پیوند از متغیر a به شی 1 برقرار می‌کند. به این پیوند «ارجاع» (Reference) گفته می‌شود که به صورت یک اشاره‌گر (Pointer) در حافظه پیاده‌سازی می‌گردد.
_images/l06-python-variable-01.png

انتساب شی دیگری (که می‌تواند از هر نوع دیگری باشد) به یک متغیر موجود؛ موجب حذف ارجاع قبلی آن و ارجاع به شی جدید می‌شود. دستور a = 2 موجب ایجاد شی 2، حذف ارجاع متغیر a به شی 1 و ایجاد ارجاعی جدید از متغیر a به شی 2 می‌شود. هر متغیر نامی است برای اشاره به یک شی؛ دستور b = a نیز می‌گوید: یک متغیر جدید با نام b ایجاد گردد و به همان شی‌ای ارجاع داشته باشد که متغیر a ارجاع دارد.

ولی اکنون که ارجاعی به شی 1 وجود ندارد، با آن چه می‌شود؟

هر شی شامل یک «شمارنده ارجاع» (Reference Counter) نیز هست؛ به این صورت که در هر لحظه تعداد ارجاع‌ها به آن شی را نشان می‌دهد و با هر ارجاع جدید به شی، یک واحد به آن اضافه می‌شود و با حذف هر ارجاع نیز یک واحد کاهش می‌یابد. چنانچه مقدار آن به صفر برسد، شی آن توسط تکنیک ”Garbage Collection“ پاک می‌گردد و مقدار حافظه‌ای که توسط شی مصرف شده بود آزاد می‌گردد. برای مشاهده تعداد ارجاع‌ها به یک شی می‌توان از تابع ()getrefcount درون ماژول sys استفاده کرد [اسناد پایتون].

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

>>> import sys

>>> a = 1
>>> sys.getrefcount(1)
760

>>> a = 2
>>> sys.getrefcount(1)
759
>>> sys.getrefcount(2)
96

>>> b = a
>>> sys.getrefcount(2)
97

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

انتساب چندگانه

امکان ایجاد همزمان چند متغیر یا انتساب‌های چندگانه در پایتون وجود دارد - می‌توان چند متغیر که همگی به یک شی ارجاع دارند را ایجاد کرد:

>>> a = b = c = "python"

>>> a
'python'
>>> b
'python'
>>> c
'python'

برای انتساب اشیا متفاوت می‌بایست از ویرگول (Comma) و تنها یک عملگر انتساب (=) استفاده نماییم - توجه داشته باشید که تعداد عناصر دو طرف عملگر انتساب می‌بایست برابر باشد:

>>> a, b, c, d = 1, 4.5, "python", 2

>>> a
1
>>> b
4.5
>>> c
'python'
>>> d
2

یکی از کاربردهای انتساب چندگانه این است که می‌توان اشیا دو متغیر را به سادگی و تنها با یک سطر دستور با یکدیگر عوض کرد:

>>> a = 1
>>> b = 2

>>> a, b = b, a

>>> a
2
>>> b
1

ثابت

«ثابت» (Constant) به متغیری گفته می‌شود که مقدار آن همواره ثابت بوده و پس از تعریف دیگر امکان تغییر مقدار آن وجود ندارد. برای نمونه یک ثابت در زبان Java به شکل پایین تعریف می‌گردد - پس از دستور پایین هر گونه تلاش برای تغییر مقدار ثابت HOURS با خطا روبرو می‌گردد:

1
final int HOURS = 24;

در پایتون امکانی برای تعریف ثابت پیش‌بینی نشده است!.

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

ولی برای ایجاد ثابت می‌توانید متغیر‌های مورد نظر خود را در ماژولی جدا تعریف نمایید و در هر جایی که لازم بود با import آن به متغیرهای مورد نظر خود دسترسی یابید:

1
2
3
4
# File: constant.py
# Path: /home/saeid/Documents/MyModule

HOURS = 24
>>> import sys
>>> sys.path.append('/home/saeid/Documents/MyModule')

>>> import constant
>>> constant.HOURS
24

البته اگر تغییر‌ناپذیر بودن متغیرها برایتان اهمیت ویژه دارد می‌توانید ماژولی حاوی کد پایین ایجاد نمایید [منبع]:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# File: constant.py
# Path: /home/saeid/Documents/MyModule

class _const:

    class ConstError(TypeError): pass

    def __setattr__(self, name, value):
        if name in self.__dict__:
            raise self.ConstError("Can't rebind const(%s)" % name)
        self.__dict__[name] = value

import sys
sys.modules[__name__] = _const()
>>> import sys
>>> sys.path.append('/home/saeid/Documents/MyModule')

>>> import constant
>>> constant.HOURS = 24
>>> constant.HOURS
24
>>> constant.HOURS = 23
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/saeid/Documents/MyModule/constant.py", line 10, in __setattr__
    raise self.ConstError("Can't rebind const(%s)" % name)
constant.ConstError: Can't rebind const(HOURS)
>>> constant.HOURS
24

درک کد کلاس const_ نیاز مطالعه درس‌های کلاس و استثنا‌ها (Exceptions) دارد. ولی برای توضیحی کوتاه در این درس باید گفت که:

مفسر پایتون برای اینکه بداند کدام نام به کدام مقدار یا شی ارجاع دارد از ساختاری مشابه {... ,name : value} که به نوع دیکشنری (Dictionary) معروف است استفاده می‌کند؛ صفت‌های هر شی و مقدار‌ آن‌ها نیز توسط چنین ساختاری نگهداری می‌شود که برای مشاهده این دیکشنری که در واقع همان فهرستی از صفت‌‌‌های هر شی به همراه مقدار آن‌هاست می‌توانید از صفت ویژه __dict__ استفاده نمایید. متد __setattr__ [اسناد پایتون] از متدهای ویژه است - این متدها امکانی هستند تا بتوانیم برای مواقعی خاص، رفتارهای مشخصی را تعریف نماییم - __setattr__ هر زمان که به یکی از صفت‌های شی‌ای از کلاس مقداری نسبت داده شود به صورت خودکار فراخوانی می‌گردد و وظیفه آن ذخیره صفت‌ها و مقدار آن‌ها در این دیکشنری است.

در اینجا رفتار متد __setattr__ کمی تغییر داده شده است به این صورت که بررسی می‌شود (سطر 9) چنانچه پیش از این صفت مورد نظر وجود نداشته باشد (یعنی: پیش از این هیچ مقداری به آن انتساب داده نشده است که بخواهد در فهرست باشد؛ تعریف متغیر را به یاد بیاورید) همراه با مقدار به فهرست صفت‌های شی افزوده خواهد شد (سطر 11)؛ در غیر این صورت یک خطا گزارش می‌گردد که موجب توقف اجرای متد شده و در نتیجه از درج جدید در فهرست که موجب تغییر مقدار صفت مورد نظر می‌گردد جلوگیری خواهد شد (سطر 10).

با ماژول‌ها هم در پایتون به صورت شی برخورد می‌شود، پس مفسر پایتون باید بداند کدام نام ماژول به کدام شی مربوط است؛ sys.modules یک دیکشنری حاوی تمام ماژول‌هایی است که در این لحظه از اجرای برنامه بارگذاری شده‌اند. [__sys.modules[__name به عضوی از این دیکشنری که نام آن __name__ است اشاره دارد. می‌دانیم که __name__ بیانگر نام ماژول جاری است؛ بنابراین عبارت [__sys.modules[__name معرف نامی است که به شی ماژول constant.py ارجاع دارد. دستور سطر 14 موجب می‌شود تا ارجاع این نام به ماژول حذف شود و در عوض به شی‌ای از کلاس const_ نسبت داده شود که این عمل موجب حذف شی ماژول از حافظه می‌گردد (چون که دیگر ارجاعی به آن وجود ندارد). از طرفی می‌دانیم که با import هر ماژول، تمام محتویان آن اجرا می گردد؛ با import ماژول constant.py و پس از اجرای کدهای آن به ويژه سطر 14 همانطور که گفته شده ماژول مربوطه حذف می‌شود ولی کدهای آن هنوز در بایت‌کد باقی است. بنابراین پس از import می‌توان به آسانی از نام ماژول که اکنون ارجاع به شی‌ای از کلاس const_ دارد برای ایجاد صفت‌ها که حکم ثابت‌های ما را دارند استفاده کرد. [تمام این مفاهیم در آینده به صورت کامل بررسی خواهد شد]

Tip

[PEP 8]: برای نام‌گذاری ثابت‌ها (Constants) تنها از حروف بزرگ و برای جداسازی کلمه‌ها نیز از ـ استفاده شود. مانند: MAX_OVERFLOW ،TOTAL و…

عملگر‌ها

«عملگر» (Operator) به نمادی گفته می‌شود که عمل مشخصی را بر روی اشیا به انجام می‌رساند؛ به مانند عملگر انتساب = که پیش از این بررسی شد. همچنین به اشیایی که عملگر‌ بر روی آن‌ها عملی را به انجام می‌رساند «عملوند» (Operand) گفته می‌شود. عملگرها دارای انواع مختلفی هستند که در ادامه بررسی خواهیم کرد.

۱. عملگرهای حسابی (Arithmetic Operators): + - * ** / // %

  • + جمع (Addition): مقدار عملوندهای دو طرف خود را با یکدیگر جمع می‌کند. 2 + 1 حاصل: 3

  • - تفریق (Subtraction): مقدار عملوند سمت راست را از مقدار عملوند سمت چپ خود منها می‌کند: 4 - 7 حاصل: 3

  • * ضرب (Multiplication): مقدار عملوندهای دو طرف خود را در یکدیگر ضرب می‌کند: 2 * 5 حاصل: 10

  • ** توان (Exponent): مقدار عملوند سمت چپ را به توان مقدار عملوند سمت راست خود می‌رساند. 3 ** 2 حاصل: 8

  • / تقسیم (Division): مقدار عملوند سمت چپ را بر مقدار عملوند سمت راست خود تقسیم می‌کند و خارج قسمت را برمی‌گرداند:

    >>> # Python 3.x              >>> # Python 2.x
    
    >>> 7 / 3                     >>> 7 / 3
    2.3333333333333335            2
    >>> 12 / 3                    >>> 12 / 3
    4.0                           4
    >>> 6.0 / 2                   >>> 6.0 / 2
    3.0                           3.0
    

    همانطور که در نمونه کد بالا مشاهده می‌‌شود؛ در نسخه‌های 3x حاصل هر تقسیمی همواره به صورت عدد اعشاری محاسبه می‌گردد ولی در نسخه‌های 2x حاصل تقسیم دو عدد صحیح به همان صورت عدد صحیح محاسبه و از مقدار اعشار (در صورت وجود) صرف نظر می‌گردد. می‌توان به صورت پایین این ویژگی را به نسخه‌های 2x اضافه کرد [اسناد پایتون]:

    >>> # Python 2.x
    >>> from __future__ import division
    >>> 7 / 3
    2.3333333333333335
    >>> 12 / 3
    4.0
    
  • // تقسیم گردشده پایین (Floor Division): مقدار عملوند سمت چپ را بر مقدار عملوند سمت راست خود تقسیم می‌کند و خارج قسمت را با حذف مقدار اعشاری (در صورت وجود) برمی‌گرداند. حاصل این عملگر برای اعداد صحیح به صورت یک عدد صحیح محاسبه می‌گردد، به نتایج نمونه کد پایین توجه نمایید:

    >>> # Python 3.x              >>> # Python 2.x
    
    >>> 7 // 3                    >>> 7 // 3
    2                             2
    >>> 12 // 3                   >>> 12 // 3
    4                             4
    >>> 6.0 // 2                  >>> 6.0 // 2
    3.0                           3.0
    >>> 7.0 // 3                  >>> 7.0 // 3
    2.0                           2.0
    
  • % باقی‌ مانده (Modulus): مقدار عملوند سمت چپ را بر مقدار عملوند سمت راست خود تقسیم می‌کند و باقی‌ مانده را برمی‌گرداند. 3 % 7 حاصل: 1

۲. عملگرهای مقایسه‌ (Comparison Operators): == =! <> < > =< =>

  • == برابر (Equal): چنانچه مقدار عملوندهای دو طرف برابر باشند، True را برمی‌گرداند. 1 == 3 : False
  • =! نابرابر (Not Equal): چنانچه مقدار عملوندهای دو طرف برابر نباشند، True را برمی‌گرداند. 1 =! 3 : True
  • <> نابرابر (Not Equal): عملکرد آن همانند =! است ولی فقط در نسخه 2x پایتون قابل استفاده است. 1 <> 3 : True
  • < بزرگتر از (Greater Than): چنانچه مقدار عملوند سمت چپ بزرگتر از مقدار عملوند سمت راست آن باشد، True را برمی‌گرداند. 5 < 3 : False
  • > کوچکتر از (Less Than): چنانچه مقدار عملوند سمت چپ کوچکتر از مقدار عملوند سمت راست آن باشد، True را برمی‌گرداند. 5 > 3 : True
  • =< برابر یا بزرگتر از (Greater Than or Equal): چنانچه مقدار عملوند سمت چپ برابر یا بزرگتر از مقدار عملوند سمت راست آن باشد، True را برمی‌گرداند. 5 =< 7 : True
  • => برابر یا کوچکتر از (Less Than or Equal): چنانچه مقدار عملوند سمت چپ برابر یا کوچکتر از مقدار عملوند سمت راست آن باشد، True را برمی‌گرداند. 5 => 7 : False

۳. عملگرهای انتساب (Assignment Operators):

  • = عملوند سمت راست را به عملوند سمت چپ خود نسبت می‌دهد. چنانچه یک عبارت محاسباتی در سمت راست باشد، حاصل آن را به عملوند سمت چپ نسبت می‌دهد:

    >>> a = 3
    
    >>> b = 2
    
    >>> c = a + b
    >>> c
    5
    
  • =+ =- =* =** =/ =// =% عملگرهای ترکیبی (انتساب حسابی): این عملگرها ابتدا عمل مربوط به عملگر حسابی را بر روی مقدار عملوندهای دو طرف خود به انجام می‌رسانند و سپس حاصل را به عملوند سمت چپ نسبت می‌دهند:

    >>> a += b
    >>> a
    5
    
    >>> a -= b
    >>> a
    1
    
    >>> a *= b
    >>> a
    6
    
    >>> a **= b
    >>> a
    9
    
    >>> # Python 3.x                  >>> # Python 2.x
    >>> a /= b                        >>> a /= b
    >>> a                             >>> a
    1.5                               1
    

۴. عملگرهای بیتی (Bitwise Operators): & | ^ ~ >> <<

این دسته از عملگرها، عمل مشخصی را بر روی تک تک بیت‌های عملوند‌(ها) انجام می‌دهند. در پایتون برای استفاده از این عملگرها لزومی به تبدیل اعداد به پایه دو (دودویی یا باینری Binary) وجود ندارد ولی در اینجا برای مشاهده بهتر عملکرد آن‌ها از اعداد دودویی استفاده کرده‌ایم. در زبان پایتون اعداد پایه دو همواره می‌بایست با یک 0b شروع شوند:

>>> a = 0b0011
>>> a
3
>>> b = 0b0010
>>> b
2

از تابع ()bin می‌توان برای به دست آوردن مقدار دودویی یک عدد ده‌دهی استفاده کرد؛ البته توجه داشته باشید که این تابع مقدار دودویی را در قالب متنی (نوع String) بر می‌گرداند - نکته دیگر اینکه در حالت تعاملی پایتون با وارد کردن اعداد دودویی، خروجی ده‌دهی به دست می‌آید:

>>> bin(10)
'0b1010'

>>> type(bin(10))
<class 'str'>

>>> 0b1010
10
  • &: معادل AND بیتی است - تنها بیت‌هایی از خروجی آن 1 خواهند بود که هر دو بیت متناظر از عملوندهای آن 1 باشند:

    >>> a & b                  0000 0011
    2                          0000 0010
                        (AND) -----------
                               0000 0010  = 2
    
  • |: معادل OR بیتی است - تنها بیت‌هایی از خروجی آن 0 خواهند بود که هر دو بیت متناظر از عملوندهای آن 0 باشند:

    >>> a | b                  0000 0011
    3                          0000 0010
                         (OR) -----------
                               0000 0011  = 3
    
  • ^: معادل XOR بیتی است - تنها بیت‌هایی از خروجی آن 1 خواهند بود که هر دو بیت متناظر از عملوندهای آن مخالف یکدیگر باشند:

    >>> a ^ b                  0000 0011
    1                          0000 0010
                        (XOR) -----------
                               0000 0001  = 1
    
  • ~ معادل NOT بیتی و تک عملوندی است - هر یک از بیت‌های عملوند خود را از 0 به 1 و برعکس تبدیل می‌کند:

    >>> ~ a                    0000 0011
    -4                  (NOT) -----------
                               1111 1100
    

    یک شیوه برای نمایش اعداد علامت دار دودویی، همین عمل یعنی برعکس کردن بیت‌ها (0 به 1 و 1 به 0) است که به آن نمایش «مکمل یک» (One’s Complement) اعداد دودویی گفته می‌شود. ولی مفسر پایتون به صورت پیش‌فرض اعداد علامت دار را به شیوه رایج‌تر دیگری ارزیابی می‌کند که به نام نمایش «مکمل دو» (Two’s Complement) شناخته می‌شود؛ در این روش پس از برعکس شدن بیت‌ها، حاصل با عدد 1 جمع می‌شود. بنابراین در نمونه کد بالا حاصل NOT عدد a برابر 11111100 می‌شود که نمایش عدد 4 - در پایه دو به شیوه مکمل دو است:

    n = 3                       0000 0011
    3 = 0000 0011        (NOT) -----------
                                1111 1100  = -3 (in One’s Complement)
                                           = -4 (in Two’s Complement)
    
    Two’s Complement
    
    n = 4                       0000 0100
    4 = 0000 0100        (NOT) -----------
                                1111 1011
                                        1
                         ( + ) -----------
                                1111 1100  = -4
    

    می‌توان مقدار a ~ را برابر حاصل عبارت 1 - a- در نظر گرفت. بنابراین:

    >>> ~ a + 1
    -3
    
  • >> شیفت چپ (Left Shift): بیت‌های عملوند سمت چپ را به مقدار عملوند سمت راست خود به سمت چپ جابه‌جا می‌کند - مکان‌های رد شده با صفر مقداردهی می‌شوند:

    >>> a << 3                  0000 0011
    24                   (LSH) -----------
                                0001 1000  = 24
    
  • << شیفت راست (Right Shift): بیت‌های عملوند سمت چپ را به مقدار عملوند سمت راست خود به سمت راست جابه‌جا می‌کند - مکان‌های رد شده با صفر مقداردهی می‌شوند:

    >>> a = 88                  0101 1000
    >>> a >> 3           (RSH) -----------
    11                          0000 1011  = 11
    
  • =& =| =^ =>> =<< عملگرهای ترکیبی (انتساب بیتی): این عملگرها ابتدا عمل مربوط به عملگر بیتی را بر روی عملوندهای دو طرف خود به انجام می‌رسانند و سپس حاصل را به عملوند سمت چپ نسبت می‌دهند.

۵. عملگرهای منطقی (Logical Operators):

این عملگرها عبارتند از not or and که در دستورات شرطی کاربرد دارند. عملگرهای منطقی عملوند‌های خود را بر اساس ارزش‌‌های True (درست) و False (نادرست) مورد ارزیابی قرار می‌دهند و نتایج خود را بر اساس جدول پایین برمی‌گردانند. عملگر not تک عملوندی است.

a b a and b a or b not a not b
True False False True False True
False True False True True False
False False False False True True
True True True True False False

عملگر and تنها زمانی که هر دو عملوند آن ارزش True داشته باشند، True را بر می‌گرداند. عملگر or تنها زمانی که هر دو عملوند آن ارزش False داشته باشند، False را برمی‌گرداند. عملگر not نیز ارزش عملود خود را برعکس می‌کند (True به False و False به True).

۶. عملگرهای عضویت (Membership Operators):

شامل دو عملگر in و not in می‌باشد که از آن‌ها برای بررسی وجود یک مقدار در میان اعضای یک دنباله (sequence مانند: رشته، لیست و…) استفاده می‌شود.

  • in: اگر مقدار عملوند سمت چپ خود را در عملوند سمت راست بیابد، True و در غیر این صورت False را بر می‌گرداند.
  • not in: اگر مقدار عملوند سمت چپ خود را در عملوند سمت راست نیابد، True و در غیر این صورت False را بر می‌گرداند.
>>> "py" in "python"
True
>>> 1 in [1, 2, 3]
True
>>> "s" not in "python"
True
>>> 3 not in [1, 2, 3]
False

۷. عملگرهای هویت (Identity Operators):

شامل دو عملگر is و is not است که از آن‌ها برای بررسی یکی بودن دو شی استفاده می‌شود.

  • is: اگر هر دو عملوند به یک شی ارجاع داشته باشند، True و در غیر این صورت False را بر می‌گرداند.
  • is not: اگر هر دو عملوند به یک شی ارجاع نداشته باشند، True و در غیر این صورت False را بر می‌گرداند.
>>> a = 3

>>> a is 3
True

اولویت‌ها

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
( )               # پرانتز
**
~
-       +         # منفی و مثبت
*       /       //      %
-       +         # بعلاوه و منها
<<      >>
&       ^       |
==      !=      <>
<       <=      >       >=
=       **=     /=      //=      %=      *=      -=      +=
is      is not
in      in not
not     and     or

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

>>> # Python 3.x

>>> 4 + 2 - 3 + 2 * 5
13
>>> 4 + ((2 - 3) + 2) * 5
9
>>> 9 / 3 * 2
6.0
>>> 3 * 2 / 9
0.6666666666666666
>>> (5 - 3) ** (7 - 3)
16
>>> 4 + 3 ** 2 - 9 / 3 * 3
4.0
>>> 4 * 2 == 5 + 3
True


😊 امیدوارم مفید بوده باشه

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

درس ۰۷: انواع آماده شی - بخش یکم

پایتون هر «نوع داده» (Data Type) را توسط یک کلاس ارایه می‌دهد؛ بنابراین هر داده یک نمونه یا یک شی از کلاسی مشخص است. هر چند برنامه‌نویس نیز می‌تواند با تعریف کلاس، نوع دلخواه خود را داشته باشد ولی در این درس می‌خواهیم درباره آن بخشی از انواع داده یا انواع شی‌ای که به شکل آماده (Built-in) در اختیار مفسر زبان پایتون قرار داده شده است صحبت کنیم.

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

سطح: مقدماتی



انواع عددی

در زبان پایتون دسته‌ای از انواع شی وجود دارد که برای کار با داده‌های عددی ایجاد گشته‌اند؛ از این جهت به عنوان «انواع عددی» (Numeric Types) شناخته می‌شوند. این انواع شی عبارتند از:

  • صحیح (Integer)
  • ممیز شناور (Floating-Point)
  • مختلط (Complex)
  • دسیمال (Decimal)
  • کسر (Fraction)
  • بولی (Boolean)

در ادامه به بررسی هر یک خواهیم پرداخت.

صحیح

این نوع از اشیا تمام اعداد مثبت و منفی بدون «ممیز اعشار» را شامل می‌شوند؛ مانند: 1234، 26- و…

ارایه نوع عدد صحیح از موارد اختلاف در نسخه‌های 2x و 3x می‌باشد.

در نسخه‌های 2x اعداد صحیح در قالب دو نوع int (با محدودیت اندازه) و long (بدون محدودیت اندازه) بیان می‌شوند:

>>> a = 3           # Python 2.x
>>> type(a)
<type 'int'>

>>> b = 3L
>>> type(b)
<type 'long'>

به این صورت که اگر عدد صحیحی با حرف L (اِل بزرگ) یا l (اِل کوچک) پایان یابد؛ به صورت نوع long در نظر گرفته خواهد شد. البته توجه داشته باشید چنانچه در نوع int سرریز (Overflow) رخ دهد؛ خطایی به وجود نخواهد آمد و پایتون به صورت خودکار شی نوع int را به شی‌ای از نوع long تبدیل (Convert) خواهد کرد.

بیشینه و کمینه مقدار یک شی از نوع int به ترتیب با استفاده از sys.maxint و sys.maxint - 1 - قابل دریافت است که می‌توانید این مقادیر را در یک نمونه کامپیوتر با معماری ۶۴ بیتی به صورت پایین مشاهده نمایید:

>>> import sys            # Python 2.x

>>> sys.maxint
9223372036854775807
>>> type(_)               # _ is result of the last executed statement  => 9223372036854775807
<type 'int'>

>>> - sys.maxint - 1
-9223372036854775808

>>> type(sys.maxint + 1)
<type 'long'>

در نسخه‌های 3x اعداد صحیح تنها در قالب یک نوع int (بدون محدودیت اندازه) ارایه می‌گردد و باید توجه داشت که استفاده از حرف L (یا l) در پایان اعداد صحیح مجاز نمی‌باشد:

>>> a = 3                   # Python 3.x
>>> type(a)
<class 'int'>

>>> b = 3L
  File "<stdin>", line 1
    b = 3L
         ^
SyntaxError: invalid syntax
>>>

در این نسخه‌ها sys.maxint حذف شده است ولی می‌توان به جای آن از sys.maxsize استفاده کرد که مقدار آن در نمونه کامپیوتر پیش برابر پایین است:

>>> import sys              # Python 3.x

>>> sys.maxsize
9223372036854775807
>>> type(_)
<class 'int'>

>>> type(sys.maxsize + 1)
<class 'int'>

Note

منظور از اندازه نامحدود اعداد این است که اندازه این اشیا تنها محدود به میزان حافظه‌ (Memory) آزاد بوده و تا هر اندازه‌ای که حافظه در دسترس باشد می‌توانند در محاسبات رشد داشته باشند.

در هر دو شاخه از پایتون؛ اعداد صحیح را می‌توان علاوه بر پایه ده؛ در پایه دو (Binary)، پایه هشت (Octal) و پایه شانزده (Hexadecimal) نیز در نظر گرفت. به این صورت که:

  • اعداد پایه دو می‌بایست با یک 0b یا 0B (صفر و حرف بی کوچک یا بزرگ) آغاز گردند؛ مانند: 0b11 که برابر عدد 3 در پایه ده است:

    >>> a = 0b11
    >>> type(a)
    <class 'int'>
    >>> a
    3
    
  • اعداد پایه هشت می‌بایست با یک 0o یا 0O (صفر و حرف اُ کوچک یا بزرگ) آغاز گردند؛ مانند: 0o14 که برابر عدد 12 در پایه ده است:

    >>> a = 0o14
    >>> type(a)
    <class 'int'>
    >>> a
    12
    

    همچنین در نسخه‌های 2x برای مشخص کردن عددی در این پایه می‌توان به جای 0o یا 0O، تنها از یک صفر 0 استفاده کرد:

    >>> 0o14    # Python 3.x and Python 2.x
    12
    
    >>> 014     # Python 2.x
    12
    
  • اعداد پایه شانزده می‌بایست با یک 0x یا 0X (صفر و حرف اِکس کوچک یا بزرگ) آغاز گردند؛ مانند: 0xA5 که برابر عدد 165 در پایه ده است:

    >>> a = 0xA5
    >>> type(a)
    <class 'int'>
    >>> a
    165
    >>> print(a)
    165
    

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

برای تبدیل یک عدد صحیح در پایه ده به هر یک از این پایه‌ها می‌توانید از تابع‌های آماده ()bin [اسناد پایتون] برای تبدیل به پایه دو، ()oct [اسناد پایتون] برای تبدیل به پایه هشت و ()hex [اسناد پایتون] برای تبدیل به پایه شانزده استفاده نمایید. تنها توجه داشته باشید که خروجی هر یک از این تابع‌ها به صورت یک شی از نوع رشته یا String برگردانده می‌شود و نه یک نوع عددی:

>>> a = 3
>>> b = bin(a)
>>> b
'0b11'
>>> type(b)
<class 'str'>

>>> a = 12
>>> b = oct(a)
>>> b
'0o14'
>>> type(b)
<class 'str'>

>>> a = 165
>>> b = hex(a)
>>> b
'0xa5'
>>> type(b)
<class 'str'>

و برای برگرداندن پایه اعداد صحیح به پایه ده می‌توان از کلاس ()int [اسناد پایتون] استفاده کرد. آرگومان‌های نمونه این کلاس به صورت (int(str, base می‌باشد؛ آرگومان یکم: str می‌بایست یک «رشته عددی» یعنی یک عدد صحیح (در هر پایه‌ای) داخل نمادهای نقل قول (Quotation) باشد که آرگومان دوم، پایه (Base) آن را مشخص می‌کند. در نهایت این کلاس یک شی int متناظر با آرگومان یکم ولی در پایه ده را برمی‌گرداند:

>>> a = 165

>>> type(a)
<class 'int'>

>>> b = hex(a)          # Converted to hexadecimal
>>> b
'0xa5'

>>> type(b)
<class 'str'>

>>> int(b, 16)           # str='0xa5' base=16
165

>>> type(int(b, 16))
<class 'int'>

توجه داشته باشید که می‌توان اعداد را بدون حرف مشخص کننده پایه (0x 0o 0b) به این کلاس ارسال کنیم. همچنین از این کلاس می‌توان برای تبدیل نوع رشته‌های عددی در پایه ده به عدد صحیح استفاده کرد. مقدار پیش‌فرض آرگومان پایه 10 است؛ بنابراین در هنگام ارسال اعداد در این پایه، نیازی به ذکر پایه 10 نمی‌باشد:

>>> int("A5", 16)    # 0xA5
165
>>> a = "56"
>>> int(a, 10)
56
>>> int(a)
56
>>> int()
0

()int بدون آرگومان یک شی صفر از نوع صحیح را برمی‌گرداند.

Note

منظور از «رشته عددی»، رشته‌ای است که به گونه‌ای بتوان آن را به یک عدد ارزیابی نمود. مانند: "25"، "0x2F" و… که بدیهی است قرار دادن رشته‌هایی همچون "0w55" و… - که به هیچ شکلی نمی‌توان آن‌ها را به عددی در پایتون ارزیابی نمود - در آرگومان ()int موجب بروز خطا می‌گردد.

با تفاوت شیوه ارایه نوع اعداد صحیح در بین نسخه‌های 2x و 3x پایتون آشنا شده‌ایم. فقط باید توجه داشت که در نسخه‌های 2x پایتون؛ کلاس ()int [اسناد پایتون] یک شی از نوع int را برمی‌گرداند و برای ایجاد اشیایی از نوع long کلاس مشابه دیگری با نام ()long [اسناد پایتون] در دسترس است:

>>> a = 25     # Python 2.x

>>> int(a)
25

>>> long(a)
25L

در هر دو شاخه از پایتون؛ اعداد در پایه ده را می‌توان با نوع عددی - نه به شکل رشته عددی - نیز به تابع ()int (یا ()long) ارسال نمود.

برای به دست آوردن اندازه یا میزان حافظه گرفته شده توسط یک شی به واحد بایت (Byte) می‌توان از تابع ()getsizeof [اسناد پایتون] درون ماژول sys استفاده نماییم - خروجی این تابع برای دو شی صحیح دلخواه در یک نمونه کامپیوتر ۶۴ بیتی به صورت پایین است:

>>> import sys                # Python 3.x
>>> a = 1
>>> sys.getsizeof(a)
28
>>> sys.getsizeof(10**100)
72
>>> import sys                # Python 2.x
>>> a = 1
>>> sys.getsizeof(a)
24
>>> sys.getsizeof(10**100)
72

ممیز شناور

تمام اعداد مثبت و منفی که شامل یک «ممیز اعشار» هستند در پایتون به صورت اشیایی با نوع float (معادل نوع double در زبان C) ارایه می‌شوند؛ مانند: 3.1415، .5 (برابر 5.0) و…

>>> a = 3.1415
>>> type(a)
<class 'float'>

>>> import sys
>>> sys.getsizeof(a)
24

جزییات این نوع با استفاده از sys.float_info [اسناد پایتون] قابل مشاهده است:

>>> import sys
>>> sys.float_info
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)

گاهی برای نمایش اعداد از شیوه «نماد علمی» (Scientific Notation) استفاده می‌شود؛ در پایتون هم می‌توان از حرف E یا e که معادل «ضرب در ۱۰ به توانِ» می‌باشد، برای این منظور استفاده کرد.

برای نمونه: عبارت 4 × 105، به شکل 4E5 یا 4e5 بیان می‌شود. پایتون این نوع اعداد را نیز در قالب اعداد ممیز شناور (اشیایی از نوع float) ارايه می‌دهد:
>>> 3e2
300.0

>>> type(3e2)
<class 'float'>

>>> 3e-2
0.03

>>> 3e+2
300.0

می‌توان از کلاس ()float [اسناد پایتون] برای تبدیل اعداد یا رشته‌های عددی به یک شی ممیز شناور استفاده کرد:

>>> a = 920

>>> type(a)
<class 'int'>

>>> float(a)
920.0

>>> type(float(a))
<class 'float'>

>>> float("920")
920.0

>>> float("3e+2")
300.0
>>> float()
0.0

()float بدون آرگومان یک شی صفر از نوع ممیز شناور را برمی‌گرداند.

چنانچه عددی از نوع ممیز شناور در آرگومان کلاس ()int قرار بگیرد؛ تنها بخش صحیح عدد برگردانده می‌شود:

>>> a = 2.31
>>> type(a)
<class 'float'>

>>> int(a)
2
>>> type(int(a))
<class 'int'>

>>> int(3.9)
3

با استفاده از کلاس ()float می‌توانیم اشیایی با مقدارهای مثبت و منفی «بی‌نهایت» (infinity) برابر: inf یا infinity و «تعریف نشده» (Not a Number) برابر: NaN ایجاد نماییم - چگونگی کوچک یا بزرگ نوشتن حروف این کلمه‌ها تفاوتی در آن‌ها ایجاد نمی‌کند:

>>> a = float('infinity')
>>> a = float('inf')
>>> a
inf

>>> b = float('-infinity')
>>> b = float('-inf')
>>> b
-inf

>>> c = float('NaN')
>>> c
nan
>>> a = float('inf')

>>> 5 / a
0.0

>>> a / a
nan
>>> a = float('inf')
>>> b = float('inf')
>>> a == b
True

>>> a = float('nan')
>>> b = float('nan')
>>> a == b
False

دو شی NaN با یکدیگر برابر نیستند.

برای بررسی اینکه مقدار یک شی «بی‌نهایت» یا «تعریف نشده» است؛ می‌توان به ترتیب از تابع‌های ()isinf [اسناد پایتون] و ()isnan [اسناد پایتون] درون ماژول math استفاده نماییم:

>>> a = float('inf')
>>> b = float('nan')

>>> import math

>>> math.isinf(a)
True
>>> math.isnan(b)
True

مختلط

همانطور که می‌دانیم اعداد مختلط (Complex Numbers) از یک بخش حقیقی (Real) و یک بخش موهومی (Imaginary) تشکیل شده‌اند. این اعداد در پایتون الگویی برابر RealPart + ImaginaryPart j دارند که حرف j نشانگر «واحد موهومی» است. این اعداد در پایتون توسط اشیایی با نوع complex ارایه می‌شوند:

>>> a = 3 + 4j
>>> type(a)
<class 'complex'>

>>> import sys
>>> sys.getsizeof(a)
32

از کلاس ()complex [اسناد پایتون] می‌توان برای ایجاد یک شی complex استفاده کرد. این کلاس الگویی مشابه (complex(real, imag دارد؛ آرگومان‌های نمونه real و imag بیانگر اعدادی هستند که به ترتیب قرار است در بخش‌های حقیقی و موهومی عدد مختلط مورد نظر وجود داشته باشند. اگر هر کدام از آرگومان‌ها ارسال نگردند به صورت پیش‌فرض صفر در نظر گرفته خواهند شد:

>>> a = 3
>>> b = 4

>>> type(a)
<class 'int'>
>>> type(b)
<class 'int'>

>>> complex(a, b)
(3+4j)

>>> type(complex(a, b))
<class 'complex'>
>>> complex(3, 4)
(3+4j)

>>> complex(3)
(3+0j)

>>> complex(0, 4)
4j

>>> complex(4j)
4j
>>> a = 3 + 4j
>>> a
(3+4j)

>>> a = 3.2 + 4j
>>> a
(3.2+4j)

>>> a = 3.0 + 4j
>>> a
(3+4j)

>>> a = 3.0 + 4.0j
>>> a
(3+4j)

همچنین با استفاده از دو صفت real و imag می‌توان بخش‌های حقیقی و موهومی هر شی complex را به دست آورد. توجه داشته باشید که جدا از این که اعداد از چه نوعی در تشکیل یک نوع مختلط شرکت کرده باشند؛ بخش‌های عدد مختلط به صورت عدد ممیز شناور تفکیک می‌گردند:

>>> a = 3 + 4j

>>> a.real
3.0
>>> a.imag
4.0

()complex توانایی دریافت یک رشته عددی و تبدیل آن به عدد مختلط را نیز دارد. تنها باید توجه داشت که نباید داخل این رشته هیچ فضای خالی وجود داشته باشد:

>>> a = "3+4j"

>>> type(a)
<class 'str'>

>>> complex(a)
(3+4j)

>>> a = "3"
>>> complex(a)
(3+0j)

>>> type(complex(a))
<class 'complex'>
>>> a = "3 + 4j"
>>> complex(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: complex() arg is a malformed string
>>>

Note

امکان قرار دادن رشته عددی (مختلط) یا خود شی عدد مختلط در آرگومان کلاس‌های ()int (یا ()long) و ()float وجود ندارد و موجب بروز خطا می‌شود.

دسیمال

اساس طراحی این نوع برای استفاده در مواقعی است که خطا نوع ممیز شناور قابل گذشت نیست [PEP 327] مانند توسعه برنامه حسابداری. مفسر پایتون برای ارایه نوع ممیز شناور به کامپیوتر از کدگذاری Binary Floating-Point (استاندارد IEEE 754) استفاده می‌کند. این کدگذاری اعداد در پایه ده که مورد نظر کاربر هستند را - مانند 0.1 - به شکل دقیق ارایه نمی‌دهد؛ به عنوان نمونه عدد 0.1 برابر با عددی نزدیک به 0.10000000000000001 در محاسبات کامپیوتر شرکت داده می‌شود؛ هر چند که این عدد بسیار نزدیک به 0.1 است ولی به هر حال خود آن نیست!. این موضوع ممکن است در برخی موارد موجب خطا منطقی در برنامه گردد:

>>> a = 0.1 + 0.1 + 0.1
>>> a == 0.3
False
>>> a
0.30000000000000004

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

در پایتون نوع دسیمال با ایجاد شی از کلاس Decimal درون ماژول decimal در دسترس قرار گرفته است [اسناد پایتون]. به نمونه کد پایین توجه نمایید:

>>> import decimal

>>> a = decimal.Decimal('0.1')
>>> b = decimal.Decimal('0.3')

>>> b == a + a + a
True

>>> type(a)
<class 'decimal.Decimal'>

>>> a
Decimal('0.1')

>>> print(a)
0.1

>>> import sys
>>> sys.getsizeof(a)
104

به شیوه‌های گوناگونی می‌توان شی دسیمال ایجاد کرد:

1
2
3
4
5
6
a = decimal.Decimal(23)                  # Creates Decimal("23")
b = decimal.Decimal("23.45")             # Creates Decimal("23.45")
c = decimal.Decimal("2345e-2")           # Creates Decimal("23.45")
d = decimal.Decimal((1,(2,3,4,5),-2))    # Creates Decimal("-23.45")
e = decimal.Decimal("infinity")
f = decimal.Decimal("NaN")
  • از آنجا که نوع ممیز شناور دقیق نیست؛ این اعداد را حتما به صورت رشته به Decimal ارسال نمایید (سطر دوم).
  • اعداد را می‌توان به صورت یک شی تاپل (Tuple) - ساختاری مشابه: (… ,Ο, Ο, Ο) - ارسال کرد (سطر چهارم). شیوه نماد علمی را به یاد بیاورید؛ تاپل مورد نظر باید ساختاری مشابه الگو (sign, digits, exponent) داشته باشد که در آن sign مثبت بودن (توسط عدد صفر) یا منفی بودن (توسط عدد یک) را مشخص می‌کند، digits خود تاپلی است که رقم‌های دخیل را بیان می‌کند و exponent نیز بیانگر همان توان است.

میزان دقت (Precision) و عمل گرد کردن (Rounding) اعداد از نوع دسیمال با استفاده از یک شی Context قابل کنترل است؛ این شی یک سری اطلاعات پیکربندی را در اختیار اشیا دسیمال قرار می‌دهد که برای دسترسی به آن باید از تابع ()getcontext [اسناد پایتون] درون ماژول decimal استفاده کرد. تابع ()getcontext شی Context اشیا دسیمال جاری برنامه را برمی‌گرداند. در برنامه‌نویسی چندنخی (Multithreading) هر نخ (thread) شی Context خاص خود را دارد؛ بنابراین این تابع شی Context مربوط به نخ فعال را برمی‌گرداند:

>>> import decimal

>>> a = decimal.Decimal('3.45623')
>>> b = decimal.Decimal('0.12')

>>> a + b
Decimal('3.57623')

>>> print(a + b)
3.57623

>>> ctx = decimal.getcontext()
>>> type(ctx)
<class 'decimal.Context'>

>>> ctx.prec = 1
>>> a + b
Decimal('4')

>>> ctx.prec = 2
>>> a + b
Decimal('3.6')

>>> ctx.prec = 3
>>> a + b
Decimal('3.58')

همانطور که در نمونه کد بالا مشاهده می‌شود دقت محاسبات اعداد دسیمال را می‌توان با استفاده از صفت prec شی Context به شکل دلخواه تنظیم نمود؛ مقدار پیش‌فرض این صفت 28 است. بدیهی است برای اینکه اعداد در محدوده دقت کوچکتری نسبت به طول خود قرار بگیرند نیاز به گرد شدن دارند؛ برای تنطیم عمل گرد کردن در اعداد دسیمال نیز از صفت rounding که مقدار پیش‌فرض آن "ROUND_HALF_EVEN" است، استفاده می‌شود:

>>> a = decimal.Decimal('2.0')
>>> b = decimal.Decimal('0.52')

>>> ctx.prec
28
>>> ctx.rounding
'ROUND_HALF_EVEN'

>>> print(a + b)
2.52

>>> ctx.prec = 2

>>> print(a + b)
2.5

>>> ctx.rounding = "ROUND_CEILING"

>>> print(a + b)
2.6

صفت rounding می‌بایست حاوی مقادیر ثابتی به شرح پایین باشد:

  • ROUND_CEILING - گرد کردن به سمت مثبت بی‌نهایت: یعنی برای اعداد مثبت ارقام خارج از محدوده حذف می‌گردند و آخرین رقم باقی مانده یک واحد افزایش می‌یابد مثلا عدد 2.52 به 2.6 گرد می‌شود. برای اعداد منفی نیز تنها اعداد خارج از محدوده حذف می‌گردند مثلا عدد 2.19- به 2.1- گرد می‌شود.
  • ROUND_FLOOR - گرد کردن به سمت منفی بی‌نهایت: یعنی برای اعداد منفی ارقام خارج از محدوده حذف می‌گردند و آخرین رقم باقی مانده یک واحد افزایش می‌یابد مثلا عدد 2.52- به 2.6- گرد می‌شود. برای اعداد مثبت نیز تنها اعداد خارج از محدوده حذف می‌گردند مثلا عدد 2.19 به 2.1 گرد می‌شود.
  • ROUND_DOWN - گرد کردن به سمت صفر: یعنی برای اعداد مثبت و منفی تنها ارقام خارج از محدوده حذف می‌گردند مثلا عدد 2.58 به 2.5 و عدد 2.58- به 2.5- گرد می‌شود.
  • ROUND_UP - گرد کردن به دور از صفر: یعنی برای اعداد مثبت و منفی ارقام خارج از محدوده حذف می‌گردند و آخرین رقم باقی مانده یک واحد افزایش می‌یابد مثلا عدد 2.52 به 2.6 و عدد 2.52- به 2.6- گرد می‌شود.
  • ROUND_HALF_DOWN - اگر رقم ابتدایی بخش حذف شده بزرگتر از 5 باشد به روش ROUND_UP و در غیر این صورت به روش ROUND_DOWN گرد می‌گردد. مثلا عدد 2.58 به 2.6 و عدد 2.55 به 2.5 گرد شده و همینطور عدد 2.58- به 2.6- و عدد 2.55- به 2.5- گرد می‌شود.
  • ROUND_HALF_UP - اگر رقم ابتدایی بخش حذف شده بزرگتر یا برابر 5 باشد به روش ROUND_UP و در غیر این صورت به روش ROUND_DOWN گرد می‌گردد. مثلا عدد 2.55 به 2.6 و عدد 2.51 به 2.5 گرد شده - همینطور عدد 2.55- به 2.6- و عدد 2.51- به 2.5- گرد می‌کند.
  • ROUND_HALF_EVEN - همانند ROUND_HALF_DOWN است ولی در مواقعی که رقم ابتدایی بخش حذف شده برابر 5 باشد رفتار آن متفاوت می‌شود: در این حالت اگر آخرین رقم باقی مانده زوج باشد به شیوه ROUND_DOWN و اگر فرد باشد به روش ROUND_UP گرد می‌گردد. مثلا عدد 2.68 به 2.7، 2.65 به 2.6 و 2.75 به 2.8 - همینطور عدد 2.68- به 2.7-، 2.65- به 2.6- و 2.75- به 2.8- گرد می‌کند.
  • ROUND_05UP - اگر بر اساس روش ROUND_DOWN آخرین رقم باقی مانده 0 یا 5 باشد؛ به روش ROUND_UP و در غیر این صورت به همان شیوه ROUND_DOWN گرد می‌کند. مثلا عدد 2.58 به 2.6 و 2.48 به 2.4 - همینطور عدد 2.58- به 2.6- و 2.48- به 2.4- گرد می‌شود.

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

کسر

این نوع برای پشتیبانی اعداد گویا (Rational) در پایتون ارایه شده است و با ایجاد شی از کلاس Fraction درون ماژول fractions در دسترس قرار می‌گیرد [اسناد پایتون]:

>>> import fractions

>>> a = 1
>>> b = 2
>>> f = fractions.Fraction(a, b)

>>> f
Fraction(1, 2)

>>> print(f)
1/2

>>> type(f)
<class 'fractions.Fraction'>

>>> import sys
>>> sys.getsizeof(f)
56

علاوه‌بر روش بالا که به صورت مستقیم صورت و مخرج کسر - از نوع صحیح - مشخص شده است؛ به روش‌های دیگری نیز می‌توان یک شی کسری ایجاد نمود:

  • از یک شی ممیز شناور - بهتر است این نوع به صورت رشته وارد شود:

    >>> print(fractions.Fraction('0.5'))
    1/2
    >>> print(fractions.Fraction('1.1'))
    11/10
    >>> print(fractions.Fraction('1.5'))
    3/2
    >>> print(fractions.Fraction('2.0'))
    2
    
    >>> print(fractions.Fraction(0.5))
    Fraction(1, 2)
    
    >>> print(fractions.Fraction(1.1))
    2476979795053773/2251799813685248
    >>> 2476979795053773 / 2251799813685248
    1.1
    
    >>> print(fractions.Fraction(1.5))
    3/2
    

    متد ()limit_denominator می‌تواند یک شی ممیز شناور را با محدود کردن مخرج در یک مقدار بیشینه به صورت تقریبی به یک شی کسر تبدیل نماید:

    >>> fractions.Fraction(1.1).limit_denominator()
    Fraction(11, 10)
    
    >>> import math
    >>> math.pi
    3.141592653589793
    >>> pi = math.pi
    >>> fractions.Fraction(pi)
    Fraction(884279719003555, 281474976710656)
    >>> 884279719003555 / 281474976710656
    3.141592653589793
    
    >>> fractions.Fraction(pi).limit_denominator()
    Fraction(3126535, 995207)
    >>> 3126535 / 995207
    3.1415926535886505
    
    >>> fractions.Fraction(pi).limit_denominator(8)
    Fraction(22, 7)
    >>> 22 / 7
    3.142857142857143
    
    >>> fractions.Fraction(pi).limit_denominator(60)
    Fraction(179, 57)
    >>> 179 / 57
    3.1403508771929824
    
  • از یک شی دسیمال:

    >>> print(fractions.Fraction(decimal.Decimal('1.1')))
    11/10
    
  • از یک رشته کسری - صورت و مخرج کسر می‌بایست از نوع صحیح باشند:

    >>> print(fractions.Fraction('3/14'))
    3/14
    
  • از یک شی کسر دیگر:

    >>> f1 = fractions.Fraction(1, 2)
    >>> f2 = fractions.Fraction(3, 5)
    >>> fractions.Fraction(f1)
    Fraction(1, 2)
    >>> fractions.Fraction(f1, f2)
    Fraction(5, 6)
    

با استفاده از دو صفت numerator و denominator می‌توان به ترتیب به صورت و مخرج شی کسر دسترسی یافت:

>>> f = fractions.Fraction('1.5')
>>> f.numerator
3
>>> f.denominator
2

از این نوع شی به سادگی می توان در انواع محاسبات ریاضی استفاده کرد؛ برای نمونه به تکه کد پایین توجه نمایید:

>>> fractions.Fraction(1, 2) + fractions.Fraction(3, 4)
Fraction(5, 4)

>>> fractions.Fraction(5, 16) - fractions.Fraction(1, 4)
Fraction(1, 16)

>>> fractions.Fraction(3, 5) * fractions.Fraction(1, 2)
Fraction(3, 10)

>>> fractions.Fraction(3, 16) / fractions.Fraction(1, 8)
Fraction(3, 2)

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

>>> fractions.Fraction(5, 2) + 3
Fraction(11, 2)
>>> fractions.Fraction(5, 2) + 3.0
5.5

ب.م.م

ماژول fractions علاوه بر نوع کسری؛ حاوی تابع ()gcd [اسناد پایتون] نیز است. این تابع «بزرگترین مقسوم‌علیه مشترک» (GCD) دو عدد را برمی‌گرداند:

>>> import fractions
>>> fractions.gcd(54, 24)
6

بولی

کلاسی که در پایتون از آن برای ایجاد شی بولی استفاده می‌شود (bool) در واقع یک کلاس فرزند از کلاس اعداد صحیح (int) است. این نوع شی تنها می‌تواند یکی از دو مقدار True (درست) یا False (نادرست) را داشته باشد که True برابر با عدد صحیح 1 و False برابر با عدد صحیح 0 ارزیابی می‌گردد:

>>> a = True

>>> a
True

>>> type(a)
<class 'bool'>

>>> import sys
>>> sys.getsizeof(a)
28
>>> int(True)
1
>>> int(False)
0
>>> float(True)
1.0
>>> complex(True)
(1+0j)
>>> True + 1
2
>>> False + 1
1
>>> True * 25
25
>>> False * 25
0

کلاس ()bool یا متد ()__bool__ مقدار بولی یک شی را برمی‌گرداند [اسناد پایتون]:

>>> bool(0)
False
>>> bool(1)
True
>>> bool("")   # Empty String
False
>>> a = 15
>>> a.__bool__()
True
>>> a = -15
>>> a.__bool__()
True
>>> a = 0
>>> a.__bool__()
False

در پایتون اشیا پایین به مقدار بولی False (نادرست) ارزیابی می‌گردند:

  • None
  • False
  • شی صفر (در انواع گوناگون): 0، 0.0، 0j
  • تمام اشیا دنباله‌ خالی: ""، ()، []
  • شی دیکشنری خالی: {}
  • شی مجموعه خالی: ()set

با موارد نا آشنا به مرور آشنا می‌شوید.

رشته

نوع «رشته» (String) در پایتون با قرار گرفتن دنباله‌ای از کاراکترها درون یک جفت نماد نقل قول (Quotation) تکی ' ' یا دو تایی " " ایجاد می‌شود؛ به مانند "Python Strings" یا 'Python Strings' که تفاوتی با یکدیگر از نظر نوع ندارند:

>>> a = "Python Strings"

>>> a
'Python Strings'

>>> print(a)
Python Strings

>>> import sys
>>> sys.getsizeof(a)
63

بیشتر مواقع در حالت تعاملی نیازی به استفاده از تابع (یا دستور) print نمی‌باشد ولی باید توجه داشته باشیم که حالت تعاملی بر بدون ابهام بودن این خروجی‌ها توجه دارد بنابراین آن‌ها را با جزییات نمایش می‌دهد که مناسب برنامه‌نویس است؛ برای نمونه حتما به چگونگی نمایش انواع دسیمال و کسری توجه کرده‌اید یا در نمونه کد بالا مشاهده می‌شود که نوع رشته به همراه نماد نقل قول نمایش داده شده است یا اگر متن رشته شامل کاراکترهای Escape باشد، آن‌ها را بدون تفسیر به همان شکل به خروجی می‌فرستد. اما print توجه بر خوانایی خروجی خود دارد و تا حد امکان جزییات را پنهان می‌کند؛ در نتیجه متن تمیزتری را نمایش می‌دهد که بیشتر مناسب کاربر نهایی است.

در پایتون برخلاف برخی از زبان‌ها نوع کاراکتر یا char وجود ندارد؛ در این زبان یک کاراکتر چیزی جز یک رشته با طول یک نیست.

در پایتون می‌توان از نمادهای نقل قول در داخل یکدیگر نیز بهره برد؛ در این شرایط تنها می‌بایست نماد نقل قول داخلی با بیرونی متفاوت باشد. چنانچه می‌خواهید از نماد نقل قول یکسانی استفاده نمایید، باید از کاراکترهای Escape کمک بگیرید که در ادامه بررسی خواهند شد:

>>> "aaaaaa 'bbb'"
"aaaaaa 'bbb'"
>>> 'aaaaaa "bbb"'
'aaaaaa "bbb"'

>>> "I'm cold!"
"I'm cold!"
>>> 'I\'m cold!'
"I'm cold!"

از درس پیش با Docstring آشنا شده‌ایم؛ در کاربردی دیگر از سه نماد نقل قول """ یا ''' برای ایجاد شی رشته نیز استفاده می‌شود. مزیت این نوع رشته در این است که می‌توان متن آن را به سادگی در چند سطر و با هر میزان تورفتگی دلخواه نوشت؛ این موضوع در زمان‌هایی که قصد استفاده از کدهای خاص به مانند HTML در برنامه خود داشته باشیم، بسیار مفید خواهد بود:

>>> a = """Python"""
>>> a
'Python'
>>> html = """
... <!DOCTYPE html>
... <html>
...     <head>
...         <title>Page Title</title>
...     </head>
...     <body>
...         <h1>This is a Heading.</h1>
...         <p>This is a paragraph.</p>
...     </body>
... </html>
... """
>>> print(html)

<!DOCTYPE html>
<html>
    <head>
        <title>Page Title</title>
    </head>
    <body>
        <h1>This is a Heading.</h1>
        <p>This is a paragraph.</p>
    </body>
</html>

>>>

دنباله‌ها

برخی از انواع شی پایتون به مانند رشته، تاپل (tuple)، لیست (list) و… با عنوان دنباله (Sequence) نیز شناخته می‌شوند. دنباله ویژگی‌هایی دارد که در اینجا به کمک نوع رشته بررسی خواهیم کرد. رشته در واقع یک دنباله از کاراکترهاست در نتیجه می‌توان هر یک از اعضای این دنباله را با استفاده از اندیس (Index) موقعیت آن دستیابی نمود؛ اندیس اعضا از سمت چپ با عدد صفر شروع و به سمت راست یک واحد یک واحد افزایش می‌یابد. به عنوان نمونه برای شی 'Python Strings' می‌توانیم شمای اندیس‌گذاری را به صورت پایین در نظر بگیریم:

P y t h o n   S t r i n g s
- - - - - - - - - - - - - -
0 1 2 3 4 5 6 7  ...      13

برای دستیابی اعضای یک دنباله با نام seq از الگو [seq[i که i اندیس عضو مورد نظر است؛ استفاده می‌شود:

>>> a = "Python Strings"
>>> a[0]
'P'
>>> a[7]
'S'
>>> a[6]
' '

چند نکته:

  • الگو [seq[-i اعضا دنباله را از سمت راست پیمایش می کند؛ اندیس سمت راست ترین عضو 1- است و به ترتیب به سمت چپ یک واحد یک واحد کاهش می‌یابد.
  • الگو [seq[i:j اعضایی از دنباله را که در بازه‌ای از اندیس i تا قبل از اندیس j هستند را دستیابی می‌کند. برای بیان نقاط «از ابتدا» و «تا انتها» می‌توان به ترتیب i و j را ذکر نکرد.
  • الگو [seq[i:j:k همانند قبلی است با این تفاوت که k اندازه گام پیمایش اعضا را تعیین می‌کند.
  • با استفاده از تابع ()len می‌توان تعداد اعضای یک دنباله را به دست آورد [اسناد پایتون].
>>> a = "Python Strings"

>>> len(a)
14

>>> a[-2]
'g'

>>> a[2:4]
'th'
>>> a[7:]
'Strings'
>>> a[:6]
'Python'
>>> a[:-1]
'Python String'

>>> a[2:12:3]
'tntn'
>>> a[:6:2]
'Pto'
>>> a[7::4]
'Sn'

>>> a[-1]
's'
>>> a[len(a)-1]
's'

باید توجه داشت که یک شی رشته جزو انواع immutable پایتون است و مقدار (یا اعضا دنباله) آن را نمی‌توان تغییر داد؛ برای مثال نمی‌توان شی 'Python Strings' به 'Python-Strings' تغییر داد - برای این کار تنها می‌بایست یک شی جدید ایجاد کرد:

>>> a = "Python Strings"
>>> a[6] = "-"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

عملگرها برای رشته

با رشته‌ها نیز می‌توان از عملگرهای + (برای پیوند رشته‌ها) و * (برای تکرار رشته‌ها) بهره برد:

>>> a = "Python" + " " + "Strings"
>>> a
'Python Strings'

>>> "-+-" * 5
'-+--+--+--+--+-'

برای پیوند می‌توان از عملگر + صرف نظر کرد و تنها با کنار هم قرار دادن رشته‌ها آن‌ها را پیوند داد؛ البته این روش در مواقعی که از متغیر استفاده می‌کنید درست نمی‌باشد:

>>> "Python " "Programming " "Language"
'Python Programming Language'
>>> a, b, c = "Python ", "Programming ", "Language"
>>> a + b + c
'Python Programming Language'

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

>>> a = "py"
>>> b = "PY"    # Uppercase
>>> a == b
False

از عملگرهای عضویت هم می‌توان برای بررسی وجود کاراکتر یا رشته‌ای درون رشته‌ای دیگر استفاده کرد:

>>> "n" in "python"
True
>>> "py" not in "python"
False

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

کاراکترهای Escape

به صورت پیش‌فرض تعدادی کاراکتر خاص تعریف شده است که می‌توان آن‌ها را درون رشته‌ها بکار برد. تمام این کاراکترها با یک \ آغاز می‌شوند به همین دلیل گاهی نیز به نام Backslash Characters خوانده می‌شوند. در واقع این کاراکترها امکانی برای درج برخی دیگر از کاراکترها هستند که نمی‌توان آن‌ها را به سادگی توسط صفحه‌کلید وارد کرد. برای نمونه یکی از کاراکترهای Escape رایج n\ است که بیانگر کاراکتری با کد اسکی 10 (LF) به نام newline می‌باشد؛ n\ در هر جایی از رشته (یا متن) که درج گردد در هنگام چاپ سطر جاری را پایان می‌دهد و ادامه رشته (یا متن) از سطر جدید آغاز می‌‌شود [اسناد پایتون]:

>>> a = "Python\nProgramming\nLanguage"
>>> a
'Python\nProgramming\nLanguage'
>>> print(a)
Python
Programming
Language
>>>

برخی از این کاراکترها به شرح پایین است:

  • n\ - پایان سطر جاری و رفتن به سطر جدید
  • t\ - برابر کد اسکی 9 (TAB): درج هشت فاصله (کلید Space)
  • uxxxx\ - درج یک کاراکتر یونیکد 16 بیتی با استفاده از مقدار هگزادسیمال (پایه شانزده) آن : "u067E\"
  • Uxxxxxxxx\ - درج یک کاراکتر یونیکد 32 بیتی با استفاده از مقدار هگزادسیمال (پایه شانزده) آن : "U0001D11E\"
  • ooo\ - درج یک کاراکتر با استفاده از مقدار اُکتال (پایه هشت) آن : "123\"
  • xhh\ - درج یک کاراکتر با استفاده از مقدار هگزادسیمال (پایه شانزده) آن : "x53\"
  • '\ - درج یک کاراکتر '
  • "\ - درج یک کاراکتر "
  • \\ - درج یک کاراکتر \

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

>>> fpath = "C:\new\text\sample.txt"

>>> print(fpath)
C:
ew        ext\sample.txt

برای حل مشکل نمونه کد بالا می‌توان هر جا که نیاز به \ است از \\ استفاده کرد: "C:\\new\\text\\sample.txt". ولی راهکار جامع‌تر ایجاد «رشته‌های خام» (Raw Strings) است؛ در این نوع رشته‌، کاراکترهای Escape بی‌اثر هستند. رشته خام با افزوده شدن یک حرف r یا R به ابتدای یک رشته معمولی ایجاد می‌گردد:

>>> fpath = r"C:\new\text\sample.txt"
>>> print(fpath)
C:\new\text\sample.txt

تبدیل کد به کاراکتر و برعکس

می‌دانیم برای اینکه کامپیوتر بتواند کاراکتر‌ها را درک کند نیاز به سیستم‌هایی است که آن‌ها را برای تبدیل به کدهای پایه دو کدگذاری کند؛ به مانند سیستم اَسکی (ASCII) یا سیستم‌های جامع‌تری مانند UTF-8 که تحت استاندارد یونیکد (Unicode) در دسترس هستند. گاهی نیاز است به این کدها دسترسی داشته باشیم و با کاراکترها بر اساس آن‌ها کار کنیم؛ برای این منظور در پایتون می‌توان از دو تابع ()ord (تبدیل کد به کاراکتر) [اسناد پایتون] و ()chr (تبدیل کاراکتر به کد) [اسناد پایتون] استفاده کرد. تابع ()ord یک رشته تک کاراکتری را گرفته و یک عدد (در پایه ده) که بیانگر کد کاراکتر مورد نظر می‌باشد را برمی‌گرداند. تابع ()chr نیز کد کاراکتری (که می‌بایست عددی در پایه ده باشد) را گرفته و کاراکتر مربوط به آن را برمی‌گرداند:

>>> # Python 3.x - GNU/Linux

>>> ord("A")
65
>>> chr(65)
'A'

>>> int("067E", 16)   # Hexadecimal to Decimal
1662
>>> chr(1662)         # Unicode Character:  1662 -> 067E -> 'پ'
'پ'
>>> ord(_)            # _ is result of the last executed statement  = 'پ'
1662

>>> ord("\U0001D11E")
119070
>>> chr(_)
'𝄞'

از آنجا که نسخه‌های 2x پایتون به صورت پیش‌فرض از کدگذاری تحت استاندارد یونیکد پشتیبانی نمی‌کنند؛ برای گرفتن کاراکتر یونیکد (کاراکترهای خارج از محدوده اَسکی) از کد آن، می‌بایست از تابع جداگانه‌ای با نام ()unichr [اسناد پایتون] استفاده نماییم:

>>> # Python 2.x - GNU/Linux

>>> ord("a")
97
>>> chr(97)
'a'

>>> unichr(1662)
u'\u067e'
>>> print _
پ

>>> ord(u"\U0001D11E")
119070
>>> unichr(_)
u'\U0001d11e'
>>> print _
𝄞

تبدیل به نوع رشته

برای تبدیل اشیایی از نوع دیگر به نوع رشته؛ کلاس ()str [اسناد پایتون] و تابع ()repr [اسناد پایتون] وجود دارد. کلاس ()str یک نمونه غیر رسمی (informal) از نوع شی رشته را برمی‌گرداند؛ غیر رسمی از این جهت که توسط آن جزییات شی رشته پنهان می‌شود. اما تابع ()repr یک نمونه رسمی (official) از نوع رشته پایتون را برمی‌گرداند. کمی قبل‌تر راجب تفاوت خروجی print و حالت تعاملی صحبت کردیم؛ در واقع خروجی ()str مناسب برای چاپ است و همانند print جزییات این نوع شی را ارایه نمی‌دهد در حالی که ()repr به مانند حالت تعاملی یک ارايه (representation) کامل از شی رشته را برمی‌گرداند:

>>> str(14)
'14'
>>> repr(14)
'14'

>>> str(True)
'True'
>>> repr(False)
'False'
>>> a = "Python Strings"

>>> str(a)
'Python Strings'
>>> repr(a)
"'Python Strings'"

>>> print(str(a))
Python Strings
>>> print(repr(a))
'Python Strings'

همچنین به جای این دو می‌توانید از متدهای ()__str__ و ()__repr__ استفاده نمایید:

>>> a = 10
>>> a.__str__()
'10'

قالب‌بندی رشته‌ (String Formatting)

قالب‌بندی امکانی برای جایگزین کردن یک یا چند مقدار (به بیان بهتر: شی) - گاهی همراه با اعمال تغییر دلخواه - درون یک رشته است که به دو شکل در پایتون پیاده‌سازی می‌گردد [اسناد پایتون]:

۱. قالب سنتی - با الگو (s..." % (values%..."

از دو بخش تشکیل شده است؛ بخش سمت چپ عملگر %، رشته‌ای را مشخص می‌کند که شامل یک یا چند کد جایگذاری شی می‌باشد - کدهای جایگذاری همگی با یک کاراکتر % شروع می‌شوند؛ مانند: s% - و در سمت راست آن شی‌هایی برای جایگزین شدن در رشته، داخل پرانتز قرار دارد؛ این اشیا به ترتیب از سمت چپ درون رشته جایگذاری می‌گردند:

>>> "Python is %s to learn if you know %s to start!" % ("easy", "where")
'Python is easy to learn if you know where to start!'

برخی از کدهای جایگذاری به شرح پایین است:

  • s% - جایگزینی در قالب یک رشته به شکل خروجی کلاس ()str
  • r% - جایگزینی در قالب یک رشته به شکل خروجی تابع ()repr
  • c% - جایگزینی در قالب یک کاراکتر: یک عدد صحیح که نشانگر کد کاراکتر می‌باشد را به کاراکتر یونیکد تبدیل کرده و درون رشته قرار می دهد.
>>> "%r is a %s language." % ("Python", "programming")
"'Python' is a programming language."

>>> er = 1427
>>> "Error %s!" % (er)
'Error 1427!'

>>> "A, B, C, ... Y, %c" % (90)
'A, B, C, ... Y, Z'
  • d% یا i% - جایگزینی در قالب یک عدد صحیح در پایه ده
  • o% - جایگزینی در قالب یک عدد صحیح در پایه هشت
  • x% - جایگزینی در قالب یک عدد صحیح در پایه شانزده با حروف کوچک
  • X% - جایگزینی در قالب یک عدد صحیح در پایه شانزده با حروف بزرگ
>>> "4 + 4 == %d" % (2*4)
'4 + 4 == 8'

>>> "%d" % (0b0110)
'6'

>>> "%d" % (12.6)
'12'

>>> "int('%o', 8) == %d" % (0o156, 0o156)
"int('156', 8) == 110"

>>> "15 == %X in HEX" % (15)
'15 == F in HEX'
  • f% - جایگزینی در قالب یک عدد ممیز شناور (دقت پیش‌فرض: ۶) در پایه ده
  • F% - همانند f% ؛ با این تفاوت که nan و inf را به شکل NAN و INF درج می‌کند.
  • e% - جایگزینی در قالب یک عدد ممیز شناور به شکل نماد علمی با حرف کوچک
  • E% - جایگزینی در قالب یک عدد ممیز شناور به شکل نماد علمی با حرف بزرگ
>>> "%f" % (12.526)
'12.526000'

>>> "%f" % (122e-3)
'0.122000'

>>> "%E" % (12.526)
'1.252600E+01'

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

>>> '%(qty)d more %(product)s' % {'product': 'book', 'qty': 1}
'1 more book'


>>> reply = """
... Greetings...
... Hello %(name)s!
... Your age is %(age)s
... """
>>> values = {'name': 'Bob', 'age': 40}
>>> print(reply % values)

Greetings...
Hello Bob!
Your age is 40

>>>

در اصل می‌توان برای بخش سمت چپ این قالب، ساختاری مانند پایین را در نظر گرفت:

%[(keyname)][flags][width][.precision]typecode
  • در هر استفاده وجود هر یک از []ها اختیاری است یا بستگی به مورد استفاده دارد.
  • (keyname) - درج کلید داخل پرانتز - در مواقع استفاده از شی دیکشنری آورده می‌شود.
  • flags - می‌تواند یکی از سه نماد +، و 0 باشد. + موجب درج علامت عدد می‌شود (علامت اعداد منفی به صورت پیش‌فرض درج می‌گردد؛ این علامت بیشتر برای درج علامت اعداد مثبت به کار می‌رود)، موجب چپ‌چین شدن مقدار می‌گردد (حالت پیش‌فرض راست‌چین است) و 0 تعیین می‌کند که فضای خالی اضافی با صفر پر گردد (در حالت پیش‌فرض Space گذاشته می‌شود).
  • width - اندازه رشته را تعیین می‌کند؛ در مواردی که اندازه تعیین شده بیشتر از اندازه واقعی مقدار باشد، فضای اضافی را می‌توان با صفر یا فضای خالی (Space) پر کرد و البته زمانی که کمتر تعیین گردد، این گزینه نادیده گرفته می‌شود.
  • precision. - در مورد اعداد ممیز شناور، دقت یا تعداد ارقام بعد از ممیز را تعیین می‌کند (دقت پیش‌فرض: ۶). در مواردی که تعداد تعیین شده کمتر از تعداد واقعی ارقام بعد ممیز باشد، عدد گِرد می‌گردد. به وجود . پیش از آن توجه نمایید.
  • typecode - بیانگر همان حرف تعیین کننده نوع کد جایگذاری می‌باشد.
  • به جای width و precision. می توان از * استفاده کرد که در این صورت عدد مربوط به آن‌ها نیز در بخش سمت راست آورده می‌شود و شی جایگزینی می‌بایست درست پس از آن ذکر گردد. این گزینه در مواقعی که لازم است این اعداد در طول اجرای برنامه تعیین گردند کاربرد دارد.
>>> "%6d" % (256)    # typecode='d' width='6'
'   256'

>>> "%-6d" % (256)   # typecode='d' width='6' flags='-'
'256   '

>>> "%06d" % (256)   # typecode='d' width='6' flags='0'
'000256'

>>> "%+d" % (256)    # typecode='d' flags='+'
'+256'
>>> "%10f" % (3.141592653589793)      # typecode='f' width='10'
'  3.141593'

>>> "%10.4f" % (3.141592653589793)    # typecode='f' precision='4' width='10'
'    3.1416'

>>> "%10.8f" % (3.141592653589793)    # typecode='f' precision='8' width='10'
'3.14159265'

>>> "%-10.0f" % (3.141592653589793)   # typecode='f' precision='0' width='10' flags='-'
'3         '
>>> "%*d" % (5, 32)                                  # typecode='d' width='5'
'   32'

>>> "%d %*d %d" % (1, 8, 8231, 3)
'1     8231 3'

>>> "%f, %.2f, %.*f" % (1/3.0, 1/3.0, 4, 1/3.0)
'0.333333, 0.33, 0.3333'

>>> n = """
... %15s : %-10s
... %15s : %-10s
... """
>>> v = ("First name", "Richard", "Last name",  "Stallman")
>>> print(n % v)

     First name : Richard
      Last name : Stallman

>>>

۲. قالب جدید، فراخوانی متد ()format - با الگو (format(values."...{}..."

در این قالب که در نسخه‌های 2.6، 2.7 و 3x پایتون در دسترس است؛ اشیا، آرگومان‌های یک متد مشخص هستند و با استفاده اندیس موقعیت‌ یا نام آن‌ها داخل {} در رشته جایگذاری می‌گردند:

>>> '{0} {1} {2}'.format("Python", "Programming", "Language")
'Python Programming Language'
>>> reply = """
... Greetings...
... Hello {name}!
... Your age is {age}
... """
>>> print(reply.format(age=40, name='Bob'))

Greetings...
Hello Bob!
Your age is 40

>>>
>>> "{0} version {v}".format("Python", v="3.4")
'Python version 3.4'

Caution

همانطور که در درس تابع‌ خواهیم آموخت؛ بدون نیاز به رعایت ترتیب می‌توان آرگومان‌ها را با انتساب مقدار مورد نظر به آن‌ها ارسال نمود.

با هر ترتیبی می‌توان اشیا را جایگذاری نمود:

>>> '{2}, {1}, {0}'.format('a', 'b', 'c')
'c, b, a'

از نسخه 2.7 و بالاتر چنانچه بخواهیم اشیا به ترتیبی که در آرگومان متد قرار دارد جایگذاری شوند؛ نیازی به ذکر اندیس یا نام آرگومان نمی‌باشد:

>>> '{}, {}, {}'.format('a', 'b', 'c')   # 2.7+ only
'a, b, c'

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

>>> '{2}, {1}, {0}'.format(*'abc')
'c, b, a'

>>> '{2}, {1}, {0}'.format(*'python')
't, y, p'

>>> '{2}, {1}, {0}'.format('z', *'abc')
'b, a, z'

بخش درون رشته این قالب نیز ساختاری مشابه پایین دارد:

{fieldname !conversionflag :formatspec}
  • fieldname - اندیس یا نام آرگومان است.

  • conversionflag! - می‌تواند یکی از حروف r و s باشد که به ترتیب ()repr و ()str را بر روی شی فراخوانی می‌کنند. توجه داشته باشید که این حروف با ! شروع می‌شوند:

    >>> "repr() shows quotes: {!r}; str() doesn't: {!s}".format('test1', 'test2')
    "repr() shows quotes: 'test1'; str() doesn't: test2"
    
  • formatspec: - چگونگی درج شی در رشته را تعیین می‌کند. با : شروع می‌شود و خود ساختاری به مانند پایین دارد:

    [[fill]align][sign][#][0][width][,][.precision][typecode]
    
    • در هر استفاده وجود هر یک از []ها اختیاری است یا بستگی به مورد استفاده دارد.
    • fill - می‌تواند هر کاراکتر قابل چاپی باشد - از این گزینه برای پر کردن فضای خالی که توسط width ایجاد گردیده، استفاده می‌شود.
    • align - می‌تواند یکی از کاراکترهای <، > یا ^ باشد که به ترتیب بیانگر حالت راست‌چین، چپ‌چین و وسط‌چین می‌باشند. width نیز پس از آن‌ها آورده می‌شود که میزان اندازه رشته را تعیین می‌کند.
    >>> '{0:<30}'.format('left aligned')     # align='<' width='30'
    'left aligned                  '
    
    >>> '{0:>30}'.format('right aligned')    # align='>' width='30'
    '                 right aligned'
    
    >>> '{0:^30}'.format('centered')         # align='^' width='30'
    '           centered           '
    
    >>> '{0:*^30}'.format('centered')        # align='^' width='30' fill='*'
    '***********centered***********'
    
    • sign - برای نمایش علامت اعداد کاربرد دارد و می‌تواند یکی از نمادهای +، یا یک فضا خالی (Space) باشد. به این صورت که: + علامت تمام اعداد مثبت و منفی را درج می‌کند و نیز تنها موجب درج علامت اعداد منفی می‌شود. در صورت استفاده از فضای خالی، علامت اعداد منفی درج شده ولی به جای علامت اعداد مثبت یک کاراکتر فضای خالی وارد می‌شود.
    >>> '{0:+f}; {1:+f}'.format(3.14, -3.14)   # typecode='f' sign='+'
    '+3.140000; -3.140000'
    
    >>> '{0:-f}; {1:-f}'.format(3.14, -3.14)   # typecode='f' sign='-'
    '3.140000; -3.140000'
    
    >>> '{0: f}; {1: f}'.format(3.14, -3.14)   # typecode='f' sign=' '
    ' 3.140000; -3.140000'
    
    • برخلاف قالب سنتی، می‌توان تبدیل پایه دو را هم داشته باشیم. تبدیل پایه در این قالب با استفاده از حروف b (پایه دو)، o (حرف اُ کوچک - پایه هشت) و x یا X (پایه شانزده) انجام می‌شود. چنانچه یک نماد # به پیش از آن‌ها افزوده شود، پیشوند پایه نیز درج می‌گردد:

      >>> "int: {0:d};  hex: {0:x};  oct: {0:o};  bin: {0:b}".format(42)
      'int: 42;  hex: 2a;  oct: 52;  bin: 101010'
      
      >>> "int: {0:d};  hex: {0:#x};  oct: {0:#o};  bin: {0:#b}".format(42)
      'int: 42;  hex: 0x2a;  oct: 0o52;  bin: 0b101010'
      
    • با استفاده از یک , (کاما Comma) می‌توان یک عدد را سه رقم سه رقم از سمت راست جدا نمود:

      >>> '{0:,}'.format(1234567890)
      '1,234,567,890'
      
    • بخش‌هایی از قالب سنتی در این قالب نیز تعریف شده‌ است. گزینه‌های precision ،typecode. و width به همان صورتی هستند که در قالب سنتی بیان گشته است. البته موارد typecode کمی کمتر است؛ به عنوان نمونه در این قالب کد i وجود ندارد و تنها می‌توان از d برای اعداد صحیح در پایه ده استفاده کرد:

      >>> '{0:06.2f}'.format(3.14159)    # width='6' precision='.2' typecode='f'  and [0]
      '003.14'
      >>> '{0:^8.2f}'.format(3.14159)    # align='^'
      '  3.14  '
      
    • برای بیان درصد می‌توان از % به جای f استفاده کرد:

      >>> points = 19.5
      >>> total = 22
      >>> 'Correct answers: {0:.2%}'.format(points/total)
      'Correct answers: 88.64%'
      
    • در قالب سنتی با استفاده از * می‌توانستیم گزینه‌های خود را در طرف دیگر مقداردهی نماییم؛ در قالب جدید برای این منظور می‌توان مانند کاری که برای جایگذاری اشیا انجام می‌دادیم، از { } استفاده کرده و مقدار گزینه‌ها را در جایگاه آرگومان متد تعریف نماییم:

      >>> text = "Right"
      >>> align = ">"
      >>> '{0:{fill}{align}16}'.format(text, fill=align, align=align)
      '>>>>>>>>>>>Right'
      

برخی از متدهای کاربردی یک شی رشته

  • ()capitalize [اسناد پایتون] - یک کپی از رشته که نخستین حرف آن به صورت بزرگ (Capital) نوشته شده است را برمی‌گرداند:

    >>> a = "python string methods"
    >>> a.capitalize()
    'Python string methods'
    
  • (center(width [اسناد پایتون] - یک عدد صحیح که تعیین کننده اندازه رشته است گرفته و رشته را به صورت وسط‌چین شده درون این بازه برمی‌گرداند. در صورتی که اندازه تعیین شده کوچکتر از اندازه واقعی رشته ((len(string) باشد؛ رشته بدون تغییر بازگردانده می‌شود. این متد یک آرگومان اختیاری هم دارد که توسط آن می‌توان کاراکتری را برای پر کردن فضای خالی تعیین نمود:

    >>> a = "python"
    
    >>> a.center(25)
    '          python         '
    
    >>> a.center(25, "-")
    '----------python---------'
    

    دو متد مشابه دیگر با الگو (rjust(width [اسناد پایتون] و (ljust(width [اسناد پایتون] نیز هستند که به ترتیب برای راست‌چین و چپ‌چین کردن متن رشته استفاده می‌شوند:

    >>> a.rjust(25)
    '                   python'
    
    >>> a.ljust(25, ".")
    'python...................'
    
  • (count(sub [اسناد پایتون] - یک رشته را گرفته و تعداد وقوع آن در رشته اصلی را برمی‌گرداند. این متد دو آرگومان اختیاری نیز دارد [[start[, end,] که می‌توان نقطه شروع و پایان عمل این متد را مشخص نمود:

    >>> a = "python string methods"
    
    >>> a.count("t")
    3
    >>> a.count("tho")
    2
    >>> a.count("tho", 15)              # start=15
    1
    >>> a.count("tho", 0, len(a)-1)     # start=0 end=20 -> len(a)==21 : 0 ... 20
    2
    
  • (endswith(suffix [اسناد پایتون] - یک رشته را گرفته و چنانچه رشته اصلی با آن پایان یافته باشد مقدار True و در غیر این صورت False را برمی‌گرداند. این متد دو آرگومان اختیاری نیز دارد [[start[, end,] که می‌توان نقطه شروع و پایان عمل این متد را مشخص نمود:

    >>> a = "Wikipedia, the free encyclopedia."
    
    >>> a.endswith(",")
    False
    >>> a.endswith(",", 0 , 10)    # start=0 end=10
    True
    >>> a.endswith("pedia.", 14)   # start=14
    True
    
  • (find(sub [اسناد پایتون] - یک رشته را گرفته و اندیس شروع آن را برای نخستین وقوع درون رشته اصلی برمی‌گرداند؛ در صورتی که آرگومان دریافتی در رشته اصلی یافت نشود مقدار 1- برگردانده می‌شود. این متد دو آرگومان اختیاری نیز دارد [[start[, end,] که می‌توان نقطه شروع و پایان عمل این متد را مشخص نمود:

    >>> a = "python programming language"
    
    >>> a.find("language")
    19
    >>> a.find("p")
    0
    >>> a.find("p", 6)               # start=6
    7
    >>> a.find("g", 18, len(a)-1)    # start=18 end=27-1
    22
    >>> a.find("saeid")
    -1
    

    متد مشابه دیگری نیز با الگو (rfind(sub [اسناد پایتون] وجود دارد؛ ولی با این تفاوت که اندیس شروع آرگومان دریافتی را برای آخِرین وقوع درون رشته اصلی برمی‌گرداند:

    >>> a.rfind("p")
    7
    >>> a.rfind("p", 6)
    7
    >>> a.rfind("g", 18, len(a)-1)
    25
    >>> a.rfind("saeid")
    -1
    

    در صورتی که نیازی به اندیس ندارید و تنها می‌خواهید وجود یک رشته را درون رشته‌ای مشخص بررسی نمایید؛ از عملگر in استفاده کنید:

    >>> "language" in a
    True
    >>> "p" in a
    True
    >>> "saeid" in a
    False
    
  • (index(sub [اسناد پایتون] - همانند متد (find(sub است با این تفاوت که اگر آرگومان دریافتی در رشته اصلی یافت نشود یک خطا ValueError را گزارش می‌دهد:

    >>> a = "python programming language"
    
    >>> a.index("python")
    0
    >>> a.index("python", 6)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: substring not found
    

    متد دیگری نیز با الگو (rindex(sub [اسناد پایتون] وجود دارد که مانند (rfind(sub عمل می‌کند ولی با این تفاوت که اگر آرگومان دریافتی در رشته اصلی یافت نشود یک خطا ValueError را گزارش می‌دهد:

    >>> a.rindex("g", 18, len(a)-1)
    25
    
  • (join(iterable [اسناد پایتون] - یک دنباله با اعضایی تمام از نوع رشته را به صورت آرگومان دریافت می‌کند و با استفاده از رشته اصلی اعضای آن‌ را به یکدیگر پیوند داده و برمی‌گرداند:

    >>> a = "-*-"
    
    >>> a.join("python")
    'p-*-y-*-t-*-h-*-o-*-n'
    
    >>> a.join(['p', 'y', 't', 'h', 'o', 'n'])   # get a list of strings
    'p-*-y-*-t-*-h-*-o-*-n'
    
  • (split(sep [اسناد پایتون] - یک کاراکتر را دریافت کرده و رشته را بر اساس آن از هم جدا کرده و به صورت یک شی لیست (list) برمی‌گرداند. این متد یک آرگومان اختیاری نیز دارد که می توان تعداد عمل جداسازی را تعیین نمود:

    >>> a = "p-y-t-h-o-n"
    
    >>> a.split()
    ['p-y-t-h-o-n']
    
    >>> a.split("-")
    ['p', 'y', 't', 'h', 'o', 'n']
    
    >>> a.split("-", 2)
    ['p', 'y', 't-h-o-n']
    
    >>> '1,2,,3,'.split(',')
    ['1', '2', '', '3', '']
    

    متد مشابه دیگری نیز با الگو (rsplit(sep [اسناد پایتون] وجود دارد ولی با این تفاوت که رشته را از سمت راست پیمایش می‌کند:

    >>> a.rsplit("-")
    ['p', 'y', 't', 'h', 'o', 'n']
    
    >>> a.rsplit("-", 2)
    ['p-y-t-h', 'o', 'n']
    
  • (replace(old, new [اسناد پایتون] - دو رشته به صورت آرگومان دریافت می‌کند؛ در تمام رشته اصلی بخش‌هایی که برابر مقدار آرگومان old هستند را با آرگومان new جایگزین می‌کند و سپس رشته جدید را برمی‌گرداند. این متد یک آرگومان اختیاری نیز دارد که می‌توان تعداد عمل جایگزینی را تعیین نمود:

    >>> a = "He has a blue house and a blue car!"
    
    >>> a.replace("blue", "red")
    'He has a red house and a red car!'
    
    >>> a.replace("blue", "red", 1)
    'He has a red house and a blue car!'
    
  • ()lower [اسناد پایتون] - تمام حروف الفبا انگلیسی موجود در رشته را به حرف کوچک تبدیل می‌کند و برمی‌گرداند:

    >>> "CPython-3.4".lower()
    'cpython-3.4'
    

    برعکس؛ متد ()upper [اسناد پایتون] تمام حروف الفبا انگلیسی موجود در رشته را به حرف بزرگ تبدیل می‌کند و برمی‌گرداند:

    >>> "CPython-3.4".upper()
    'CPYTHON-3.4'
    
  • ()islower [اسناد پایتون] - اگر رشته حداقل شامل یکی از حروف الفبا انگلیسی بوده و تمام حروف الفبا آن به صورت کوچک باشند مقدار True و در غیر این صورت False را برمی‌گرداند:

    >>> "python".islower()
    True
    >>> "python-3.4".islower()
    True
    >>> "Python".islower()
    False
    

    برعکس؛ متد ()isupper [اسناد پایتون] اگر رشته حداقل شامل یکی از حروف الفبا انگلیسی بوده و تمام حروف الفبا آن به صورت بزرگ باشند مقدار True و در غیر این صورت False را برمی‌گرداند:

    >>> "python".isupper()
    False
    >>> "Python".isupper()
    False
    >>> "PYTHON".isupper()
    True
    >>> "PYTHON-3.4".isupper()
    True
    
  • ()isalpha [اسناد پایتون] - اگر رشته حداقل شامل یک کاراکتر بوده و تمام کاراکترهای آن تنها یکی از حروف الفبا انگلیسی (کوچک یا بزرگ) باشند مقدار True و در غیر این صورت False را برمی‌گرداند:

    >>> "python".isalpha()
    True
    >>> "python34".isalpha()
    False
    >>> "python 34".isalpha()
    False
    
  • ()isalnum [اسناد پایتون] - اگر رشته حداقل شامل یک کاراکتر بوده و تمام کاراکترهای آن تنها یکی از عددهای 0 تا 9 یا حروف الفبا انگلیسی (کوچک یا بزرگ) باشند مقدار True و در غیر این صورت False را برمی‌گرداند:

    >>> "python34".isalnum()
    True
    >>> "python3.4".isalnum()
    False
    >>> "python-34".isalnum()
    False
    
  • ()isdigit [اسناد پایتون] - اگر رشته حداقل شامل یک کاراکتر بوده و تمام کاراکترهای آن تنها یکی از عددهای 0 تا 9 باشند مقدار True و در غیر این صورت False را برمی‌گرداند:

    >>> "python34".isdigit()
    False
    >>> "34".isdigit()
    True
    >>> "3.4".isdigit()
    False
    

چگونگی ارايه نوع رشته از موارد اختلاف اساسی در نسخه‌های 2x و 3x پایتون است.

در نسخه‌های 2x یک نوع جامع str که محدود به کدگذاری ASCII است؛ هر دو قالب رشته‌های معمولی و داده‌های باینری (متن‌های کدگذاری شده، فایل‌های مدیا و پیام‌های شبکه) را در بر می‌گیرد - رشته باینری با یک حرف b در آغاز آن‌ مشخص می‌گردد. در این سری از نسخه‌ها نوع دیگری نیز با نام unicode وجود دارد که رشته‌های خارج از محدوده کدگذاری ASCII را در بر می‌گیرد؛ برای ایجاد این نوع اشیا می‌بایست رشته مورد نظر با یک حرف u آغاز گردد:

>>> # python 2.x

>>> a = "python"
>>> type(a)
<type 'str'>

>>> a = b"python"
>>> type(a)
<type 'str'>

>>> a = u"python"
>>> type(a)
<type 'unicode'>

علاوه‌بر قرار دادن حرف u در ابتدای رشته برای ایجاد رشته یونیکد، می‌توان از تابع ()unicode [اسناد پایتون] نیز با مشخص کردن سیستم کدگذاری استفاده کرد:

>>> # python 2.x

>>> u = unicode("python", "utf-8")

>>> type(u)
<type 'unicode'>

>>> u
u'python'

>>> print u
python

>>> fa = u"پ"
>>> fa
u'\u067e'
>>> print fa
پ

بنابراین انواع رشته در پایتون 2x:

  • رشته‌های معمولی (محدود به کدگذاری اَسکی) + داده‌های باینری: str
  • رشته‌های یونیکد : unicode

ولی در نسخه‌های 3x رشته توسط سه نوع ارایه می‌گردد. اکنون کدگذاری پیش‌فرض کاراکترها در پایتون از ASCII بسیار گسترده‌تر شده است و از استاندارد یونیکد پشتیبانی می‌کند بنابراین نوع str به تنهایی می‌تواند تقریبا تمامی کاراکترهای دنیا را شامل شود و دیگر نیازی به نوع جداگانه و استفاده از حرف u برای مشخص کردن رشته‌های یونیکد نیست؛ بنابراین در این نسخه‌ها برای تمام رشته‌های اسکی و یونیکد تنها یک نوع str ارایه شده است. تغییر دیگری نیز رخ داده که نوع داده باینری از رشته‌های معمولی جدا شده است و توسط نوع جدیدی با نام bytes ارایه می‌گردد:

>>> # Python 3.x

>>> a = "python"
>>> type(a)
<class 'str'>

>>> a = b"python"
>>> type(a)
<class 'bytes'>

>>> a = u"python"
>>> type(a)
<class 'str'>

بنابراین انواع رشته در پایتون 3x:

  • رشته‌های معمولی (اَسکی و یونیکد): str
  • داده‌های باینری: bytes
  • نوع تغییر پذیر (Mutable) برای داده‌های باینری: bytearray - این نوع در واقع یک دنباله تغییر پذیر از نوع bytes است که در نسخه‌های 2.6 و 2.7 نیز در دسترس است.

در پایتون 3x برای ایجاد نوع bytes علاوه‌بر حرف b می‌توان از کلاس ()bytes [اسناد پایتون] نیز استفاده کرد که در آرگومان این کلاس برای نوع رشته لازم است که سیستم کدگذاری آن را نیز مشخص نماییم؛ داده‌های عددی را نیز بهتر است به شکل یک شی لیست ارسال نماییم:

>>> # Python 3.x
>>> b = b"python"
>>> b
b'python'
>>> b = bytes("python", "utf-8")
>>> b
b'python'

>>> c = bytes([97])
>>> c
b'a'

اکنون برای تبدیل نوع bytes به str نیاز به کدگشایی یا Decode کردن داده‌ها داریم؛ این کار را می‌توان با استفاده از متد ()decode یا کلاس ()str با مشخص کردن سیستم کدگشایی به انجام رساند:

>>> type(b)
<class 'bytes'>

>>> print(b)
b'python'

>>> b.decode("utf-8")
'python'

>>> str(b, "utf-8")
'python'

همانند کلاس ()bytes این بار برای ایجاد نوع bytearray از کلاس ()bytearray [اسناد پایتون] استفاده می‌شود:

>>> # Python 3.x

>>> b = bytearray("python", "utf-8")

>>> b
bytearray(b'python')

>>> print(b)
bytearray(b'python')

>>> b[0]
112
>>> b[0] = 106           # 106='j'

>>> b.decode("utf-8")
'jython'
>>> str(b, "utf-8")
'jython'


😊 امیدوارم مفید بوده باشه

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

درس ۰۸: انواع آماده شی - بخش دوم

پایتون هر «نوع داده» (Data Type) را توسط یک کلاس ارایه می‌دهد؛ بنابراین هر داده یک نمونه یا یک شی از کلاسی مشخص است. هر چند برنامه‌نویس نیز می‌تواند با تعریف کلاس، نوع دلخواه خود را داشته باشد ولی در این درس می‌خواهیم درباره آن بخشی از انواع داده یا انواع شی‌ (Object Types) که به شکل آماده (Built-in) در اختیار مفسر زبان پایتون قرار داده شده است صحبت کنیم.

این درس در ادامه درس پیش به بررسی برخی از انواع دیگر پایتون به مانند «لیست»، «تاپل»، «دیکشنری» و «مجموعه» می‌پردازد.

سطح: مقدماتی



لیست

نوع «لیست» (List) انعطاف‌ پذیرترین نوع آماده در پایتون می‌باشد. این نوع همانند رشته یک «دنباله» (Sequence) بوده ولی برخلاف آن یک نوع «تغییر پذیر» (Mutable) است. شی لیست با استفاده از کروشه [ ] ایجاد می‌گردد و می‌تواند عضوهایی - با هر نوع - داشته باشد که توسط کاما , از یکدیگر جدا می‌شوند؛ نوع لیست در واقع محلی برای نگهداری اشیا گوناگون است:

>>> L = [1, 2, 3]
>>> type(L)
<class 'list'>

>>> L
[1, 2, 3]
>>> print(L)
[1, 2, 3]

>>> import sys
>>> sys.getsizeof(L)
88
>>> L = []    # An empty list
>>> L
[]

عضوهای لیست می‌توانند از هر نوعی باشند؛ حتی یک لیست:

>>> L = [15, 3.14, 'string', [1, 2]]

شی لیست جزو انواع دنباله پایتون است و می‌توان عضوها را بر اساس اندیس موقعیت آن‌ها دستیابی نمود:

>>> L = [1, 2, 3]
>>> L[0]
1
>>> L[-1]
3

و همچنین تعداد عضوهای هر شی لیست را توسط تابع ()len [اسناد پایتون] به دست آورد:

>>> L1 = []
>>> len(L1)
0

>>> L2 = ['python', 12.06]
>>> len(L2)
2

>>> len(L2[0])
6

>>> L3 = ['a', [1, 2], 'b']
>>> len(L3)
3
>>> len(L3[1])
2

چنانچه یک دنباله جزو عضوهای شی لیست باشد، با استفاده از الگو [seq[i][j می‌توان عضوهای آن را نیز دستیابی نمود که در آن i اندیسی است که به یک عضو شی لیست اشاره دارد و j نیز اشاره به اندیس داخلی عضو i دارد؛ این الگو به همین شیوه می‌تواند ادامه یابد:

>>> L = ['python', 2.56]
>>> L[0]
'python'
>>> L[0][:2]
'py'

>>> L = ['python', 2.56, [128, ['a', 'z']]]
>>> L[2][1][0]
'a'

یکی از مثال‌های رایج شی لیست‌، شبیه‌سازی ساختار ماتریس (Matrix) است:

>>> L = [[1, 2, 3],
...      [4, 5, 6],
...      [7, 8, 9]]
>>>

>>> L
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

>>> L[0][1]
2

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

  • جایگزین کردن:

    >>> L = [1, 2, 3]
    
    >>> L[1] = 'py'
    >>> L
    [1, 'py', 3]
    
    >>> L = [1, 2, 3, 4, 5, 6]
    
    >>> L[:2] = [0, 0]
    >>> L
    [0, 0, 3, 4, 5, 6]
    
  • درج کردن - i در الگو [seq[i:i به موقعیتی از شی seq اشاره دارد که می‌خواهیم درج در آن نقطه انجام شود؛ در این شیوه توجه داشته باشید که شی‌ای که می‌خواهید درون لیست درج کنید می‌بایست یک دنباله باشد:

    >>> L = [0, 1, 5, 6]
    
    >>> L[2:2] = [2, 3, 4]
    >>> L
    [0, 1, 2, 3, 4, 5, 6]
    
    >>> L[0:0] = 'abc'
    >>> L
    ['a', 'b', 'c', 0, 1, 2, 3, 4, 5, 6]
    
    >>> L[3:3] = ['d', [-2, -1]]
    >>> L
    ['a', 'b', 'c', 'd', [-2, -1], 0, 1, 2, 3, 4, 5, 6]
    
  • حذف کردن - کافی است یک شی لیست خالی ([]) را به یک یا چند عضو از شی لیست مورد نظر انتساب دهیم:

    >>> L = [0, 1, 2, 3, 4, 5, 6]
    
    >>> L[2:5] = []
    >>> L
    [0, 1, 5, 6]
    

دستور del

با استفاده از دستور del [اسناد پایتون] نیز می‌توان یک عضو یا یک تکه از شی لیست را حذف کرد:

>>> L = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

>>> del L[2]
>>> L
['a', 'b', 'd', 'e', 'f', 'g']

>>> del L[1:4]
>>> L
['a', 'f', 'g']

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

>>> a = 5
>>> a
5

>>> del a

>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

انتساب چندگانه

می‌توان یک شی لیست - یا در کل یک شی دنباله - را به تعدادی نام انتساب داد و متغیرهای جداگانه‌ای ایجاد نمود؛ این عمل Unpacking خوانده می‌شود. در این شرایط مفسر پایتون هر عضو دنباله را با حفظ ترتیب به یکی از نام‌ها انتساب می‌دهد که در حالت عادی می‌بایست تعداد نام‌ها با عضوهای دنباله برابر باشد:

>>> L = [1.1, 2.2, 3.3, 4.4]

>>> a, b, c, d = L

>>> a
1.1
>>> b
2.2
>>> c
3.3
>>> d
4.4
>>> a, b = [1.1, 2.2, 3.3, 4.4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)

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

>>> L = [1.1, 2.2, 3.3, 4.4]

>>> a, b, *c = L

>>> a
1.1
>>> b
2.2
>>> c
[3.3, 4.4]
>>> *a, b = [1.1, 2.2, 3.3, 4.4]

>>> a
[1.1, 2.2, 3.3]
>>> b
4.4
>>> a, *b, c = [1.1, 2.2, 3.3, 4.4]

>>> a
1.1
>>> b
[2.2, 3.3]
>>> c
4.4
>>> a, b, c, *d = [1.1, 2.2, 3.3, 4.4]

>>> a
1.1
>>> b
2.2
>>> c
3.3
>>> d
[4.4]

کپی کردن

همانند دیگر اشیا می‌توان با انتساب یک متغیر موجود از شی لیست به یک نام جدید، متغیر دیگری از این نوع شی ایجاد کرد. البته همانطور که پیش‌تر نیز بیان شده است؛ در این حالت شی کپی نمی‌گردد و تنها یک ارجاع جدید از این نام جدید به شی آن متغیر داده می‌شود. این موضوع با استفاده از تابع ()id [اسناد پایتون] قابل آزمودن است؛ خروجی این تابع برابر نشانی شی در حافظه می‌باشد و بدیهی است که دو مقدار id یکسان برای دو متغیر نشان از یکی بودن شی آن‌هاست:

>>> L1 = [1, 2, 3]

>>> L2 = L1

>>> L2
[1, 2, 3]

>>> id(L1)
140254551721800
>>> id(L2)
140254551721800

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

>>> L1 = [1, 2, 3]

>>> L2 = L1

>>> L1[0] = 7

>>> L1
[7, 2, 3]
>>> L2
[7, 2, 3]

اگر این موضوع را یک مشکل بدانیم برای رفع آن می‌توان از شی متغیر یک کپی ایجاد کرده و این کپی را به متغیر جدید نسبت دهیم؛ در این شرایط هر دو متغیر به اشیایی جداگانه در محل‌هایی متفاوت از حافظه اشاره خواهند داشت. در حالت عادی برای کپی کردن یک شی لیست نیاز به کار جدیدی نیست و می‌توان از اندیس گذاری [:] - به معنی تمامی عضوها - استفاده کرد:

>>> L1
[7, 2, 3]

>>> L2 = L1[:]

>>> L1
[7, 2, 3]
>>> L2
[7, 2, 3]

>>> id(L1)
140254551721928
>>> id(L2)
140254551721800

>>> L1[0] = 5

>>> L1
[5, 2, 3]
>>> L2
[7, 2, 3]
_images/l08-python-list-assignment-01.png

ولی اگر شی لیست مورد نظر عضوهایی از نوع لیست (یا هر نوع تغییر پذیر دیگر) داشته باشد، مشکل فوق همچنان برای این عضوها باقی است. به نمونه کد و تصویر پایین توجه نمایید:

>>> L1 = [1, 2, [7, 8]]

>>> L2 = L1[:]
>>> L2
[1, 2, [7, 8]]

>>> L1[2][1] = 5

>>> L1
[1, 2, [7, 5]]
>>> L2
[1, 2, [7, 5]]

>>> id(L1)
140402644179400
>>> id(L2)
140402651379720

>>> id(L1[2])
140402644179080
>>> id(L2[2])
140402644179080
_images/l08-python-list-assignment-02.png

در پایتون کپی شی به دو شیوه «سطحی» (Shallow Copy) و «عمیق» (Deep Copy) انجام می‌شود که به ترتیب توسط تابع‌های ()copy و ()deepcopy از درون ماژول copy در دسترس هستند [اسناد پایتون]. در شیوه کپی سطحی همانند کاری که پیش از این انجام دادیدم - یعنی انتساب با استفاده از اندیس [:] - اشیا داخلی کپی نمی‌شوند و تنها یک ارجاع جدید به آن‌ها داده می‌شود؛ در حالی که توسط شیوه کپی عمیق از تمامی اشیا (تغییر پذیر) داخلی نیز یک کپی ایجاد می‌گردد:

>>> L1 = [1, 2, [7, 8]]

>>> import copy
>>> L2 = copy.copy(L1)    # Shallow Copy

>>> L1[2][1] = 5

>>> L1
[1, 2, [7, 5]]
>>> L2
[1, 2, [7, 5]]
>>> L1 = [1, 2, [7, 8]]

>>> import copy
>>> L2 = copy.deepcopy(L1)    # Deep Copy

>>> L1[2][1] = 5

>>> L1
[1, 2, [7, 5]]
>>> L2
[1, 2, [7, 8]]

>>> id(L1)
140402651379656
>>> id(L2)
140402644179400

>>> id(L1[2])
140402644106312
>>> id(L2[2])
140402651379080

عملگرها برای لیست

می‌توان از عملگرهای + (برای پیوند لیست‌ها) و * (برای تکرار عضوهای لیست) بهره برد:

>>> [1, 2] + [2, 3] + [3, 4]
[1, 2, 2, 3, 3, 4]

>>> ['python'] * 3
['python', 'python', 'python']

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

>>> [1, 'python'] == [1, 'python']
True

>>> [1, 'python'] == [1, 'PYTHON']
False

از عملگرهای عضویت هم می‌توان برای بررسی وجود شی‌ای درون لیست استفاده کرد:

>>> L = ['a', [1, 2]]

>>> 'b' not in L
True
>>> 2 in L
False
>>> [1, 2] in L
True

تفاوت عملگرهای == و is

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

>>> a = 5
>>> b = a
>>> a == b
True
>>> a is b
True

>>> L1 = [1, 2, 3]
>>> L2 = L1
>>> L1 == L2
True
>>> L1 is L2
True

>>> L2 = L1[:]
>>> L1 == L2
True
>>> L1 is L2          # False!
False

از درس پنجم به یاد داریم که هر شی در پایتون حاوی یک «شناسه» (identity)، یک «نوع» (type) و یک «مقدار» (value) است. عملگر == دو شی را از نظر یکسان بودن «مقدار» مورد بررسی قرار می‌دهد در حالی که عملگر is دو شی را از نظر یکسان بودن «شناسه» (خروجی تابع ()id) یا همان نشانی آن‌ها در حافظه مورد بررسی قرار می‌دهد.

پیش از این هم بیان شده بود که مفسر پایتون برای صرفه‌جویی در زمان و حافظه از ساخت مجدد اشیا نوع «صحیح» و «رشته» کوچک موجود اجتناب می‌کند و تنها یک ارجاع جدید به آن‌ها می‌دهد. اما این موضوع در مورد اشیا دیگر درست نمی‌باشد و مفسر پایتون برای هر متغیری که برای این نوع اشیا تعریف می‌گردد یک شی جدید ایجاد می‌کند و به آن ارجاع می‌دهد:

>>> a = 5
>>> b = 5
>>> a == b
True
>>> a is b
True

>>> m = 'python'
>>> n = 'python'
>>> m == n
True
>>> m is n
True

>>> L1 = [1, 2, 3]
>>> L2 = [1, 2, 3]
>>> L1 == L2
True
>>> L1 is L2          # False!
False

تبدیل به شی لیست

با استفاده از کلاس ()list [اسناد پایتون] می‌توان یک شی لیست ایجاد کرد یا اشیایی که از نوع دنباله هستند را به یک شی لیست تبدیل نمود:

>>> a = 'python'
>>> type(a)
<class 'str'>

>>> b = list(a)
>>> type(b)
<class 'list'>

>>> b
['p', 'y', 't', 'h', 'o', 'n']
>>> L = list()
>>> L
[]

متدهای کاربردی یک شی لیست

شی لیست تغییر پذیر است و متدهای آن برخلاف شی رشته یک شی جدید تغییر یافته را برنمی‌گردانند بلکه تغییرات را بر روی همان شی ایجاد می‌کنند.

  • (append(x - شی x را به انتهای لیست مورد نظر اضافه می‌کند:

    >>> L = [1, 2, 3]
    
    >>> L.append(4)
    >>> L
    [1, 2, 3, 4]
    
    >>> L.append(['a', 'b'])
    >>> L
    [1, 2, 3, 4, ['a', 'b']]
    

    عملکرد این متد ((L.append(x) همانند عمل [L + [x است:

    >>> L = [1, 2, 3]
    >>> L + [4]
    [1, 2, 3, 4]
    
  • (extend(s - عضوهای شی دنباله s را به انتهای لیست مورد نظر اضافه می‌کند:

    >>> L = [1, 2, 3]
    
    >>> L.extend(['a', 'b'])
    >>> L
    [1, 2, 3, 'a', 'b']
    
    >>> L = [1, 2, 3]
    
    >>> L.extend('py')
    >>> L
    [1, 2, 3, 'p', 'y']
    
  • (insert(i, x - یک عضو جدید (مانند x) را در موقعیتی از لیست با اندیس دلخواه (مانند i) قرار می‌دهد:

    >>> L = [1, 2, 3]
    
    >>> L.insert(0, 'python')
    >>> L
    ['python', 1, 2, 3]
    
  • (remove(x - در لیست مورد نظر از سمت چپ به دنبال شی‌ x می‌گردد و نخستین مورد یافت شده را از لیست حذف می‌کند. چنانچه هیچ عضو برابری با شی x یافت نشود یک خطا گزارش می‌دهد:

    >>> L = [1, 2, 3, 5, 2 , 6 , 1]
    
    >>> L.remove(2)
    >>> L
    [1, 3, 5, 2, 6, 1]
    
    >>> L.remove(0)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: list.remove(x): x not in list
    

    Note

    در مواردی که می‌خواهید اندیس خاصی از لیست را حذف نمایید؛ از دستور del استفاده کنید.

  • ([pop([i - عضو متناظر با اندیس i را از لیست حذف و به عنوان خروجی برمی‌گرداند. چنانچه اندیس به متد فرستاده نشود به صورت پیش‌فرض آخرین عضو از لیست مورد نظر را حذف و برمی‌گرداند:

    >>> L = ['a', 'b', 'c', 'd']
    
    >>> L.pop(2)
    'c'
    >>> L
    ['a', 'b', 'd']
    
    >>> L.pop()
    'd'
    >>> L
    ['a', 'b']
    

    Note

    نماد [ ] در الگو متدها تنها روشی برای بیان اختیاری بودن عبارت درون آن می‌باشد و جزیی از متد نیست.

  • ([index(x[, n - در لیست مورد نظر از سمت چپ به دنبال شی x می‌گردد و اندیس نخستین مورد یافت شده را برمی‌گرداند. این متد یک آرگومان اختیاری (n) نیز دارد که به کمک آن می‌توان تعیین نمود اندیس چندمین مورد یافت شده برگردانده شود. چنانچه هیچ عضو برابری با شی x یافت نشود یک خطا گزارش می‌دهد:

    >>> L = ['s', 'b', 'c', 'a', 's', 'b']
    
    >>> L.index('b')
    1
    
    >>> L.index('b', 2)
    5
    
    >>> L.index('z')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: 'z' is not in list
    
  • (count(x - تعداد وقوع شی x را در لیست مورد نظر برمی‌گرداند:

    >>> L = ['a', 'b', 'c', 'a', 'a', 'b']
    
    >>> L.count('a')
    3
    >>> L.count(5)
    0
    
  • ()clear - تمام عضوهای لیست مورد نظر را حذف می‌کند. عملکرد این متد معادل دستور [:]del L می‌باشد:

    >>> L = [0, 1, 2, 3, 4, 5]
    
    >>> L.clear()
    >>> L
    []
    
    >>> L = [0, 1, 2, 3, 4, 5]
    
    >>> del L[:]
    >>> L
    []
    
  • ()reverse - عضوهای لیست مورد نظر را وارونه می‌کند:

    >>> L = ['a', 'b', 'c', 'd']
    
    >>> L.reverse()
    >>> L
    ['d', 'c', 'b', 'a']
    
  • ()sort - عضوهای یک لیست را مرتب می‌کند:

    >>> L = [4, 6, 2, 1, 5, 0, 3]
    
    >>> L.sort()
    >>> L
    [0, 1, 2, 3, 4, 5, 6]
    
    >>> L = ['g', 'e', 'h', 'f', 'd']
    
    >>> L.sort()
    >>> L
    ['d', 'e', 'f', 'g', 'h']
    

    این متد در حالت پیش‌فرض به صورت صعودی اقدام به مرتب سازی می‌کند ولی می‌توان با فرستادن مقدار True به آرگومان اختیاری reverse، شیوه آن را به نزولی تغییر داد:

    >>> L = [4, 6, 2, 1, 5, 0, 3]
    
    >>> L.sort(reverse=True)
    >>> L
    [6, 5, 4, 3, 2, 1, 0]
    

    متد ()sort آرگومان اختیاری دیگری نیز با نام key دارد که می‌توان با ارسال یک تابع تک آرگومانی به آن عمل دلخواهی را بر روی تک تک عضوهای لیست مورد نظر، پیش از مقایسه و مرتب‌سازی به انجام رساند. البته باید توجه داشت که تنها می‌بایست نام تابع به آرگومان متد فرستاده شود و نه الگو کامل آن؛ برای مثال تابع با الگو (func(x باید به صورت key=func فرستاده شود. چنانچه آرگومان key فرستاده شود، این متد عضوهای لیست را به تابع تعیین شده می‌فرستد و در انتها خروجی آن‌ها را برای عمل مرتب‌سازی در نظر می‌گیرد. به نمونه کد پایین توجه نمایید:

    >>> L = ['a', 'D', 'c', 'B', 'e', 'f', 'G', 'h']
    
    >>> L.sort()
    >>> L
    ['B', 'D', 'G', 'a', 'c', 'e', 'f', 'h']
    

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

    >>> L = ['a', 'D', 'c', 'B', 'e', 'f', 'G', 'h']
    
    >>> L.sort(key=str.lower)
    >>> L
    ['a', 'B', 'c', 'D', 'e', 'f', 'G', 'h']
    

    در نمونه کد بالا str.lower به چه معنی است؟

    در درس پیش با کلاس ()str که از آن برای ایجاد شی رشته استفاده می‌شد آشنا شدیم و با برخی از متدهای آن که برای یک شی رشته در دسترس بود (مانند: ()join) نیز کار کردیم. در آینده توسط درس مربوط به کلاس‌ها خواهیم آموخت که می‌توان با استفاده از نام کلاس و بدون ایجاد شی، متدهای داخل آن را فراخوانی نمود؛ در اینجا نیز همین اتفاق افتاده است و (lower(s متدی تک آرگومانی داخل کلاس str می‌باشد که توسط نام این کلاس فراخوانی شده است.

    >>> str
    <class 'str'>
    
    >>> str.lower
    <method 'lower' of 'str' objects>
    
    >>> dir(str)
    ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
    

    Tip

    با استفاده از تابع آماده ()dir [اسناد پایتون] می‌توانیم لیستی از تمام صفت‌ها و متدهای در دسترس یک شی را دریافت نماییم.

    به جای متد ()sort می‌توان از تابع آماده ()sorted [اسناد پایتون] نیز با همین توضیح استفاده کرد:

    >>> L = ['a', 'D', 'c', 'B', 'e', 'f', 'G', 'h']
    
    >>> sorted(L)
    ['B', 'D', 'G', 'a', 'c', 'e', 'f', 'h']
    
    >>> sorted(L, key=str.lower, reverse=True)
    ['h', 'G', 'f', 'e', 'D', 'c', 'B', 'a']
    

ایجاد پشته

«پشته» (Stack) ساختاری برای نگهداری موقت داده‌ها می‌باشد به شکلی که آخرین داده‌ای که در آن قرار می‌گیرد نخستین داده‌ای خواهد بود که خارج می‌گردد؛ این شیوه سازمان‌دهی LIFO یا Last In, First Out خوانده می‌شود. پشته تنها از دو عمل (یا متد) پشتیبانی می‌کند: push که داده‌ای را بالای تمام داده‌های موجود در آن قرار می‌دهد و pop که بالاترین داده را از آن خارج می‌کند.

ساختار پشته را می‌توان به سادگی با استفاده از نوع لیست در پایتون پیاده‌سازی کرد؛ به این صورت که برای یک شی لیست متد ()append معادل عمل push و متد ()pop نیز معادل عمل pop خواهد بود:

>>> stack = []

>>> stack.append(1)
>>> stack.append(2)
>>> stack.append(3)

>>> stack
[1, 2, 3]

>>> stack.pop()
3
>>> stack.pop()
2

>>> stack
[1]

تاپل

نوع «تاپِل» (Tuple) همانند نوع list است ولی با این تفاوت که تغییر پذیر نیست و عضوهای آن درون پرانتز () قرار داده می‌شوند:

>>> t = (1, 2, 3)
>>> type(t)
<class 'tuple'>

>>> t
(1, 2, 3)
>>> print(t)
(1, 2, 3)

>>> import sys
>>> sys.getsizeof(t)
72
>>> t = ()    # An empty tuple
>>> t
()

در انتهای شی تاپل تک عضوی می‌بایست یک نماد کاما قرار داد؛ به مانند: (,1). از آنجا که از پرانتز در عبارت‌ها نیز استفاده می‌شود؛ با این کار مفسر پایتون یک شی تاپل را از عبارت تشخیص می دهد:

>>> (4 + 1)
5

>>> a = (1)
>>> a
1
>>> type(a)
<class 'int'>
>>> t = (1,)
>>> t
(1,)
>>> type(t)
<class 'tuple'>

برای ایجاد شی تاپل حتی می‌توان از گذاردن پرانتز صرف نظر کرد و تنها اشیا (یا عبارت‌ها) را با کاما از یکدیگر جدا نمود:

>>> 5,
(5,)
>>> 1, 2 , 'a', 'b'
(1, 2, 'a', 'b')
>>> t = 'p', 'y'
>>> t
('p', 'y')
>>> 5 > 1, True == 0 , 7-2
(True, False, 5)

Note

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

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

>>> ('a', 'b', 'c') + (1 , 2, 3)
('a', 'b', 'c', 1, 2, 3)

>>> ('python', 0) * 3
('python', 0, 'python', 0, 'python', 0)
>>> t = ('p', 'y', [1, 2, 3], 5)

>>> 'p' in t
True
>>> 2 not in t
True
>>> [1, 2, 3] not in t
False
>>> (1, 'python') == (1, 'python')
True
>>> (1, 'python') == (1, 'PYTHON')
False
>>> t1 = (1, 2, 3)
>>> t2 = t1
>>> t2 == t1
True
>>> t2 is t1
True

>>> t1 = (1, 2, 3)
>>> t2 = (1, 2, 3)
>>> t2 == t1
True
>>> t2 is t1
False
>>> t = ('p', 'y', [1, 2, 3], 5)

>>> t[0]
'p'
>>> t[-1]
5
>>> t[:2]
('p', 'y')
>>> t[2]
[1, 2, 3]
>>> t[2][1]
2

>>> t[0] = 'j'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t = ('p', 'y', [1, 2, 3], 5)

>>> len(t)
4
>>> len(t[2])
3

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

>>> t = ('p', 'y', [1, 2, 3], 5)

>>> t[2][1] = 8
>>> t
('p', 'y', [1, 8, 3], 5)

همچنین به نمونه کدهای پایین در مورد Unpacking توجه نمایید:

>>> a, *b = (1.1, 2.2, 3.3, 4.4)

>>> a
1.1
>>> b
[2.2, 3.3, 4.4]
>>> a, *b, c = (1.1, 2.2, 3.3, 4.4)

>>> a
1.1
>>> b
[2.2, 3.3]
>>> c
4.4
>>> a, *b = [1.1, 2.2, (3.3, 4.4)]

>>> a
1.1
>>> b
[2.2, (3.3, 4.4)]
>>> a, *b, c = [1.1, 2.2, (3.3, 4.4)]

>>> a
1.1
>>> b
[2.2]
>>> c
(3.3, 4.4)
>>> a, *b, c = (1.1, 2.2, (3.3, 4.4))

>>> a
1.1
>>> b
[2.2]
>>> c
(3.3, 4.4)

حتما متوجه شده‌اید که عضوهای دنباله تنها با نوع لیست به نام نشانه‌گذاری شده انتساب داده می‌شود.

در هنگام انتساب متغیر تاپل به موضوع کپی نشدن اشیا تغییر پذیر توجه داشته باشید و در صورت نیاز از ماژول copy استفاده نمایید:

>>> t1 = ('p', 'y', [1, 2, 3], 5)

>>> t2 = t1                  # No Copy

>>> t1[2][1] = 8

>>> t1
('p', 'y', [1, 8, 3], 5)
>>> t2
('p', 'y', [1, 8, 3], 5)
>>> t1 = ('p', 'y', [1, 2, 3], 5)

>>> import copy
>>> t2 = copy.deepcopy(t1)    # Deep Copy

>>> t1[2][1] = 8

>>> t1
('p', 'y', [1, 8, 3], 5)
>>> t2
('p', 'y', [1, 2, 3], 5)

همانند شی لیست؛ شی تاپل نیز به دو متد ()index و ()count دسترسی دارد - این موضوع با استفاده از تابع ()dir قابل بررسی است:

>>> t = ('s', 'b', 'c', 'a', 's', 'b')
>>> dir(t)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'index']
>>> t.index('b')
1

>>> t.index('b', 2)
5

>>> t.index('z')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: tuple.index(x): x not in tuple
>>> t.count('a')
3
>>> t.count(5)
0

استفاده از راهنما را که فراموش نکرده‌اید؟!:

>>> t = ('s', 'b', 'c', 'a', 's', 'b')

>>> help(t.index)

Help on built-in function index:

index(...) method of builtins.tuple instance
    T.index(value, [start, [stop]]) -> integer -- return first index of value.
    Raises ValueError if the value is not present.
(END)

هر زمان که نیاز به اِعمال تغییر در شی تاپل باشد؛ می‌توان شی مورد نظر را به صورت موقت به یک شی لیست تبدیل کرد. در این حالت می‌توان از ویژگی و متدهای شی لیست بهره برد و تغییرات دلخواه را اعمال کرد و در نهایت با یک تبدیل نوع دیگر دوباره به شی تاپل بازگشت. برای این منظور می‌توان با استفاده از کلاس ()list یک دنباله - در اینجا یک شی تاپل - را به شی لیست تبدیل کرد و در طرف دیگر توسط کلاس ()tuple نیز یک دنباله - در اینجا یک شی لیست - را به شی تاپل تبدیل نمود:

>>> t = (1, 2, 3)
>>> type(t)
<class 'tuple'>

>>> L = list(t)
>>> type(L)
<class 'list'>
>>> L
[1, 2, 3]

>>> L.insert(0, 'python')
>>> L
['python', 1, 2, 3]

>>> t = tuple(L)
>>> t
('python', 1, 2, 3)

البته در مواقعی که می‌خواهید عضوهای درون یک شی تاپل را مرتب (Sort) کنید، نیازی به تبدیل نوع لیست نمی‌باشد و می‌توانید از تابع ()sorted استفاده نمایید؛ این تابع مطابق آنچه که پیش از این معرفی شد یک شی تاپل را می‌گیرد و یک شی لیست با همان عضوها اما مرتب شده را برمی‌گرداند:

>>> t = ('a', 'D', 'c', 'B', 'e', 'f', 'G', 'h')

>>> sorted(t, key=str.lower, reverse=True)
['h', 'G', 'f', 'e', 'D', 'c', 'B', 'a']

کلاس ()tuple بدون آرگومان یک شی تاپل خالی را ایجاد می‌کند:

>>> t = tuple()
>>> t
()
>>> type(t)
<class 'tuple'>

دیکشنری

یکی دیگر از انواع انعطاف پذیر آماده در پایتون «دیکشنری» (Dictionary) می‌باشد که با نام کوتاه شده dict ارایه شده است. اشیا نوع دیکشنری با استفاده از نماد آکولاد { } معرفی‌ می‌شوند و هر داده در آن به شکل یک جفت «کلید:مقدار» (key:value) ذخیره می‌گردد. از این نوع شی با عنوان شی mapping (نگاشت) پایتون نیز یاد می‌شود چرا که در این نوع هر شی «کلید» به یک شی «مقدار» map یا نگاشت داده می‌شود. شی دیکشنری دنباله نیست ولی تغییر پذیر بوده و «مقدار» هر عضو توسط «کلید» متناظر با آن دستیابی می‌شود. شی «مقدار» می‌تواند از هر نوعی باشد حتی یک شی دیکشنری دیگر ولی شی «کلید» تنها می‌بایست از انواع «تغییر ناپذیر» انتخاب شود و باید توجه داشت که تمام «کلید»‌های یک شی دیکشنری می‌بایست «یکتا» (Unique) باشند.

>>> d = {1:'One', 2:'Two', 3:'Three'}

>>> type(d)
<class 'dict'>

>>> d
{1: 'One', 2: 'Two', 3: 'Three'}

>>> print(d)
{1: 'One', 2: 'Two', 3: 'Three'}

>>> import sys
>>> sys.getsizeof(d)
288

در نمونه کد بالا؛ اشیا 1، 2 و 3 کلید‌های شی d هستند که به ترتیب با اشیای 'One' و 'Two' و 'Three' نگاشت شده‌اند. برای دستیابی هر مقدار شی دیکشنری dic از الگو [dic[key استفاده می‌کنیم که key در آن، کلید متصل به مقدار مورد نظر می‌باشد:

>>> d = {1:'One', 2:'Two', 3:'Three'}

>>> d[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 0

>>> d[1]
'One'

>>> d[3][2:]
'ree'

[d[3 اشاره به مقدار 'Three' دارد؛ و از آنجا که این شی یک دنباله است می‌توان به روش دنباله‌ها (یعنی با استفاده از اندیس موقعیت) عضوهای این شی را نیز دستیابی نماییم.

به چند مثال دیگر توجه نمایید:

>>> d = {}    # An empty dictionary
>>> d
{}
>>> d = {'name': 'Bob', 'age': 40}

>>> d['name']
'Bob'
>>> d['age']
40
>>> d = {'cb4f2': {'name': 'Bob', 'age': 40}}

>>> d['cb4f2']['age']
40

ساختار نوع دیکشنری مشابه «جدول درهم‌سازی» (Hash table) است و کاربرد‌های فراوانی در الگوریتم‌های جستجو دارد. از این نوع همچنین می‌توان برای سازماندهی و ذخیره داده‌ها بر روی فایل استفاده کرد؛ برای نمونه فرض کنید می‌خواهیم چند فیلم با بازی Benedict Cumberbatch را به گونه‌ای در اختیار داشته باشیم که بتوانیم آن‌ها را بر اساس سال ساخت دستیابی نماییم:

>>> benedict_cumberbatch = {'2014':'The Imitation Game',
...                         '2013':('The Fifth Estate', '12 Years a Slave', 'Star Trek Into Darkness'),
...                         '2012':'The Hobbit: An Unexpected Journey',
...                         '2011':('War Horse', ' Wreckers', 'Tinker Tailor Soldier Spy')}
>>>

>>> benedict_cumberbatch['2014']
'The Imitation Game'

>>> len(benedict_cumberbatch['2011'])
3

>>> benedict_cumberbatch['2011'][0]
'War Horse'

از تابع ()len نیز می‌توان برای به دست آوردن تعداد عضوهای شی دیکشنری (جفتِ کلید:مقدار) استفاده کرد:

>>> d = {1:'One', 2:'Two', 3:'Three'}

>>> len(d)
3

با انتساب یک مقدار جدید به یک کلید موجود از شی دیکشنری می‌توان مقدار آن کلید را تغییر داد و با انتساب یک مقدار به یک کلید جدید که در شی دیکشنری وجود ندارد یک عضو جدید به آن شی افزوده می‌شود:

>>> d = {'name': 'Bob', 'age': 40}

>>> d['name'] = 'Jhon'
>>> d
{'name': 'Jhon', 'age': 40}

>>> d['job'] = 'unemployed'
>>> d
{'name': 'Jhon', 'job': 'unemployed', 'age': 40}

برخلاف شی لیست یا تاپل (یا در کل دنباله‌ها) که داده‌هایی منظم (Ordered) هستند و ترتیب یا جایگاه قرار گرفتن عضوهای آن‌ها اهمیت دارد، یک شی دیکشنری این طور نیست و ترتیب عضوها در آن کاملا بی اهمیت است.

با استفاده از دستوری مشابه [del dic[key نیز می‌توان یک عضو شی دیکشنری را حذف کرد:

>>> d = {'name': 'Jhon', 'job': 'unemployed', 'age': 40}

>>> del d['job']
>>> d
{'name': 'Jhon', 'age': 40}

امکانی برای تغییر کلیدها وجود ندارد مگر آنکه عضو مورد نظر را حذف کرده و یک عضو جدید (همان مقدار ولی با کلیدی جدید) اضافه نمایید:

>>> d = {'name': 'Jhon', 'job': 'unemployed', 'age': 40}

>>> d['occupation'] = d['job']
>>> del d['job']

>>> d
{'name': 'Jhon', 'age': 40, 'occupation': 'unemployed'}

عملگرها برای دیکشنری

عملگرهای + و * برای اشیا دیکشنری تعریف نشده‌اند.

از عملگرهای عضویت می‌توان برای بررسی وجود یک کلید در شی دیکشنری استفاده کرد:

>>> 'job' in {'name': 'Bob', 'age': 40}
False

>>> 'job' not in {'name': 'Bob', 'age': 40}
True

در مورد عملکرد عملگر برابری == و عملگرهای هویت (is و is not) صحبت شده است؛ این عملگرها برای اشیا دیکشنری نیز کاربرد دارند.

کپی کردن

همانطور که گفته شد شی دیکشنری از انواع «تغییر پذیر» پایتون است و همان توضیحاتی که در مورد شی لیست بیان شد؛ در اینجا هم درست است و گاهی نیاز می‌شود که از ماژول copy برای کپی اشیا دیکشنری استفاده نماییم:

  • بدون کپی کردن:

    >>> d1 = {'name': 'Bob', 'age': 40}
    
    >>> d2 = d1
    
    >>> d1 == d2
    True
    >>> d1 is d2
    True
    
    >>> d1['age'] = 46
    
    >>> d1
    {'name': 'Bob', 'age': 46}
    >>> d2
    {'name': 'Bob', 'age': 46}
    
  • کپی سطحی:

    >>> d1 = {'name': 'Bob', 'age': 40}
    
    >>> import copy
    >>> d2 = copy.copy(d1)              # shallow copy
    
    >>> d1 == d2
    True
    >>> d1 is d2                        # False!
    False
    
    >>> d1['age'] = 46
    
    >>> d1
    {'name': 'Bob', 'age': 46}
    >>> d2
    {'name': 'Bob', 'age': 40}
    
    >>> d1 = {'names': ['Bob', 'Jhon'], 'ages': [40, 40]}
    
    >>> import copy
    >>> d2 = copy.copy(d1)              # shallow copy
    
    >>> d1 == d2
    True
    >>> d1 is d2                        # False!
    False
    
    >>> d1['ages'][0] = 46
    
    >>> d1
    {'ages': [46, 40], 'names': ['Bob', 'Jhon']}
    
    >>> # d2 has changed!
    >>> d2
    {'ages': [46, 40], 'names': ['Bob', 'Jhon']}
    
  • کپی عمیق:

    >>> d1 = {'names': ['Bob', 'Jhon'], 'ages': [40, 40]}
    
    >>> import copy
    >>> d2 = copy.deepcopy(d1)          # deep copy
    
    >>> d1 == d2
    True
    >>> d1 is d2                        # False!
    False
    
    >>> d1['ages'][0] = 46
    
    >>> d1
    {'ages': [46, 40], 'names': ['Bob', 'Jhon']}
    >>> d2
    {'ages': [40, 40], 'names': ['Bob', 'Jhon']}
    

تبدیل به شی دیکشنری

برای تبدیل دیگر اشیا به نوع دیکشنری یا در کل ایجاد شی دیکشنری از کلاس ()dict [اسناد پایتون] استفاده می‌شود. توجه داشته باشید که عضوهای شی دیکشنری از طریق آرگومان‌ها و به شکل «کلید=مقدار» به کلاس فرستاده می‌شوند:

>>> d = dict(one=1, two=2, three=3)

>>> d
{'two': 2, 'one': 1, 'three': 3}
>>> d['one']
1

در این حالت برای انتخاب کلیدها باید قوانین انتخاب نام در پایتون را رعایت نماییم؛ برای مثال کلیدی که با عدد شروع شود مجاز نمی‌باشد.

برای فرستادن کلیدها و مقدارها می‌توانیم از تابع ()zip [اسناد پایتون] استفاده کنیم و خروجی این تابع را به عنوان آرگومان به کلاس dict ارسال کنیم. می‌توان اینگونه تصور کرد که این تابع تعدادی شی دنباله را می‌گیرد و عضوهای نظیر به نظیر آن‌ها را در کنار هم قرار می‌دهد؛ این دنباله‌ها باید تعداد عضو برابری داشته باشند؛ چرا که عضوهای اضافی هر دنباله نادیده گرفته می‌شود. خروجی ()zip یک شی جدید از نوع zip است و برای مشاهده معمولا آن را به نوع لیست تبدیل می‌کنند:

>>> k = [1, 2, 3, 4, 5]
>>> v = ['x', 'y', 'z']

>>> z = zip(k, v)

>>> z
<zip object at 0x7eff1d263548>

>>> type(z)
<class 'zip'>

>>> list(z)
[(1, 'x'), (2, 'y'), (3, 'z')]
>>> k = (1, 2, 3)
>>> v = ('One', 'Two', 'Three')

>>> d = dict(zip(k, v))

>>> d
{1: 'One', 2: 'Two', 3: 'Three'}

در آینده باز هم از تابع ()zip استفاده خواهیم کرد.

برخی از متدهای کاربردی یک شی دیکشنری

  • ()items [اسناد پایتون] تمام عضوهای شی را برمی‌گرداند - ()values [اسناد پایتون] تمام مقدارهای موجود در شی را بر می‌گرداند - ()keys [اسناد پایتون] تمام کلیدهای موجود در شی را بر می‌گرداند:

    >>> # Python 3.x
    
    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.items()
    dict_items([(1, 'One'), (2, 'Two'), (3, 'Three')])
    
    >>> d.values()
    dict_values(['One', 'Two', 'Three'])
    
    >>> d.keys()
    dict_keys([1, 2, 3])
    

    توجه داشته باشید که در نسخه‌های 3x پایتون خروجی این متدها از نوع متفاوتی است که با استفاده از ()type می‌توانید مشاهده کنید؛ این نوع dict_view نامیده می‌شود [اسناد پایتون 3x]. این متدها یک کپی از داده‌های مورد نظر (عضوها یا مقدارها یا کلیدها) را بر نمی‌گردانند بلکه می‌توان گفت پنجره‌ای برای مشاهده آنچه که هست باز می‌کنند و در هر زمان که این داده‌ها تغییر کنند این خروجی‌ها نیز تغییر می‌کنند. برای مشاهده بهتر این خروجی‌ها می‌توانید آن‌ها را به نوع لیست تبدیل نمایید:

    >>> list(d.items())
    [(1, 'One'), (2, 'Two'), (3, 'Three')]
    
    >>> list(d.values())
    ['One', 'Two', 'Three']
    
    >>> list(d.keys())
    [1, 2, 3]
    

    این متدها در پایتون 2x چنین خروجی ندارند و تنها یکی کپی از داده‌ها را برمی‌گردانند. البته در نسخه 2.7 متدهای معادلی با عنوان‌های ()viewitems [اسناد پایتون] و ()viewvalues [اسناد پایتون] و ()viewkeys [اسناد پایتون] پورت شده است:

    >>> # Python 2.7
    
    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.viewitems()
    dict_items([(1, 'One'), (2, 'Two'), (3, 'Three')])
    
    >>> d.viewvalues()
    dict_values(['One', 'Two', 'Three'])
    
    >>> d.viewkeys()
    dict_keys([1, 2, 3])
    
    >>> # Python 2.x
    
    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.items()
    [(1, 'One'), (2, 'Two'), (3, 'Three')]
    
    >>> d.values()
    ['One', 'Two', 'Three']
    
    >>> d.keys()
    [1, 2, 3]
    
  • ()clear [اسناد پایتون] - تمام عضوهای یک شی دیکشنری را حذف می‌کند:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.clear()
    >>> d
    {}
    
  • ()copy [اسناد پایتون] - این متد یک کپی سطحی از شی برمی‌گرداند:

    >>> d1 = {'name':'Bob'}
    
    >>> d2 = d1.copy()
    
    >>> d1 is d2
    False
    
  • (fromkeys(seq [اسناد پایتون] - یک دنباله از کلیدها را دریافت و یک شی جدید دیکشنری با استفاده از آن‌ها ایجاد می‌کند؛ البته کلیدهای این شی فاقد مقدار هستند که می‌بایست در زمانی دیگر به آن‌ها مقدار داد:

    >>> k = (1, 2, 3)   # or k=[1, 2, 3]  or  k='123'
    
    >>> dict.fromkeys(k)
    {1: None, 2: None, 3: None}
    

    توجه داشته باشید که این متد توسط خود کلاس dict فراخوانی می‌شود.

    این متد یک آرگومان اختیاری نیز دارد که توسط آن می‌توان یک شی را به عنوان «مقدار» پیش‌فرض کلید‌ها تعیین نمود:

    >>> k = (1, 2, 3)
    
    >>> dict.fromkeys(k, '-*-')
    {1: '-*-', 2: '-*-', 3: '-*-'}
    
  • (pop(key [اسناد پایتون] - عضو دارنده کلید key را حذف و مقدار آن را برمی‌گرداند. چنانچه عضوی با این کلید یافت نشود شی پیش‌فرض تعیین شده (آرگومان دوم که اختیاری است) را برمی‌گرداند و اگر این آرگومان ارسال نشده باشد یک خطا گزارش می‌دهد:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.pop(2)
    'Two'
    >>> d
    {1: 'One', 3: 'Three'}
    
    >>> d.pop(2)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    KeyError: 2
    
    >>> d.pop(2, 'Oops!')
    'Oops!'
    

    از این متد می‌توان برای تغییر راحت‌تر کلیدها استفاده کرد!:

    >>> d = {'name': 'Jhon', 'job': 'unemployed', 'age': 40}
    
    >>> d['occupation'] = d.pop('job')
    
    >>> d
    {'name': 'Jhon', 'age': 40, 'occupation': 'unemployed'}
    

    متد مشابه دیگری نیز با نام ()popitem [اسناد پایتون] - که بدون آرگومان است - در دسترس می‌باشد؛ این متد در هر فراخوانی یک عضو از شی مورد نظر را به صورت دلخواه حذف و به شکل تاپل (key, value) برمی‌گرداند و چنانچه دیکشنری خالی باشد یک خطا KeyError گزارش می‌دهد:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.popitem()
    (1, 'One')
    
  • (get(key [اسناد پایتون] - مقدار مربوط به کلید key را برمی‌گرداند. چنانچه درون شی مورد نظر هیچ عضوی با این کلید وجود نداشته باشد شی پیش‌فرض تعیین شده (آرگومان دوم که اختیاری است) را برمی‌گرداند و اگر این آرگومان ارسال نشده باشد هیچ خطایی گزارش نمی‌دهد:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.get(1)
    'One'
    
    >>> d.get(0)
    >>>
    
    >>> d.get(0, False)
    False
    
  • (setdefault(key [اسناد پایتون] - مقدار مربوط به کلید key را برمی‌گرداند. چنانچه عضوی با این کلید درون شی مورد نظر وجود نداشته باشد، کلید را به همراه مقدار پیش‌فرض تعیین شده (آرگومان دوم که اختیاری است) درون شی اضافه می‌کند و خود این مقدار را برمی‌گرداند؛ اگر آرگومان دوم ارسال نشده باشد به صورت پیش‌فرض مقدار None در نظر گرفته خواهد شد:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d.setdefault(1)
    'One'
    >>> d
    {1: 'One', 2: 'Two', 3: 'Three'}
    
    >>> d.setdefault(5)
    >>> d
    {1: 'One', 2: 'Two', 3: 'Three', 5: None}
    
    >>> d.setdefault(7, 'Seven')
    'Seven'
    >>> d
    {1: 'One', 2: 'Two', 3: 'Three', 5: None, 7: 'Seven'}
    
  • ()update [اسناد پایتون] - یک شی دیکشنری دیگر را به عنوان آرگومان می‌گیرد و عضوهای شی مورد نظر را بر اساس آن تغییر می‌دهد:

    >>> d = {1:'One', 2:'Two', 3:'Three'}
    
    >>> d2 = {5:'Five', 6:'Six'}
    >>> d.update(d2)
    >>> d
    {1: 'One', 2: 'Two', 3: 'Three', 5: 'Five', 6: 'Six'}
    
    >>> d3 = {1:'0001'}
    >>> d.update(d3)
    >>> d
    {1: '0001', 2: 'Two', 3: 'Three', 5: 'Five', 6: 'Six'}
    

مجموعه

«مجموعه» (Set) از انواع «نامنظم» (Unordered) و «تغییر پذیر» (Mutable) پایتون است که معادل مفهوم مجموعه در ریاضیات می‌باشد. هر عضو مجموعه می‌بایست یکتا و یکی از انواع «تغییر ناپذیر» باشد. نوع مجموعه یا set در نسخه‌ 3x با کمی تفاوت ارایه شده است. در نسخه‌های 2x تنها می‌توان با استفاده از کلاس ()set [اسناد پایتون] اقدام به ایجاد این اشیا نمود در حالی که در پایتون 3x این کار به سادگی و تنها با استفاده از نماد آکولاد { } نیز امکان پذیر شده است؛ (البته این ویژگی به نسخه 2.7 هم پورت شده است). در دو نمونه کد پایین به چگونگی تعریف و نمایش شی مجموعه توجه نمایید:

نسخه‌های 2x:

>>> L = [1, 2, 3, 4, 5]

>>> s = set(L)

>>> type(s)
<type 'set'>

>>> s
set([1, 2, 3, 4, 5])

>>> print s
set([1, 2, 3, 4, 5])
>>> s = {1, 2, 3, 4, 5}    # Python 2.7

>>> type(s)
<type 'set'>

>>> s
set([1, 2, 3, 4, 5])

نسخه‌های 3x:

>>> L = [1, 2, 3, 4, 5]

>>> s = set(L)

>>> type(s)
<class 'set'>

>>> s
{1, 2, 3, 4, 5}

>>> print(s)
{1, 2, 3, 4, 5}
>>> s = {1, 2, 3, 4, 5}

>>> type(s)
<class 'set'>

>>> s
{1, 2, 3, 4, 5}

هیچ سینتکس خاصی برای ایجاد یا بیان یک شی خالی از نوع مجموعه وجود ندارد و تنها می‌بایست از کلاس ()set - بدون آرگومان - استفاده کرد. توجه داشته باشید که {} بیانگر یک شی دیکشنری خالی است و نه یک مجموعه خالی:

>>> a = {}       # Python 2.x
>>> type(a)
<type 'dict'>

>>> b = set()
>>> type(b)
<type 'set'>

>>> b
set([])
>>> a = {}       # Python 3.x
>>> type(a)
<class 'dict'>

>>> b = set()
>>> type(b)
<class 'set'>

>>> b
set()

از تابع ()len می‌توان برای به دست آوردن تعداد عضوهای یک شی مجموعه نیز استفاده کرد:

>>> s = {1, 2, 3, 4, 5}
>>> len(s)
5

عملگرها برای مجموعه

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

  • | اجتماع (Union): مانند A | B که حاصل آن مجموعه‌ای می‌باشد که تمام عضوهای مجموعه A و مجموعه B را داشته باشد و هیچ عضو اضافه دیگری نداشته باشد.

    >>> A | B
    {'w', 'y', 'q', 't', 'r', 'z', 's', 'v', 'u', 'x'}
    
  • & اشتراک (Intersection): مانند A & B که حاصل آن مجموعه‌ای می‌باشد که تنها شامل عضوهایی است که هم در مجموعه A هستند و هم در مجموعه B:

    >>> A & B
    {'w', 'v', 'u'}
    
  • - تفاضل (Difference): مانند A - B که حاصل آن مجموعه‌ای می‌باشد که تنها شامل عضوهایی از مجموعه A است كه در مجموعه B نيستند:

    >>> A = {'u', 'v', 'w', 'x', 'y', 'z'}
    >>> B = {'q', 'r', 's', 't', 'u', 'v', 'w',}
    
    >>> A - B
    {'z', 'y', 'x'}
    
  • ^ تفاضل متقارن (Symmetric difference): مانند A ^ B که حاصل آن مجموعه‌ای می‌باشد که برابر اجتماع ِ تفاضل A از B و تفاضل B از A می‌باشد یعنی: (A-B) | (B-A):

    >>> A ^ B
    {'q', 'y', 't', 'r', 'z', 's', 'x'}
    
    >>> (A-B) | (B-A)
    {'y', 'q', 't', 'r', 'z', 'x', 's'}
    

    تفاضل متقارن را می‌توان به صورت پایین نیز تعریف کرد:

    >>> (A|B) - (B&A)
    {'y', 'q', 't', 'r', 'z', 's', 'x'}
    
  • > زیرمجموعه (Subset): مانند A < B که اگر مجموعه A زیرمجموعه‌ای از مجموعه B باشد مقدار True را برمی‌گرداند. در مقابل عملگر < قرار دارد که برای مثال در عبارت A > B اگر مجموعه A یک Superset برای مجموعه B باشد مقدار True را برمی‌گرداند:

    >>> A = {1, 2, 3, 4, 5}
    >>> B = {1, 2, 3}
    
    >>> A < B
    False
    
    >>> A > B
    True
    

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

>>> A = {'a', 'b', 'c'}

>>> 'a' in A
True
>>> 'c' not in A
False
>>> A = {1, 2, 3, 4, 5}
>>> B = {1, 2, 3}

>>> A == B
False

>>> C = A

>>> A == C
True

>>> A is C
True

برخی از متدهای کاربردی یک شی مجموعه

  • ()union [اسناد پایتون] - تعدادی شی مجموعه را دریافت می‌کند و یک مجموعه جدید که برابر اجتماع شی مورد نظر با آن‌ها است را برمی‌گرداند:

    >>> A = {'a', 'b', 'c'}
    >>> B = {1, 2, 3}
    
    >>> {'t', 1, 'a'}.union(A, B)
    {'a', 1, 2, 3, 't', 'b', 'c'}
    
    >>> {'t', 1, 'a'} | A | B
    {1, 2, 3, 'b', 't', 'a', 'c'}
    

    به صورت مشابه می‌توان از متدهای ()intersection [اسناد پایتون] برای اشتراک، ()difference [اسناد پایتون] برای تفاضل، ()symmetric_difference [اسناد پایتون] - که تک آرگومانی است - برای تفاضل متقارن، ()issubset [اسناد پایتون] و ()issuperset [اسناد پایتون] - که هر دو تک آرگومانی هستند - برای بررسی زیرمجموعه یا Superset بودن استفاده کرد.

  • ()clear [اسناد پایتون] - تمام عضوهای یک شی مجموعه را حذف می‌کند:

    >>> A = {'a', 'b', 'c'}
    
    >>> A.clear()
    >>> A
    set()
    
  • (add(x [اسناد پایتون] - شی تغییر ناپذیر x را در صورتی که از قبل درون شی مجموعه مورد نظر وجود نداشته باشد به آن اضافه می‌کند:

    >>> A = {'a', 'b', 'c'}
    
    >>> A.add(1)
    >>> A
    {'a', 'c', 1, 'b'}
    
  • (remove(x [اسناد پایتون] - عضو x را از شی مجموعه مورد نظر حذف می‌کند. در صورتی که x درون مجموعه وجود نداشته باشد یک خطا گزارش می‌دهد:

    >>> A = {'a', 'b', 'c', 1}
    
    >>> A.remove(1)
    >>> A
    {'c', 'a', 'b'}
    
    >>> A.remove(1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    KeyError: 1
    

    متد مشابه دیگری نیز با الگو (discard(x [اسناد پایتون] وجود دارد که این متد چنانچه x وجود داشته باشد آن را حذف می‌کند؛ بنابرین در صورت نبودن x خطایی گزارش نمی‌گردد:

    >>> A = {'c', 'a', 'b'}
    
    >>> A.discard(1)
    >>> A
    {'b', 'a', 'c'}
    
  • ()pop [اسناد پایتون] - این متد آرگومانی ندارد و به صورت دلخواه یک عضو از مجموعه را حذف و به عنوان خروجی برمی‌گرداند. در مواردی که مجموعه خالی باشد یک خطا گزارش می گردد:

    >>> A = {'a', 'b', 'c'}
    
    >>> A.pop()
    'a'
    
    >>> A.pop()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    KeyError: 'pop from an empty set'
    

frozenset

همانطور که پیش از این بیان شد مجموعه یک شی «تغییر پذیر» است با عضوهای «تغییر ناپذیر» و به دلیل همین تغییر پذیری است که می‌توانیم به سادگی توسط متدها عضوی به آن افزوده یا حذف نماییم. ”frozenset“ یک نوع جدید مجموعه است. همانگونه که می‌توانیم یک شی تاپل را معادل یک شی لیست تغییر ناپذیر تصویر کنیم؛ frozenset را نیز می‌توان یک شی مجموعه تغییر ناپذیر تصور کرد. نوع frozenset همان نوع set است، با تمام ویژگی‌های آن به غیر از تغییر پذیری که با استفاده از کلاس ()frozenset ایجاد می‌گردد:

نسخه‌های 2x:

>>> L = [1, 2, 3]

>>> A = frozenset(L)

>>> type(A)
<type 'frozenset'>

>>> A
frozenset([1, 2, 3])

نسخه‌های 3x:

>>> L =[1, 2, 3]

>>> A = frozenset(L)

>>> type(A)
<class 'frozenset'>

>>> A
frozenset({1, 2, 3})

با استفاده از تابع ()dir می‌توان متوجه متدهای در دسترس شی frozenset شد:

>>> dir(frozenset)    # Python 3.x
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'copy', 'difference', 'intersection', 'isdisjoint', 'issubset', 'issuperset', 'symmetric_difference', 'union']

NoneType

این نوع شی فاقد مقدار است و با انتساب ثابت None [اسناد پایتون] به یک نام ایجاد می‌گردد:

>>> n = None

>>> type(n)
<class 'NoneType'>

>>> print(n)
None

>>> import sys
>>> sys.getsizeof(a)
16

>>> n = 5
>>> type(n)
<class 'int'>

None در پایتون 3x جزو کلمه‌های کلیدی (keywords) تعریف شده است.

دسته‌بندی

در این بخش به دسته‌بندی انواع شی بر اساس برخی از تعریف‌های پایتون پرداخته شده است.

  • انواع عددی (Numeric Types):

    1
    2
    3
    4
    5
    6
    7
    - int
    - long (2.x)
    - float
    - complex
    - Decimal
    - Fraction
    - bool
    
  • انواع دنباله (Sequence Types):

    1
    2
    3
    4
    5
    6
    - str
    - unicode (2.x)
    - bytes (3.x)
    - bytearray (3.x/2.6+)
    - tuple
    - list
    
  • انواع تغییر ناپذیر (Immutable Types):

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    - int
    - long (2.x)
    - float
    - complex
    - Decimal
    - Fraction
    - bool
    - str
    - unicode (2.x)
    - bytes (3.x)
    - tuple
    - frozenset
    
  • انواع تغییر پذیر (Mutable Types):

    1
    2
    3
    4
    - bytearray (3.x/2.6+)
    - list
    - dict
    - set
    
  • انواع نگاشت (Mapping Types):

    1
    - dict
    
  • انواع مجموعه (Set Types):

    1
    2
    - set
    - frozenset
    
  • برخی دیگر:

    1
    2
    3
    - zip
    - dict_views
    - NoneType
    

در درس‌های بعد نیز با انواع آماده (Built-in) دیگری آشنا خواهیم شد.



😊 امیدوارم مفید بوده باشه

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

درس ۰۹: دستورهای کنترلی

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

این درس به بررسی دستورهای کنترلی پایتون در دو بخش «انتخاب» و «تکرار» اختصاص یافته است.

سطح: مقدماتی



انتخاب

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

دستور if

۱. ساختار ساده (تک انتخابی)

این ساختار یک دستور مرکب است که در سرآیند آن یک «شرط» (Condition) بررسی می‌گردد و تنها در صورتی که این شرط برقرار باشد بدنه اجرا خواهد گشت؛ در غیر این صورت مفسر از اجرای دستور(های) بدنه صرف نظر کرده و به سراغ نخستین دستور بعد از این ساختار می‌رود. این ساختار با استفاده از کلمه کلیدی if و الگویی مشابه پایین پیاده‌سازی می‌گردد:

if condition :
    StatementBlock

منظور از شرط عبارتی است که می‌توان آن را به یکی از مقدار‌های بولی (True یا False) ارزیابی نمود؛ در اینجا اگر شرط برابر True ارزیابی گردد بخش بدنه دستور if اجرا می‌گردد. به نمونه کدهای پایین توجه نمایید:

>>> a = 5
>>> b = 3
>>> if a > b:
...     print("a is greater than b")
...
a is greater than b
>>>
>>> if a == b:
...     print("a is equal to b")
...
>>>

در نمونه کد بالا شرط برابر False ارزیابی شده و از اجرای بدنه خودداری شده است؛ بنابراین هیچ متنی در خروجی چاپ نشده است.

>>> if a > b and a >= 0:
...     print("a is positive and greater than b")
...
a is positive and greater than b
>>>

همانطور که در نمونه کد بالا نیز مشاهده می‌شود می‌توان از عملگرهای منطقی (not ،or ،and) برای بررسی برقرار بودن (یا نبودن) همزمان چندین شرط بهره گرفت.

می‌دانیم که: عدد یک و تمام اعداد مخالف صفر در پایتون برابر مقدار بولی True و عدد صفر، اشیا خالی به مانند "" یا [] برابر مقدار False ارزیابی می‌شوند:

>>> if 1:
...     print("Condition is True")
...
Condition is True
>>>
>>> if []:
...     print("Condition is True")
...
>>>
>>> a = False

>>> if not a:
...     print("Condition is True")
...
Condition is True
>>>

می‌توان از ساختار if به شکل تودرتو (Nested) نیز بهره برد. در این حالت بدنه دستور if حاوی یک یا چند دستور if دیگر می‌شود که البته آن‌ها نیز می‌توانند حاوی دستور‌های if دیگری در بدنه خود باشند:

>>> d = {'name': 'Jhon', 'job': 'programmer', 'age': 40}

>>> if d['age'] >= 40:
...     if d['job'] == 'programmer':
...         print(d['name'])
...
Jhon
>>>

۲. ساختار همراه با else (دو انتخابی)

با استفاده از کلمه‌ کلیدی else می‌توان بلاکی را برای اجرا در حالتی که شرط برقرار نیست - زمانی که شرط if برابر مقدار بولی False ارزیابی می‌گردد - تعیین کرد. else یک بخش جدا است که سرآیند و بدنه مخصوص به خود را دارد؛ این سرآیند می‌بایست فاقد هر گونه شرطی باشد:

>>> a = False

>>> if a:
...     print("Condition is True")
... else:
...     print("Condition is False")
...
Condition is False
>>>
>>> a = 7

>>> if a in [1, 2, 3]:
...     print("a is in list")
... else:
...     print("a is not in list")
...
a is not in list
>>>
>>> d = {'name': 'Bob', 'job': 'designer', 'age': 45}

>>> if d['age'] >= 40:
...     if d['job'] == 'programmer':
...         print(d['name'])
...     else:
...         print(d['name'], d['job'])  # Will be executed
... else:
...     if d['age'] >= 35:
...         print(d['name'], 'Between 35 and 40 years old')
...     else:
...         print(d['name'], 'Less than 35 years old')
...
Bob designer
>>>

۳. ساختار همراه با elif (چند انتخابی)

دستور if را می‌توان گسترش داد و بخش‌های بیشتری را با شرط‌های گوناگون ایجاد نمود؛ به این صورت که ابتدا شرط بخش if بررسی می‌گردد و چنانچه برابر True ارزیابی نگردد، شرط مربوط به نختسین بخش elif بررسی می‌گردد که اگر باز هم برابر True نشود شرط بخش elif بعدی بررسی خواهد شد و به همین صورت ادامه می‌یابد؛ در انتها نیز اگر هیچ کدام از شرط‌ها (if و elif) برابر True نشوند آنگاه بدنه مربوط به بخش else (در صورت وجود) اجرا می‌گردد. الگوی این ساختار مانند پایین است:

if condition_1:
    statements
elif condition_2:
    statements
elif condition_3:
    statements
else:
    statements
  • هر elif یک بخش جدا است که سرآیند و بدنه مخصوص به خود را دارد.
  • تعداد بخش‌های elif اختیاری است و محدودیتی در آن وجود ندارد.
  • بخش elif نمی‌تواند قبل از if یا بعد از else قرار بگیرد.
  • در این ساختار نیز وجود بخش else اختیاری است.

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

>>> percent = 60

>>> if percent == 100:
...    print('100 %')
... elif percent >= 75:
...    print('75-100 %')
... elif percent >= 50:
...    print('50-75 %')
... elif percent >= 25:
...    print('25-50 %')
... else:
...    print('less than 25 %')
...
50-75 %
>>>

اگر بخواهیم نمونه کد بالا را با استفاده از if های تودرتو پیاده‌سازی نماییم به شکل پایین خواهد شد:

>>> percent = 60

>>> if percent == 100:
...     print('100 %')
... else:
...     if percent >= 75:
...         print('75-100 %')
...     else:
...         if percent >= 50:
...             print('50-75 %')
...         else:
...             if percent >= 25:
...                 print('25-50 %')
...             else:
...                 print('less than 25 %')
...
50-75 %
>>>

چنانچه قصد دارید تمام شرط‌های مورد نظر بررسی شوند می‌توانید از چند دستور if به شکل متوالی استفاده نمایید:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# File: Documents/script.py
# Python 3.x

import sys

# Get script argument and convert it to an integer
percent = int(sys.argv[1])

if percent == 100:
    print('100 %')
if percent >= 75:
    print('75-100 %')
if percent >= 50:
    print('50-75 %')
if percent >= 25:
    print('25-50 %')
if percent < 25:
    print('less than 25 %')
user> cd Documents/

user> python script.py 60
50-75 %
25-50 %

دستور switch/case

در صورتی که سابقه برنامه‌نویسی با زبان‌های دیگری همچون C و Java را داشته باشید حتما با دستور switch نیز آشنا هستید؛ این دستور در زبان پایتون پیاده‌سازی نشده است.

دستور switch مقداری را دریافت می‌کند و سپس آن را با مقدارهای هر case درون ساختار خود به ترتیب مقایسه می‌کند؛ در صورتی که این مقدار با یکی از case ها برابر باشد، دستورهای مرتبط با آن case را اجرا کرده و از بررسی دیگر case ها صرف نظر می‌کند. همچنین اگر مقدار دریافتی با هیچ یک از case ها مطابقت نداشته باشد دستورهای مربوط به بخش default (در صورت وجود) را اجرا می‌کند. در پایین نمونه‌ایی از این دستور در زبان Java آورده شده است:

int success;
char grade = 'B';
switch (grade) {
            case 'A':
                    System.out.println("Excellent grade");
                    success = 1;
                    break;
            case 'B':
                    System.out.println("Very good grade");
                    success = 1;
                    break;
            case 'C':
                    System.out.println("Good grade");
                    success = 1;
                    break;
            case 'D':
            case 'E':
            case 'F':
                    System.out.println("Low grade");
                    success = 0;
                    break;
            default:
                    System.out.println("Invalid grade");
                    success = -1;
                    break;
}

برای پیاده‌سازی چنین ساختاری در پایتون می‌توان از if/elif/else استفاده کرد:

grade = 'B'
if grade == 'A':
    print('Excellent grade')
    success = 1
elif grade == 'B':
    print('Very good grade')
    success = 1
elif grade in ('D', 'E', 'F'):
    print('Low grade')
    success = 0
else:
    print('Invalid grade')
    success = -1

تکرار

گاهی نیاز پیدا می‌کنیم که بلاکی را چندین بار پشت سرهم اجرا نماییم. به ساختار تکرار «حلقه» (Loop) گفته می‌شود؛ در ادامه به بررسی ساختار دو حلقه ارایه شده در زبان پایتون خواهیم پرداخت.

دستور while

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

while condition :
    statements

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

>>> while 1:
...     print('Press Ctrl+C to stop!')
...
Press Ctrl+C to stop!
Press Ctrl+C to stop!
Press Ctrl+C to stop!
[..]

ولی در نمونه کد پایین مقدار متغیر a از درون بدنه کنترل و در هر بار اجرا یک واحد کاهش می‌یابد؛ بنابراین اجرای حلقه تنها تا زمانی که شرط نقض نشده باشد ادامه می‌یابد:

>>> a = 5

>>> while a > 0:
...     print(a)
...     a -= 1   # a = a - 1
...
5
4
3
2
1
>>>

در نمونه کد بالا بهتر می‌بود به جای عبارت a > 0 تنها از خود متغیر a به عنوان شرط حلقه استفاده نماییم؛ چرا که در هر مرتبه اجرا یک واحد از آن کم می‌شود و با رسیدن به مقدار صفر به صورت خودکار توسط مفسر پایتون به مقدار False ارزیابی و تکرار اجرای بدنه حلقه متوقف می‌گردد.

به عنوان نمونه‌ای دیگر،‌ فاکتوریل (Factorial) عدد ۱۰ را می‌توان به صورت پایین محاسبه کرد:

>>> a = 10

>>> n = 1
>>> while a >= 1:
...     n = n * a
...     a -= 1
...
>>> print(n)
3628800

دستور continue

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

>>> n = 10

>>> while n:
...     n -= 1
...     if n % 2 != 0:
...         continue
...     print(n)
...
8
6
4
2
0
>>>

البته مثال بالا را بدون continue نیز می‌توان به انجام رساند:

>>> n = 10
>>> while n:
...     n -= 1
...     if n % 2 == 0:
...         print(n)

دستور break

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

>>> counter = 0

>>> while counter < 100:
...     if counter == 4:
...         break
...     print(counter)
...     counter += 1
...
0
1
2
3
>>>

در while نیز می‌شود از بخش else استفاده نماییم؛ به این صورت که اگر حلقه به صورت طبیعی پایان پذیرد - و نه توسط دستور break - آنگاه بدنه else اجرا می‌گردد.

نمونه کد پایین بررسی می‌کند که آیا عدد n یک «عدد اول» (Prime number) هست یا خیر؛ این اعداد بزرگتر از یک بوده و به جز خود و عدد یک بر هیچ عدد دیگری بخش پذیر نیستند. بنابراین اگر عددی کوچکتر از n (به جز یک) پیدا شود که بر آن بخشپذیر باشد (یعنی باقی مانده تقسیم بر آن صفر باشد) اول نبودن عدد n ثابت می‌شود و حلقه به کمک دستور break متوقف می‌گردد:

>>> n = 23
>>> i = 2
>>> while i < n:
...     if n % i == 0:
...         print(n, "is not a prime number")
...         break
...     i += 1
... else:
...     print(n, "is a prime number")
...
23 is a prime number
>>>

دستور for

این دستور مرکب یک حلقه تکرار است که بر اساس تعداد عضوهای یک شی دنباله یا در حالت کلی‌تر یک شی تکرارکننده (iterator) - که در انتها بررسی خواهد شد - اجرای دستورهای بدنه را تکرار می‌کند. الگوی این دستور به شکل پایین است:

for target in object:
    statements

هر حلقه for دقیقا به تعداد عضوهای شی object تکرار می‌گردد؛ هر بار یک عضو از دنباله (یا تکرارکننده) object با حفظ ترتیب اعضا به متغیر target انتساب داده می‌شود و یک مرتبه بدنه اجرا می‌گردد؛ این روند تا پایان پیمایش عضوهای object ادامه می‌یابد. از متغیر target می‌توان در داخل بدنه استفاده کرد که در مرتبه نخست اجرای حلقه به عضو یکم و با اجراهای بعدی به عضوهای بعدی از object اشاره خواهد داشت. به نمونه کدهای پایین توجه نمایید:

>>> for item in [1, 2, 3]:
...     print(item)
...
1
2
3
>>>
>>> for char in 'python':
...     print(char)
...
p
y
t
h
o
n
>>>
>>> L = [(1, 2), (3,4), (5, 6)]

>>> for a, b in L:
...     print(a, b)
...
1 2
3 4
5 6
>>>

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

>>> L = [(1, 2), (3,4), (5, 6)]

>>> for both in L:
...     a, b = both
...     print(a, b)
...
1 2
3 4
5 6
>>>

در نمونه کد بالا، متغیر both در هر مرتبه تکرار به یک شی تاپل اشاره دارد.

>>> a, *b, c = (1, 2, 3, 4)
>>> a, b, c
(1, [2, 3], 4)

>>> for a, *b, c in [(1, 2, 3, 4), (5, 6, 7, 8)]:
...     print(a, b, c)
...
1 [2, 3] 4
5 [6, 7] 8
>>>
>>> d = {'name': 'Jhon', 'job': 'designer', 'age': 40}

>>> for key in d:
...     print(key)
...
name
job
age
>>>

در حالت عادی برای یک شی دیکشنری،‌ کلیدهای آن پیمایش می‌شوند.

>>> d = {'name': 'Jhon', 'job': 'designer', 'age': 40}

>>> d.items()
dict_items([('name', 'Jhon'), ('job', 'designer'), ('age', 40)])

>>> for key, value in d.items():
...     print(key, value)
...
name Jhon
job designer
age 40
>>>

Note

معمولا از حلقه for در مواقعی که تعداد تکرار مشخص باشد و از حلقه while زمانی که تعداد تکرار نامشخص است استفاده می‌شود.

مانند حلقه while در اینجا نیز می‌توان از دستورهای continue و break استفاده کرد. همچنین حلقه for می‌تواند شامل بخش else باشد.

مثال تشخیص عدد اول در حلقه while را با استفاده از حلقه for بازنویسی می‌کنیم:

>>> n = 23

>>> 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")
...
23 is a prime number
>>>

تابع (range(stop:

این تابع [اسناد پایتون 3x] یک شی از نوع range را برمی‌گرداند؛ این شی یک دنباله تغییر ناپذیر است که معمولا از آن برای پیمایش در حلقه for استفاده می‌شود. با تبدیل شی range به نوع لیست خواهیم دید که این شی یک دنباله مرتب از اعداد صفر تا آرگومان stop (و نه خود آن) است؛ آرگومان stop می‌بایست یک عدد صحیح مثبت باشد:

>>> r = range(10)    # Python 3.x

>>> type(r)
<class 'range'>

>>> r
range(10)

>>> print(r)
range(10)

>>> list(r)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> tuple(r)
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

>>> import sys
>>> sys.getsizeof(r)
48

این تابع را می‌توان به صورت دو آرگومانی ((range(start, stop) نیز فراخوانی نمود که آرگومان یکم عدد آغازین دنباله را تعیین می‌کند و می‌تواند یک عدد منفی نیز باشد:

>>> list(range(2, 10))
[2, 3, 4, 5, 6, 7, 8, 9]

>>> list(range(-2, 10))
[-2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

در این حالت می‌توان از آرگومان سومی نیز برای تعیین گام یا فاصله بین اعداد بهره گرفت:

>>> list(range(2, 10, 2))
[2, 4, 6, 8]

>>> list(range(2, 10, 3))
[2, 5, 8]

>>> list(range(2, 10, 4))
[2, 6]
  • هر سه آرگومان می‌بایست از نوع صحیح باشند.

  • برای تعیین آرگومان stop منفی، می‌بایست آرگومان گام را نیز به شکل منفی تعیین نمود:

    >>> list(range(2, -10, -1))
    [2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
    
    >>> list(range(2, -10, -2))
    [2, 0, -2, -4, -6, -8]
    
    >>> list(range(-2, -10, -1))
    [-2, -3, -4, -5, -6, -7, -8, -9]
    
    >>> list(range(-2, -10, -2))
    [-2, -4, -6, -8]
    

در نسخه‌های 2x پایتون دو نسخه از این تابع وجود دارد: تابع range [اسناد پایتون 2x] و تابع xrange [اسناد پایتون 2x].

خروجی تابع range یک شی از نوع لیست است:

>>> r = range(10)    # Python 2.x

>>> type(r)
<type 'list'>

>>> r
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> import sys
>>> sys.getsizeof(r)
152

ولی خروجی تابع xrange یک شی از نوع xrange می‌باشد:

>>> r = xrange(10)    # Python 2.x

>>> type(r)
<type 'xrange'>

>>> r
xrange(10)

>>> list(r)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> import sys
>>> sys.getsizeof(r)
40

خروجی تابع xrange ساده‌تر و بهینه تر از خروجی تابع range است بنابراین معمولا پیشنهاد می‌شود که در حلقه for از تابع xrange استفاده شود؛ به همین دلیل می‌باشد که تابع range در نسخه‌های 3x پایتون حذف شده است و تنها تابع xrange باقی‌مانده که با نام و نوع range پیاده‌سازی شده است.

  • چگونگی استفاده و تعداد آرگومان‌های هر دو تابع همانند نسخه 3x است که پیش از این بررسی شد.

چند مثال‌ ساده دیگر:

>>> L = ['a', 'b', 'c', 'd']

>>> for i in range(len(L)):
...     print(L[i])
...
a
b
c
d
>>>
>>> s = 'pythonprogramminglanguage'

>>> for c in s[9:13]:
...     print(c)
...
g
r
a
m
>>>
>>> reven = range(0, 10, 2)
>>> list(reven)
[0, 2, 4, 6, 8]

>>> rodd = range(1, 10, 2)
>>> list(rodd)
[1, 3, 5, 7, 9]

>>> list(zip(reven, rodd))
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]

>>> L = []
>>> for a, b in zip(reven, rodd):
...    L.append(a*b)
...
>>> L
[0, 6, 20, 42, 72]

می‌توان نتایج حلقه for را مستقیم در یک شی لیست قرار داد؛ برای نمونه دستور پایین را در نظر بگیرید:

>>> L = []
>>> for x in range(5):
...     L.append(x**2)
...
>>> L
[0, 1, 4, 9, 16]

که می‌توان خیلی ساده آن را به صورت پایین بازنویسی کرد:

>>> [x ** 2 for x in range(5)]
[0, 1, 4, 9, 16]

و به عنوان مثال‌هایی دیگر به نمونه کدهای پایین توجه نمایید:

>>> y = 7

>>> [y * x for x in range(10)]
[0, 7, 14, 21, 28, 35, 42, 49, 56, 63]
>>> L = [(1, 2), (3, 4), (5, 6)]

>>> [a + b for a, b in L]
[3, 7, 11]
>>> [a * b for a, b in zip(range(0, 10, 2), range(1, 10, 2))]
[0, 6, 20, 42, 72]
>>> [(a, b) for a, b in zip(range(0, 10, 2), range(1, 10, 2))]
[(0, 1), (2, 3), (4, 5), (6, 7), (8, 9)]

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

>>> for i in range(1, 5):
...     for j in range(0, i):
...         print(i)
...
1
2
2
3
3
3
4
4
4
4
>>>

به نمونه کد بالا توجه نمایید؛ با هر بار تکرار حلقه یکم تمام دستورهای بدنه آن که شامل یک حلقه دیگر است اجرا می‌گردد. از متغیر i درون حلقه داخلی نیز استفاده شده است. در بار نخستِ اجرای حلقه بیرونی مقدار i برابر عدد 1 قرار داده می‌شود که در این صورت اجرای حلقه داخلی تنها یک بار تکرار می‌گردد (1 == ((len(range(0, 1) و یک مقدار 1 در خروجی نمایش داده می‌شود،‌ بار دوم i برابر عدد 2 می‌شود و در نتیجه حلقه داخلی دو بار تکرار می‌گردد که بر اثر آن دو مقدار 2 در خروجی چاپ می‌گردد. این روند تا پایان تکرار حلقه بیرونی ادامه می‌یابد.

تابع (یا دستور) print به صورت پیش‌فرض پس از اجرا و چاپ مقدار به سطر بعدی می‌رود. [در درس بعد چگونگی تغییر این رفتار بررسی خواهد شد]

اگر از پیش با زبان‌هایی نظیر C یا Java آشنایی دارید؛ برای درک بهتر ساختار حلقه for پایتون نمونه کد پایین که به زبان Java است را در نظر بگیرید:

int[][] array = { { 1, 2 }, { 3 }, { 4, 5, 6 } };

for ( int row = 0; row < array.length; row++ )
{
    for ( int column = 0; column < array[ row ].length; column++ )
        System.out.printf( "%d ", array[ row ][ column ] );

    System.out.println();
}

// Paul Deitel, Harvey Deitel "Java: How to Program" (9th Edition) page 270
1 2
3
4 5 6

که می‌توانیم آن را توسط زبان پایتون به شکل پایین پیاده‌سازی نماییم:

>>> array = ((1, 2), (3,), (4, 5, 6))
>>> for row in range(0, len(array)):
...     for column in range(0, len(array[row])):
...         print("%d " % array[row][column])
...     print()

تابع (enumerate(iterable:

علاوه‌ بر تابع ()range در حلقه‌های for می‌توانیم از تابع ()enumerate [اسناد پایتون] نیز استفاده کنیم. این تابع یک شی دنباله یا تکرارکننده را به عنوان آرگومان دریافت می‌کند و یک شی از نوع enumerate برمی‌گرداند:

>>> L = ['a', 'b', 'c']

>>> e = enumerate(L)

>>> type(e)
<class 'enumerate'>

>>> e
<enumerate object at 0x7fc76a6b92d0>
>>> print(e)
<enumerate object at 0x7fc76a6b92d0>

>>> import sys
>>> sys.getsizeof(e)
72

با تبدیل این شی به یک شی لیست مشاهده می‌شود که این شی عضوهای آرگومان ورودی خود را به شکل جفت‌هایی به همراه اندیس موقعیت آن‌ها ذخیره کرده است (index, value):

>>> list(e)
[(0, 'a'), (1, 'b'), (2, 'c')]

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

>>> s = 'python'

>>> for i, v in enumerate(s):
...     print('%s) %s' % (i, v * 7))
...
0) ppppppp
1) yyyyyyy
2) ttttttt
3) hhhhhhh
4) ooooooo
5) nnnnnnn
>>>
>>> s = 'python'

>>> [v * i for i, v in enumerate(s)]
['', 'y', 'tt', 'hhh', 'oooo', 'nnnnn']

این تابع همچنین یک آرگومان اختیاری با نام start دارد که با مقدار دادن به آن می‌توان عدد ابتدایی شمارش اندیس‌ها را تعیین نمود؛ مقدار پیش‌فرض این آرگومان عدد صفر است:

>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']

>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]

>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]

شی تکرارکننده

در این بخش قصد داریم با مفهوم iterator (تکرارکننده) در پایتون آشنا شویم. برای این منظور بهتر است ابتدا مفهوم iterable (تکرارپذیر) را بدانیم.

تمام انواع دنباله یک iterable هستند؛ در واقع به اشیایی با این قابلیت که بتوان در هر لحظه یک عضو درون آن را دستیابی نمود iterable گفته می‌شود. اکثر انواع آماده شی که در پایتون می‌شناسیم یک iterable است؛ انواع شی رشته، لیست، تاپل، دیکشنری، range ،zip (یا xrange) یا یک شی فایل (file) و هر شی از کلاسی که خودتان به همراه متد‌های ویژه ()__iter__ یا ()__getitem__ تعریف نمایید یک iterable هستند.

شی iterator با استفاده از تابع آماده ()iter [اسناد پایتون] ایجاد می‌شود؛ این تابع یک شی iterable را به عنوان آرگومان دریافت می‌کند و آن را در قالب یک شی iterator بر می‌گرداند:

>>> L = [1, 2, 3, 4, 5]
>>> type(L)
<class 'list'>

>>> itr = iter(L)

>>> type(itr)
<class 'list_iterator'>
>>> t = (1, 2, 3, 4, 5)
>>> type(t)
<class 'tuple'>

>>> itr = iter(t)

>>> type(itr)
<class 'tuple_iterator'>
>>> s = 'python'
>>> type(s)
<class 'str'>

>>> itr = iter(s)

>>> type(itr)
<class 'str_iterator'>
>>> d = {'name': 'Bob', 'age': 40}
>>> type(d)
<class 'dict'>

>>> itr = iter(d)

>>> type(itr)
<class 'dict_keyiterator'>

یک شی iterator این قابلیت را دارد که می‌توان عضوهای درون آن را یکی یکی با استفاده از متد ()__next__ (یا ()next در پایتون 2x) پیمایش کرد؛ این متد در بار نخستِ فراخوانی عضو یکم شی و در دفعات بعدی فراخوانی به ترتیب عضوهای بعدی را برمی‌گرداند:

>>> L = [1, 2, 3, 4, 5]
>>> itr = iter(L)
>>> # Python 3.x

>>> itr.__next__()
1
>>> itr.__next__()
2
>>> itr.__next__()
3
>>> # Python 2.x

>>> itr.next()
1
>>> itr.next()
2
>>> itr.next()
3

با فراخوانی پی در پی این متد و رسیدن به انتهای پیمایش؛ زمانی که دیگر عضوی برای برگرداندن وجود ندارد یک خطا - البته درست این است که بگوییم یک استثنا (Exception) - با نام StopIteration گزارش می‌گردد:

>>> itr.__next__()
4
>>> itr.__next__()
5
>>> itr.__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

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

در آینده توسط درس استثنا‌ها در پایتون خواهید دید که می‌توان با ایجاد iterator و استفاده از دستور try/except [که در همان درس خواهید آموخت] یک حلقه while را به مانند حلقه for پیاده‌سازی کرد.

با استفاده از ماژول itertools می‌توانید iterator های بی‌نهایت (Infinite) یا بدون توقف ایجاد نمایید. برای نمونه تابع cycle درون این ماژول، شی iterator ای می‌سازد که در انتهای پیمایش متوقف نمی‌شود و از نو به ابتدای شی برگشته و عضو یکم را برمی‌گرداند:

>>> import itertools

>>> L = [1, 2, 3, 4, 5]

>>> itr = itertools.cycle(L)

>>> type(itr)
<class 'itertools.cycle'>

>>> itr.__next__()
1
>>> itr.__next__()
2
>>> itr.__next__()
3
>>> itr.__next__()
4
>>> itr.__next__()
5
>>> itr.__next__()
1
>>> itr.__next__()
2

این ماژول شامل تابع‌های کاربردی بسیاری است که برای مطالعه بیشتر می‌توانید به صفحه آن در اسناد پایتون مراجعه نمایید.



😊 امیدوارم مفید بوده باشه

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

درس ۱۰: ورودی و خروجی

موضوع این درس به چگونگی دریافت یا خواندن داده‌ها از کاربر حالت تعاملی یا فایل‌ها و همچنین نمایش یا نوشتن در آن‌ها اختصاص یافته است؛ بر همین اساس در متن درس به بررسی شی فایل و تابع‌های آماده ()print و ()input در پایتون پرداخته خواهد شد. به برخی از تفاوت‌ها در پیاده‌سازی نسخه جدید پایتون (شاخه 3x) که به موضوع این درس مربوط می‌باشند نیز اشاره شده است.

سطح: مقدماتی



فایل‌ها

فایل‌ها (Files) جزو منابع منطقی کامپیوتر به شمار می‌روند، توسط سیستم عامل مدیریت می‌شوند و امکانی برای نگهداری طولانی مدت از اطلاعات می‌باشند. فایل‌ها در واقع بیت‌هایی متوالی از صفر و یک هستند که بر روی دیسک ذخیره گشته‌اند و معمولا در دو قالب جداگانه:

  • «فایل‌‌ باینری» (binary file) - مانند: فایل‌های ویدئو، فایل‌های تصویر، فایل zip، فایل بایت‌کد پایتون و…
  • «فایل‌ متنی» (text file) - مانند: فایل HTML، فایل ماژول پایتون و…

شناخته می‌شوند.

همانطور که گفته شد فایل‌ها چیزی جز مجموعه‌ای از مقدارهای باینری (یا دودویی) نیستند و فایل‌های متنی نیز در واقع یک زیر مجموعه از فایل‌های باینری است با این تفاوت که بیت‌های یک فایل متنی در کنار هم، بسته به نوع کدگذاری آن متناظر با دنباله‌ای از کاراکترهایی مشخص و قابل چاپ هستند. محتوای این نوع فایل در سطرهایی جداگانه قرار داده می‌شود و با استفاده از برنامه‌های ویرایشگر متن برای انسان خوانا می‌باشد. در یک فایل متنی با کدگذاری ASCII (اَسکی) هر هشت بیت (یک بایت) برابر یک کاراکتر می‌باشد - کدهای اسکی هفت بیتی هستند ولی در اکثر کامپیوترها برای هر کدام یک بایت در نظر گرفته می‌شود - برای نمونه کلمه Python به شکل شش بایت که هر کدام به ترتیب برابر مقدار باینری کد اسکی هر یک از این کاراکترها می‌باشد، ذخیره می‌شود. اسکی تنها از ۱۲۸ کاراکتر - از کد ۰ تا ۱۲۷ (در پایه ده) - پشتیبانی می‌کند و به همین دلیل امروزه بیشتر از کدگذاری‌های استاندارد Unicode (یونیکد) استفاده می‌گردد. در یونیکد مجموعه بسیار بزرگتری از کاراکتر نسبت به کدگذاری اسکی پشتیبانی می‌شود به گونه‌ای که اسکی را نیز در برمی‌گیرد؛ برای نمونه در کدگذاری UTF-8 از این استاندارد، ۱۲۸ کد نخست (از کد ۰ تا ۱۲۷) برابر کد همان ۱۲۸ کاراکتر اسکی می‌باشد. کدگذاری UTF-8 کاراکترهای یونیکد را در یک دنباله بایت با طول متغیر (۱ تا ۶ بایت) ارايه می‌دهد؛ در این کدگذاری برای کاراکترهای اسکی تنها یک بایت در نظر گرفته می‌شود.

در یک فایل باینری وجود سطر مفهومی ندارد و بایت‌های آن ممکن است داده‌هایی را نمایش دهند که نمی‌توان آن‌ها را توسط هیچ یک از کدگذاری‌های کاراکتر (UTF-8 ،ASCII و…) چاپ کرد یا حتی ممکن است در صورت چاپ آن‌ها نیز حاصل برای انسان غیر قابل فهم باشد.

پایتون یک نوع شی آماده برای دستیابی فایل‌ها در برنامه ارایه می‌دهد که این شی با استفاده از تابع آماده (open(file, mode [اسناد پایتون] ایجاد می‌گردد؛ آرگومان نخست یک شی رشته حاوی نام کامل فایل (نشانی + نام + پسوند) مورد نظر بر روی دیسک کامپیوتر است و آرگومان دوم نیز یک رشته با مقداری خاص است و حالتی که این فایل می‌بایست در آن باز شود را مشخص می‌سازد؛ این آرگومان اختیاری است و مقدار پیش‌فرض آن 'r' می‌باشد. برای نمونه به کدهای پایین که با یکدیگر معادل هستند توجه نمایید:

>>> f = open('/home/saeid/Documents/sample.txt')
>>> f = open('/home/saeid/Documents/sample.txt', 'r')
>>> f = open('/home/saeid/Documents/sample.txt', mode='r')

مسیر نمونه فایل بالا بر اساس سیستم فایل لینوکس درج شده است که در ویندوز برای مثال می‌تواند به یکی از دو شکل پایین درج گردد:

r'C:\Users\Saeid\Documents\sample.txt'
'C:\\Users\\Saeid\\Documents\\sample.txt'

آرگومان file را می‌توان تنها با نام خالی فایل و بدون ذکر مسیر آن مقداردهی کرد؛ در این صورت مفسر پایتون مسیر دایرکتوری جاری را برای آن در نظر می‌گیرد. با استفاده از تابع ()getcwd از ماژول os [اسناد پایتون] می‌توانیم مسیر دایرکتوری جاری برنامه را به دست آوریم. [در درس بعد بیشتر درباره این ماژول صحبت خواهیم کرد]:

>>> import os

>>> os.getcwd()
'/home/saeid'

آرگومان mode نیز بر حسب نیاز می‌تواند یکی از مقدارهای پایین را داشته باشد:

  • 'r': فایل در قالب متنی تنها به منظور خواندن از آن باز می‌شود و اشاره‌گر در ابتدای آن قرار می‌گیرد. چنانچه فایلی با این نام موجود نباشد یک خطا (یا استثنا) FileNotFoundError گزارش می‌گردد. معادل 'rt'
  • 'w': فایل در قالب متنی تنها به منظور نوشتن در آن باز می‌شود؛ متن درون آن (در صورت وجود) پاک می‌شود و اشاره‌گر در ابتدای آن قرار می‌گیرد. چنانچه فایلی با این نام موجود نباشد، ابتدا ایجاد و سپس باز می‌شود. معادل 'wt'
  • 'a': فایل در قالب متنی تنها به منظور افزودن متنی در انتهای متن موجود در آن باز می‌شود؛ اشاره‌گر در انتهای فایل قرار دارد. چنانچه فایلی با این نام موجود نباشد، ابتدا ایجاد و سپس باز می‌شود. معادل 'at'
  • 'x': فقط در پایتون exclusive creation) - 3x) فایل در قالب متنی ایجاد و به منظور نوشتن در آن باز می‌شود؛ چنانچه این فایل از پیش موجود باشد یک خطا (یا استثنا) FileExistsError گزارش می‌گردد. معادل 'xt'
  • 'rb' و 'wb' و 'ab' و 'xb': همان توضیح گزینه‌های مشابه بالا را دارند ولی با این تفاوت که برای کار با فایل‌هایی در قالب باینری استفاده می‌شوند.
  • '+r': فایل در قالب متنی به منظور خواندن و نوشتن باز می‌شود و اشاره‌گر در ابتدای آن قرار می‌گیرد. چنانچه فایلی با این نام موجود نباشد یک خطا (یا استثنا) FileNotFoundError گزارش می‌گردد. توجه داشته باشید که در این حالت عمل نوشتن از همان ابتدای فایل، باعث جایگزین شدن متن جدید با متن حاضر می‌شود. معادل '+rt' یا 'r+t'
  • '+w': فایل در قالب متنی به منظور نوشتن و خواندن باز می‌شود؛ متن درون آن (در صورت وجود) پاک می‌شود و اشاره‌گر در ابتدای آن قرار می‌گیرد. چنانچه فایلی با این نام موجود نباشد، ابتدا ایجاد و سپس باز می‌شود. معادل '+wt' یا 'w+t'
  • '+a': فایل در قالب متنی به منظور افزودن متنی در انتهای متن موجود در آن و همچنین خواندن باز می‌شود؛ اشاره‌گر در انتهای فایل قرار دارد. چنانچه فایلی با این نام موجود نباشد، ابتدا ایجاد و سپس باز می‌شود. معادل '+at' یا 'a+t'
  • '+x': فقط در پایتون 3x - فایل در قالب متنی ایجاد و به منظور نوشتن و خواندن باز می‌شود؛ چنانچه این فایل از پیش موجود باشد یک خطا (یا استثنا) FileExistsError گزارش می‌گردد. معادل '+xt' یا 'x+t'
  • '+rb' یا 'r+b' و '+wb' یا 'w+b' و '+ab' یا 'a+b' و '+xb' یا 'x+b': همان توضیح گزینه‌های مشابه بالا را دارند ولی با این تفاوت که برای کار با فایل‌هایی در قالب باینری استفاده می‌شوند.
  • 'rU': خواندن یک فایل متنی با پشتیبانی از Universal Newline. معادل 'rtU'
  • 'rbU': خواندن یک فایل باینری با پشتیبانی از Universal Newline.

که در آن‌ها:

  • r: خواندن (read)
  • w: نوشتن (write)
  • a: درج در انتها (appending)
  • t: تعیین قالب متنی (text) برای فایل مورد نظر؛ قالب پیش‌فرض است و نیازی به درج آن نیست
  • b: تعیین قالب باینری (binary) برای فایل مورد نظر
  • +: فایل به منظور بروز رسانی (updating) باز می‌شود
  • U: حالت Universal Newline

در قرارداد سیستم‌های عامل گوناگون از رشته‌های مختلفی - که می‌تواند از یک یا چند کاراکتر تشکیل شده باشد - برای نشانه‌گذاری انتهای سطرهای یک فایل متنی استفاده شده است؛ برای نمونه در ویندوز از CRLF (یا 'r\n\') و در گنولینوکس از LF (یا 'n\') استفاده می‌شود. شی فایل پایتون به صورت پیش‌فرض از همان قرارداد سیستم عامل میزبان برای تعیین رشته Newline خود استفاده می‌کند؛ ولی چنانچه قصد دارید در پایتون فایلی با قرارداد سیستم عامل دیگری را به منظور خواندن باز نمایید می‌بایست این کار را در حالت Universal Newline انجام دهید. در این حالت به هنگام خواندن از یک فایل، پایتون تمام رشته‌های Newline موجود در فایل را به کاراکتر 'n\' نگاشت می‌کند [PEP 278]؛ دستور os.linesep [اسناد پایتون] رشته Newline سیستم عامل میزبان را برمی‌گرداند:

>>> import os

>>> os.linesep  # GNU/Linux
'\n'

باز کردن یک فایل به منظور خواندن از آن حکم یک منبع ورودی (input) و باز کردن یک فایل به منظور نوشتن در آن حکم یک منبع خروجی (output) را در برنامه دارد.

تابع ()open آرگومان‌های اختیاری دیگری نیز دارد که برای بررسی آن‌ها می‌توانید به اسناد پایتون مراجعه نمایید.

متدهای شی فایل

  • (write(string: یک شی از نوع str یا bytes را دریافت می‌کند و آن را درون شی فایل مورد نظر می‌نویسد:

    >>> text = '1) Python\n2) Programming\n3) Language\n'
    
    >>> print(text)
    1) Python
    2) Programming
    3) Language
    
    >>>
    
    >>> type(text)
    <class 'str'>
    
    >>> # Python 3x
    
    >>> output = open('textfile.txt', 'w')
    >>> output.write(text)
    37
    >>> output.close()
    

    در پایتون 3x، متد write تعداد کاراکترهایی که می‌نویسد را برمی‌گرداند.

    >>> # Python 3x
    
    >>> output = open('binaryfile.bin', 'wb')
    >>> output.write(text)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: a bytes-like object is required, not 'str'
    

    در پایتون 3x به این دلیل که نوع رشته‌های باینری (bytes) از رشته‌های معمولی (str) جدا گشته است، نمی‌توان از شی str برای نوشتن در فایلی که در حالت باینری باز شده است استفاده کرد.

    >>> # Python 3x
    
    >>> data = '1) Python\n2) Programming\n3) Language\n'
    
    >>> # Convert str to bytes
    >>> bdata = bytes(data, 'utf-8')
    
    >>> bdata
    b'1) Python\n2) Programming\n3) Language\n'
    
    >>> type(bdata)
    <class 'bytes'>
    
    
    >>> output = open('binaryfile.bin', 'wb')
    >>> output.write(bdata)
    37
    >>> output.close()
    

    در رفتار گنولینوکس تفاوتی بین حالت متنی و باینری وجود ندارد؛‌ اکنون اگر هر دو فایل textfile.txt و binaryfile.bin را (در گنولینوکس) توسط برنامه ویرایشگر متن باز نمایید، خواهید دید که محتوای این دو فایل مشابه یکدیگر نمایش داده می‌شوند.

    در گنولینوکس، باز کردن فایل textfile.txt توسط یک برنامه ویرایشگر متن:

    1
    2
    3
    1) Python
    2) Programming
    3) Language
    

    در گنولینوکس، باز کردن فایل binaryfile.bin توسط یک برنامه ویرایشگر متن:

    1
    2
    3
    1) Python
    2) Programming
    3) Language
    

    ولی در ویندوز به هنگام حالت متنی، اگر یک فایل را به منظور خواندن باز نمایید کاراکترهای 'n\' موجود در آن به شکل 'r\n\' برگردانده می‌شوند و اگر که یک فایل را به منظور نوشتن باز کنید، هر بار رشته 'r\n\' به جای 'n\' نوشته می‌شود. در حالت باینری این کارها انجام نمی‌شود.

    اگر دستورهای یاد شده را در ویندوز اجرا نماییم؛ دو فایل مورد نظر با محتوای پایین توسط برنامه ویرایشگر متن نمایش داده خواهند شد.

    در ویندوز، باز کردن فایل textfile.txt:

    1
    2
    3
    1) Python
    2) Programming
    3) Language
    

    در ویندوز، باز کردن فایل binaryfile.bin:

    1
    1) Python2) Programming3) Language
    

    به نمونه‌ کدهای بالا در پایتون 2x نیز توجه نمایید:

    >>> # Python 2x
    
    >>> output = open('textfile.txt', 'w')
    >>> output.write('1) Python\n2) Programming\n3) Language\n')
    >>> output.close()
    
    >>> # Python 2x
    
    >>> data = '1) Python\n2) Programming\n3) Language\n'
    
    >>> type(data)
    <type 'str'>
    
    >>> output = open('binaryfile.bin', 'wb')
    >>> output.write(data)
    >>> output.close()
    
    >>> # Python 2x
    
    >>> bdata = b'1) Python\n2) Programming\n3) Language\n'
    
    >>> type(bdata)
    <type 'str'>
    
    >>> output = open('binaryfile.bin', 'wb')
    >>> output.write(bdata)
    >>> output.close()
    
  • ()close: پس از پایان کار با هر فایل می‌بایست که آن را ببندید؛ این متد فایل باز شده را می‌بندد. شی فایل مورد نظر پس از فراخوانی این متد، هیچ متد دیگری را نمی‌تواند فراخوانی کند.

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

    همچنین برای بررسی اینکه یک فایل باز است یا اینکه بسته شده است می‌توانید از صفت closed استفاده نمایید؛ این صفت در صورتی که فایل بسته شده باشد حاوی مقدار True می‌باشد:

    >>> f.closed
    False
    
    >>> f.close()
    
    >>> f.closed
    True
    
  • ()read: تمام محتوای فایل را می‌خواند و در قالب یک شی از نوع str - برای فایل‌های متنی در هر دو شاخه پایتون و باینری در پایتون 2x - یا bytes - برای فایل‌های باینری در پایتون 3x - برمی‌گرداند:

    >>> input = open('textfile.txt')
    
    >>> content = input.read()
    
    >>> input.close()
    
    >>> type(content)
    <class 'str'>
    
    >>> content
    '1) Python\n2) Programming\n3) Language\n'
    
    >>> print(content)
    1) Python
    2) Programming
    3) Language
    
    >>>
    
    >>> # Python 3x, Reading a binary file
    
    >>> input = open('binaryfile.bin', 'rb')
    
    >>> content = input.read()
    
    >>> input.close()
    
    >>> type(content)
    <class 'bytes'>
    
    >>> content
    b'1) Python\n2) Programming\n3) Language\n'
    
    >>> print(content)
    b'1) Python\n2) Programming\n3) Language\n'
    >>>
    
    >>> # Python 2x, Reading a binary file
    
    >>> input = open('binaryfile.bin', 'rb')
    
    >>> content = input.read()
    
    >>> input.close()
    
    >>> type(content)
    <type 'str'>
    
    >>> content
    '1) Python\n2) Programming\n3) Language\n'
    
    >>> print content
    1) Python
    2) Programming
    3) Language
    
    >>>
    

    این متد یک آرگومان اختیاری نیز دارد؛ این آرگومان یک عدد صحیح است که تعداد کاراکتر (یا بایت) که می‌بایست از فایل خوانده و برگردانده شوند را تعیین می‌کند:

    >>> f = open('textfile.txt')
    
    >>> f.read(5)
    '1) Py'
    
    >>> f.read(5)
    'thon\n'
    
    >>> f.read(10)
    '2) Program'
    
    >>> f.read(4)
    'ming'
    
    >>> f.read(1)
    '\n'
    
    >>> f.close()
    

    به نمونه کد بالا توجه نمایید؛ هنگامی که فایل در این حالت (rt) باز شده است اشاره‌گر در ابتدای فایل قرار گرفته و با هر میزان خواندن از فایل، موقعیت اشاره‌گر نیز به جلو حرکت داشته است.


  • ()readline: در هر فراخوانی یک سطر از فایل - تا رشته Newline - را برمی‌گرداند:

    >>> f = open('textfile.txt')
    
    >>> f.readline()
    '1) Python\n'
    
    >>> f.readline()
    '2) Programming\n'
    
    >>> f.readline()
    '3) Language\n'
    
    >>> f.readline()
    ''
    
    >>> f.close()
    
  • ()readlines: تمام سطرهای یک فایل را در قالب یک شی لیست بر می‌گرداند:

    >>> f = open('textfile.txt')
    
    >>> cl = f.readlines()
    
    >>> cl
    ['1) Python\n', '2) Programming\n', '3) Language\n']
    
    >>> cl[1]
    '2) Programming\n'
    
    >>> f.close()
    
  • (writelines(list: یک شی لیست که تمام اعضای آن از نوع str هستند را به عنوان آرگومان گرفته و اعضای آن را به ترتیب در فایل مورد نظر می‌نویسد:

    >>> L = ['a', 'b', 'c', 'd\n', 'e']
    
    >>> f = open('tf.txt', 'w')
    >>> f.writelines(L)
    >>> f.close()
    

    حاصل کد بالا؛ باز کردن فایل tf.txt توسط یک برنامه ویرایشگر متن:

    1
    2
    abcd
    e
    
  • (seek(offset: آرگومان offset یک عدد صحیح است و این متد موقعیت اشاره‌گر فایل را به آن offset نسبت به ابتدای فایل تغییر می‌دهد:

    >>> f = open('textfile.txt')
    
    >>> f.seek(3)
    3
    
    >>> f.read(6)
    'Python'
    
    >>> f.close()
    
  • ()flush: باعث ذخیره محتوای بافر در فایل می‌شود.

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

دستور for

از تابع ()open نیز می‌توان در حلقه for استفاده کرد؛ در این صورت در هر بار تکرار سطرهای فایل پیمایش می‌شوند:

>>> for line in open('textfile.txt'):
...     print(line, end='')
...
1) Python
2) Programming
3) Language
>>>

از آنجا که متن درون فایل خود حاوی Newline (در اینجا: 'n\') است، آرگومان end تابع ()print را برای جلوگیری از درج 'n\' در انتهای هر سطر تغییر دادیم [در بخش print درباره آرگومان end صحبت خواهیم کرد].

دستور with/as

یک دستور مرکب است که از اشیایی که با نوع ”Context Manager“ [اسناد پایتون] در پایتون شناخته می‌شوند، پشتیبانی می‌کند [PEP 343]. برخی از اشیا در پایتون - به مانند شی فایل - قابلیتی با نام ”Context Manager“ دارند؛ برای پیاده سازی این قابلیت، کلاس شی مورد نظر می‌بایست حاوی دو متد ویژه ()__enter__ و ()__exit__ باشد که به ترتیب در زمان‌های «ورود به» و «خروج از» بدنه دستور with/as فراخوانی می‌شوند.

دستور with/as ساختاری مشابه پایین دارد:

with expression as variable:
    statement(s)

در این ساختار، expression نماد بخشی از دستور است که یک شی از نوع Context Manager را برمی‌گرداند؛ این شی با استفاده از کلمه کلیدی as به یک متغیر ارجاع داده می‌شود. برای نمونه ساختار with/as مربوط به یک شی فایل در پایین نوشته شده است:

with open('textfile.txt', 'w') as output:
    output.write('text')

پس از ایجاد شی فایل، این شی می‌بایست وارد اجرای دستور with/as شود؛ with/as این کار را با فراخوانی متد ()__enter__ انجام می‌دهد. در واقع این متد همان شی فایل ایجاد شده را برمی‌گرداند که در ادامه توسط as به متغیر output ارجاع داده می‌شود. همچنین با استفاده از این ساختار دیگر نیازی به فراخوانی متد ()close برای شی فایل نمی‌باشد؛ چرا که این کار پس از پایان دستورهای بدنه با فراخوانی شدن متد ()__exit__ توسط with/as به انجام می‌رسد؛ در واقع with/as بستن فایل را در پایان اجرای دستورهای بدنه خود تضمین می‌کند. همچنین در این ساختار چنانچه هنگام کار با فایل خطایی (یا استثنایی) رخ دهد، پیش از گزارش آن، ابتدا فایل بسته خواهد شد.

توجه داشته باشید که یک شی فایل همیشه باید بسته شود؛ در مواقعی که قصد استفاده از حلقه for برای یک شی فایل را دارید بهتر است از آن درون ساختار with/as بهره بگیرید:

with open('textfile.txt') as f:
    for line in f:
        print(line)

از دستور with/as می‌توان به شکل تودرتو نیز بهره گرفت:

with A() as a:
    with B() as b:
        statements

همچنین به نسخه‌های 2.7 و از 3.1 به بعد پایتون سینتکس جدیدی افزوده شده است که توسط آن می‌توان همزمان از چند Context Manager بهره گرفت:

with A() as a, B() as b:
    statements

به مانند نمونه کد پایین که دو فایل را باز می‌کند؛ از یکی می‌خواند و برخی از سطرهای آن را در فایل دیگر می‌نویسد:

with open('data') as fin, open('res', 'w') as fout:
    for line in fin:
        if 'key' in line:
            fout.write(line)

شی فایل استاندارد

سه نوع شی فایل توسط مفسر پایتون ایجاد می‌گردد که هر سه آن‌ها توسط ماژول sys در دسترس هستند:

  • sys.stdin: ورودی استاندارد [اسناد پایتون]؛ برای دستیابی تمامی ورودی‌ها در حالت تعاملی پایتون - مانند فراخوانی تابع ()input - از این شی استفاده می‌گردد.
  • sys.stdout: خروجی استاندارد [اسناد پایتون]؛ توسط print مورد استفاده قرار می‌گیرد.
  • sys.stderr: خطا استاندارد [اسناد پایتون]؛ شی‌ای است که خطاها را دریافت می‌کند.

نه همیشه ولی می‌توان منبع sys.stdin را صفحه‌کلید کامپیوتر و منبع sys.stdout و sys.stderr را نیز صفحه‌نمایش در نظر گرفت.

تابع ()input

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

پایتون 2x:

  • ()raw_input
  • ()input

در این شاخه از پایتون دو تابع ()raw_input [اسناد پایتون] و ()input [اسناد پایتون] برای همین منظور در دسترس است. تابع ()raw_input یک سطر از کاربر را می‌خواند و در قالب یک شی از نوع str برمی‌گرداند:

>>> s = raw_input()
Hello Python

با اجرا دستور سطر یکم، مفسر پایتون منتظر ورود متن می‌ماند - در این نمونه متن Hello Python نوشته می‌شود - سپس با دریافت کلید Enter تمام کاراکترهای دریافتی را در قالب یک شی رشته - نوع str - به متغیر s ارجاع می‌دهد:

>>> s
'Hello Python'
>>> type(s)
<type 'str'>

همچنین می‌توان متنی را برای مشاهده کاربر به صورت آرگومان در فراخوانی تابع قرار داد:

>>> s = raw_input("What's your name? ")
What's your name? Alan

>>> s
'Alan'
>>> s = raw_input("How old are you? ")
How old are you? 41

>>> s
'41'
>>> type(s)
<type 'str'>

تابع ()input در پایتون 2x نیز عملکردی برابر با دستور (()eval(raw_input دارد. ()eval [اسناد پایتون] تابع آماده دیگری در پایتون است که یک شی رشته را دریافت و متن آن را به شکل کد پایتون تفسیر می‌کند:

>>> x = 1
>>> y = eval('x + 1')
>>> y
2
>>> type(y)
<type 'int'>

به نمونه کدهای پایین نیز توجه نمایید:

>>> eval("9 // 2")
4

>>> eval("9 /// 2")
  File "<string>", line 1
    9 /// 2
        ^
SyntaxError: invalid syntax
>>>
>>> a = '32'
>>> type(a)
<type 'str'>

>>> b = eval(a)

>>> b
32
>>> type(b)
<type 'int'>
>>> print eval("__import__('os').getcwd()")
/home/saeid

تابع ()__import__ [اسناد پایتون] عملکردی برابر با دستور import دارد ولی با این تفاوت که می‌توان از آن به شکلی پویا در طی اجرای برنامه برای وارد کردن ماژول‌های گوناگون استفاده نمود؛ در این حالت نام یک ماژول حتی می‌تواند به شکل یک متغیر در آرگومان تابع قرار بگیرد.

اکنون که با عملکرد تابع ()eval آشنا شده‌اید به بیان مثال‌هایی از تابع ()input - در نسخه‌های 2x - می‌پردازیم:

>>> s = input("What's your name? ")
What's your name? Alan

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'Alen' is not defined
>>>

در نمونه کد بالا؛ ورودی کاربر - متن Alen - با هیچ سینتکس تعریف شده‌ای در پایتون مطابقت نداشته و باعث بروز خطا گشته است:

>>> s = input("What's your name? ")
What's your name? "Alan"

>>> s
'Alan'
>>> s = input("How old are you? ")
How old are you? 41

>>> s
41
>>> type(s)
<type 'int'>

و مثالی دیگر:

>>> a = raw_input()
3 * 4 ** 5

>>> a
'3 * 4 ** 5'


>>> b = input()
3 * 4 ** 5

>>> b
3072

پایتون 3x:

  • ()input

در این شاخه از پایتون تابع ()input از شاخه 2x وجود ندارد (حذف شده) و تنها تابع ()raw_input باقی مانده است که آن هم به ()input [اسناد پایتون] تغییر نام پیدا کرده است.

تابع ()input در پایتون 3x همانند تابع ()raw_input در پایتون 2x است:

>>> s = input("What's your name? ")
What's your name? Alan

>>> s
'Alan'
>>> type(s)
<class 'str'>

تابع ()print

پایتون 2x:

در این شاخه از پایتون print به شکل یک دستور ساده در پایتون پیاده‌سازی شده است [اسناد پایتون]. این دستور یک یا چند شی را ابتدا به نوع str تبدیل کرده و سپس به خروجی می‌فرستد:

>>> s = 'Python'

>>> print s
Python

>>> print s, "2.x"
Python 2.x

>>> print 4 * 5 / 2, 3 * 3
10 9
>>> print

>>>
  • اشیا می‌بایست توسط یک کاما , از یکدیگر جدا شوند.
  • این دستور به صورت پیش‌فرض یک حرف فاصله (یک کلید Space) در بین اشیا قرار می‌دهد.
  • در صورتی که یک عبارت محاسباتی یا منطقی به این دستور داده شود، ابتدا حاصل آن محاسبه یا ارزیابی شده و سپس به نوع str تبدیل می‌گردد.
  • دستور print به شکل تنها، یکی سطر خالی را ایجاد می‌کند.

دستور print همچنین به صورت پیش‌فرض یک 'n\' در انتهای هر سطر قرار می‌دهد؛ برای لغو این رفتار می‌توان در انتهای دستور یک کاما , قرار داد:

>>> for a in range(5):
...     print a
...
0
1
2
3
4
>>>


>>> for a in range(5):
...     print a,
...
0 1 2 3 4
>>>

این دستور توانایی نوشتن در شی فایلی غیر از شی استاندارد را نیز دارد؛ برای این منظور می‌بایست از الگوی پایین پیروی گردد:

>>> text = 'Hi :)'
>>> output = open('textfile.txt', 'w')

>>> print >> output, text

>>> output.close()

پایتون 3x:

دستور print به شکل تابع ()print در نسخه‌های 3x پایتون پیاده‌سازی شده است [اسناد پایتون]؛ الگوی این تابع به شکل پایین می‌باشد:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
  • objects*: بیانگر اشیایی است می‌خواهیم در خروجی قرار بدهیم. که می‌تواند هیچ باشد - که برابر نمایش یک سطر خالی است - یا اینکه می‌تواند یک یا چند شی - که در این صورت اشیا می‌بایست توسط یک کاما , از یکدیگر جدا شوند - را در بر گیرد:

    >>> print()
    
    >>>
    
    >>> s = 'Python'
    
    >>> print(s)
    Python
    
    >>> print(s, '3x')
    Python 3x
    
    >>> print(4 * 5 / 2, 3 * 3)
    10.0 9
    
  • sep: رشته‌ای که می‌بایست بین اشیا قرار گیرد را تعیین می‌کند. مقدار این آرگومان در حالت پیش‌فرض یک حرف فاصله (یک کلید Space) است. مقدار ارسالی به این آرگومان می‌بایست یک شی رشته یا None باشد:

    >>> print(s, '3x', sep='-')
    Python-3x
    
    >>> print(s, '3x', sep=None)
    Python 3x
    
  • end: رشته‌ای که می‌بایست در انتهای هر سطر قرار گیرد را تعیین می‌کند. مقدار این آرگومان در حالت پیش‌فرض 'n\' است. مقدار ارسالی به این آرگومان می‌بایست یک شی رشته یا None باشد:

    >>> for a in range(5):
    ...     print(a)
    ...
    0
    1
    2
    3
    4
    >>>
    
    
    >>> for a in range(5):
    ...     print(a, end=' ')
    ...
    0 1 2 3 4 >>>
    
  • file: خروجی را تعیین می‌کند که می‌بایست یک شی به همراه متد (write(string درون کلاس خود، باشد. این آرگومان به صورت پیش‌فرض بر روی خروجی استاندارد مقداردهی شده است. این تابع قابلیت استفاده در حالت باینری فایل‌ها را ندارد:

    >>> output = open('textfile.txt', 'w')
    
    >>> print('Hi :)', file=output)
    
    >>> output.close()
    
  • flush: این آرگومان از نسخه 3.3 به تابع ()print پایتون افزوده شده است. هنگامی که خروجی بر روی یک فایل قرار گرفته باشد؛ با تنظیم این گزینه بر روی مقدار True، عمل انتقال متن به فایل بدون اتلاف وقت انجام می‌پذیرد.

این تابع با استفاده از دستور import پایین در نسخه‌های 2.6 و 2.7 پایتون نیز در دسترس است [اسناد پایتون]:

from __future__ import print_function


😊 امیدوارم مفید بوده باشه

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

درس ۱۱: کتابخانه استاندارد (بخش ۱)

کتابخانه استاندارد پایتون مجموعه‌ وسیعی از امکانات آماده است که با نصب پایتون در اختیار قرار می‌گیرد. فهرست کامل این امکانات را می‌توانید از نشانی‌های (پایتون 2x) و (پایتون 3x) مشاهده نمایید. لازم به یادآوری است که بخشی بزرگی از قدرت پایتون به دلیل وجود کتابخانه‌های فراوان و قدرتمند آن است که تعداد زیادی از آن‌ها خارج کتابخانه استاندارد پایتون و درون جامعه کاربری در حال توسعه هستند که فهرست تقریبا کاملی از آن‌ها نیز توسط PyPI قابل جستجو و دریافت هستند.

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

سطح: مقدماتی



math

این ماژول حاوی ثابت‌ها (Constants) و تابع‌های ریاضی است [اسناد پایتون] که برخی از آن‌ها به شرح پایین است:

  • math.pi: ثابتی حاوی عدد π (ویکی‌پدیا) است [اسناد پایتون]:

    >>> import math
    
    >>> math.pi
    3.141592653589793
    >>>
    
  • math.e: ثابتی حاوی عدد e (ویکی‌پدیا) است [اسناد پایتون]:

    >>> import math
    
    >>> math.e
    2.718281828459045
    >>>
    
  • math.inf: (از نسخه 3.5 به بعد) - ثابتی حاوی مقدار مثبت بی‌نهایت (Positive infinity) است که این مقدار برابر با خروجی تابع ('float('inf می‌باشد. math.inf - نیز برابر منفی بی‌نهایت است [اسناد پایتون].

    برای بررسی inf بودن (مثبت یا منفی) از تابع (math.isinf(x [اسناد پایتون] استفاده می‌شود:

    >>> import math
    
    >>> a = math.inf
    >>> b = 10
    >>> a > b
    True
    
    >>> math.inf + math.inf
    inf
    >>> 1 / math.inf
    0.0
    >>> math.inf / 2
    inf
    >>> 3 * math.inf
    inf
    >>> -3 * math.inf
    -inf
    
    >>> math.isinf(a)
    True
    >>> math.isinf(b)
    False
    >>>
    
  • math.nan: از نسخه 3.5 به بعد - ثابتی حاوی مقدار «تعریف نشده» یا NaN - اختصار Not a Number (ویکی‌پدیا) - می‌باشد که این مقدار برابر با خروجی تابع ('float('nan است [اسناد پایتون].

    برای بررسی nan بودن از تابع (math.isnan(x [اسناد پایتون] استفاده می‌شود:

    >>> import math
    
    >>> a = math.nan
    >>> a
    nan
    
    >>> 0 * math.inf
    nan
    >>> math.inf - math.inf
    nan
    
    >>> math.isnan(a)
    True
    >>>
    
  • (math.ceil(x: کوچکترین عدد صحیحی که بزرگتر یا مساوی با عدد x باشد را برمی‌گرداند [اسناد پایتون]:

    >>> import math
    
    >>> math.ceil(4)
    4
    >>> math.ceil(-4.17)
    -4
    >>> math.ceil(4.17)
    5
    >>>
    
  • (math.floor(x: بزرگترین عدد صحیحی که کوچکتر یا مساوی با عدد x باشد را برمی‌گرداند [اسناد پایتون]:

    >>> import math
    
    >>> math.floor(4)
    4
    >>> math.floor(-4.17)
    -5
    >>> math.floor(4.17)
    4
    >>>
    
  • (math.fabs(x: همانند تابع آماده ()abs [اسناد پایتون] مقدار قدر مطلق (ویکی‌پدیا) عدد x را برمی‌گرداند [اسناد پایتون]:

    >>> import math
    
    >>> math.fabs(-4.17)
    4.17
    >>> math.fabs(-4)
    4.0
    >>> math.fabs(4)
    4.0
    >>>
    
  • (math.factorial(x: مقدار فاکتوریل (ویکی‌پدیا) عدد x را برمی‌گرداند [اسناد پایتون]:

    >>> import math
    
    >>> math.factorial(5)
    120
    >>>
    
  • (math.exp(x: حاصل e**x (ویکی‌پدیا) را برمی‌گرداند [اسناد پایتون]:

    >>> import math
    
    >>> math.exp(3)
    20.085536923187668
    >>>
    
  • (math.log(x[, base]: حاصل لگاریتم (Logarithm) عدد x در پایه base را برمی‌گرداند؛ آرگومان base اختیاری است و چنانچه ذکر نگردد به صورت پیش‌فرض حاصل لگاریتم عدد x در پایه عدد e یا همان لگاریتم طبیعی (ویکی‌پدیا) برگردانده می‌شود [اسناد پایتون]:

    >>> import math
    
    >>> math.log(math.e)     # ln e == 1
    1.0
    >>> math.log(1)          # ln 1 == 0
    0.0
    >>>
    
    >>> math.log(8, 2)       # 2**3 == 8
    3.0
    >>> math.log(100, 10)    # 10**2 == 100
    2.0
    >>> math.log(81, 3)      # 3**4 == 81
    4.0
    >>> math.log(2, 10)
    0.30102999566398114
    >>>
    

    برای سادگی استفاده در محاسبه‌های ریاضی دو تابع (log10(x [اسناد پایتون] - محاسبه لگاریتم عدد x در پایه عدد 10 - و (log2(x [اسناد پایتون] - محاسبه لگاریتم عدد x در پایه عدد 2؛ که از نسخه 3.3 به بعد اضافه شده است - نیز در دسترس هستند:

    >>> math.log10(100)
    2.0
    >>> math.log2(8)
    3.0
    >>>
    
  • (math.sqrt(x: ریشه دوم (Square root) یا همان جذر (ویکی‌پدیا)‌ عدد x را برمی‌گرداند [اسناد پایتون]:

    >>> import math
    
    >>> math.sqrt(4)
    2.0
    >>>
    
  • (math.pow(x, y: عدد x را به توان عدد y می‌رساند و حاصل را برمی‌گرداند [اسناد پایتون]:

    >>> import math
    
    >>> math.pow(3, 2)
    9.0
    

    این تابع هر دو آرگومان خود را به نوع float تبدیل می‌کند؛ چنانچه می‌خواهید با اعداد صحیح کار کنید، از عملگر ** یا تابع آماده ()pow [اسناد پایتون] استفاده نمایید:

    >>> 3**2
    9
    >>> pow(3, 2)
    9
    
  • توابع مثلثاتی (Trigonometric functions) [اسناد پایتون]: (cos(x و (sin(x و (tan(x و (acos(x و (asin(x و (atan(x که در تمام آن‌ها زاویه x بر حسب رادیان (Radian) است:

    >>> import math
    
    >>> math.cos(0)
    1.0
    >>> math.sin(0)
    0.0
    >>> math.tan(0)
    0.0
    >>>
    
  • (math.degrees(x: زاویه x را از رادیان به درجه تبدیل می‌کند [اسناد پایتون]:

    >>> import math
    
    >>> math.degrees(0)
    0.0
    
  • (math.radians(x: زاویه x را از درجه به رادیان تبدیل می‌کند [اسناد پایتون]:

    >>> import math
    
    >>> math.degrees(0)
    0.0
    >>> math.radians(30)
    0.5235987755982988
    
    >>> math.sin(math.radians(90))
    1.0
    
  • توابع هذلولی (Hyperbolic functions) [اسناد پایتون]: (cosh(x و (sinh(x و (tanh(x و (acosh(x و (asinh(x و (atanh(x.

os

این ماژول امکان استفاده از برخی قابلیت‌های وابسته به سیستم عامل را فراهم می‌آورد؛ مانند گرفتن مسیر دایرکتوری برنامه [اسناد پایتون]. برخی از تابع‌های موجود در این ماژول به شرح پایین است:

  • os.environ: یک شی از نوع نگاشت - مانند نوع دیکشنری [به درس هشتم رجوع شود] - است که حاوی متغیرهای محیطی سیستم عامل می‌باشد [اسناد پایتون]

    باید توجه داشت که مقدار این دستور متناسب با لحظه‌ای از سیستم عامل است که ماژول os به اسکریپت import شده است و شامل متغیرهایی که پس از این لحظه ایجاد شده باشند نمی‌شود.

    >>> # Python 3.x, GNU/Linux
    
    >>> import os
    >>> os.environ
    environ({'LOGNAME': 'saeid', 'PWD': '/home/saeid', '_': '/usr/bin/python3', 'LANG': 'en_US.UTF-8', 'PATH': '/usr/local/sbin:/usr/local/bin:/usr/bin', 'ZSH': '/home/saeid/.oh-my-zsh'})
    >>>
    
    >>> os.environ['PATH']
    '/usr/local/sbin:/usr/local/bin:/usr/bin'
    
    >>> os.environ['LANG']
    'en_US.UTF-8'
    
  • ()os.getcwd: مسیر دایرکتوری جاری (Current Working Directory)‌ را برمی‌گرداند. خروجی این تابع برابر با دستور pwd در خط فرمان گنولینوکس یا %echo %CD در خط فرمان ویندوز می‌باشد. [اسناد پایتون]:

    # Python 3.x, GNU/Linux
    
    ~ pwd
    /home/saeid
    
~ python3 -q
>>> import os
>>> os.getcwd()
'/home/saeid'
>>>
  • (os.chdir(path: مسیر دایرکتوری جاری را به مسیر آرگومان دریافتی path تغییر می‌دهد. عملکرد این تابع برابر با دستور cd در خط فرمان‌های گنولینوکس و ویندوز است. [اسناد پایتون]:

    >>> import os
    
    >>> os.getcwd()
    '/home/saeid'
    
    >>> os.chdir('/etc')
    
    >>> os.getcwd()
    '/etc'
    
  • (os.listdir(path: یک شی لیست که شامل محتویات درون دایرکتوری path است را برمی‌گرداند. چنانچه آرگومان path ارسال نشود به صورت پیش‌فرض مسیر دایرکتوری جاری در نظر گرفته می‌شود. [اسناد پایتون]

    >>> import os
    >>> os.listdir('/home/saeid/Pictures')
    ['scan0001.jpg', 'smplayer_screenshots', 'GNU.png', 'Wallpapers']
    
  • (os.mkdir(path: یک دایرکتوری که نام کامل آن توسط آرگومان path تعیین شده است را ایجاد می‌کند. در صورتی که این دایرکتوری از قبل موجود باشد یک استثنا FileExistsError رخ می‌دهد. [اسناد پایتون]:

    >>> import os
    >>> os.mkdir('dir1')
    

    در نمونه کد بالا از آنجا که مسیر دایرکتوری ذکر نشده است؛ دایرکتوری dir1 به صورت پبش فرض در مسیر دایرکتوری جاری (که در اینجا: /home/saeid/ است) ایجاد می‌گردد؛ همین امر باعث بروز استثنا با اجرای دستور پایین می‌شود:

    >>> os.mkdir('/home/saeid/dir1')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    FileExistsError: [Errno 17] File exists: '/home/saeid/dir1'
    
    >>> os.mkdir('/home/saeid/Documents/dir2')
    

    نمونه کد بالا موجب ایجاد دایرکتوری dir2 درون مسیر دایرکتوری Documents می‌شود.

    مسیر دایرکتوری می‌بایست به صورت صحیح وارد شود؛ در نمونه کد پایین نیز به همین دلیل که دایرکتوری dir3 وجود ندارد، استثنایی رخ داده است.

    >>> os.mkdir('/home/saeid/Documents/dir3/dir4')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    FileNotFoundError: [Errno 2] No such file or directory: '/home/saeid/Documents/dir3/dir4'
    
  • (os.makedirs(path: همانند (os.mkdir(path است ولی با این تفاوت که تمامی دایرکتوری‌های میانی مورد نیاز را هم ایجاد می‌کند. [اسناد پایتون]

    در نمونه کد پایین برای ایجاد دایرکتوری dir5 دایرکتوری‌های dir3 و dir4 - که البته وجود ندارند - نیز ایجاد می‌گردند.

    >>> import os
    >>> os.makedirs('/home/saeid/Documents/dir3/dir4/dir5')
    
  • (os.rmdir(path: دایرکتوری مشخص شده توسط آرگومان path را حذف می‌کند. این دایرکتوری می‌بایست خالی باشد در غیر این صورت یک استثنا OSError رخ می‌دهد. [اسناد پایتون]

    البته برای حذف کامل یک دایرکتوری به همراه تمام محتویات آن می‌توانید از تابع (rmtree(path درون ماژول shutil [اسناد پایتون] استفاده نمایید:

    >>> import shutil
    >>> shutil.rmtree("/home/saeid/Documents/dir1")
    
  • (os.removedirs(path: همانند (os.rmdir(path است ولی با این تفاوت که عملکردی بازگشتی دارد و تا زمانی که خطایی رخ نداده دایرکتوری‌های مشخص شده در آرگومان path را یکی یکی حذف می‌کند. [اسناد پایتون]

    >>> import os
    >>> os.removedirs('/home/dir1/dir2/dir3')
    

    در نمونه کد بالا ابتدا دایرکتوری dir3 (با مسیر 'home/dir1/dir2/dir3/') حذف می‌شود - البته اگر خالی باشد - و بعد از آن برای حذف دایرکتوری dir2 (با مسیر 'home/dir1/dir2/') تلاش می‌شود که اگر آن‌هم خالی باشد و حذف گردد، روند حذف به همین شکل برای باقی مسیر ادامه می‌یابد.

  • (os.rename(src, dst: این تابع برای تغییر نام یک فایل یا دایرکتوری کاربرد دارد. آرگومان src نام اصلی و آرگومان dst نیز نام جدید برای فایل یا دایرکتوری مورد نظر می‌باشند [اسناد پایتون]:

    >>> import os
    >>> os.getcwd()
    '/home/saeid/Documents/dir'
    >>> os.listdir(os.getcwd())
    ['fontsdir', 'index.html', 'style.css']
    
    >>> os.rename("fontsdir", "_fonts")
    
    >>> os.listdir(os.getcwd())
    ['index.html', 'style.css', '_fonts']
    

    توجه داشته باشید چنانچه فایل یا دایرکتوری موردنظر در مسیری دیگری از مسیر دایرکتوری جاری باشد؛ لازم است نام به شکل کامل (همراه با مسیر) ذکر گردد. همچنین بدیهی است که تغییر مسیر در آرگومان dst موجب عمل انتقال (Move) می‌شود:

    >>> import os
    >>> os.getcwd()
    '/home/saeid/Documents/dir/dir1'
    >>> os.listdir(os.getcwd())
    ['index.html', 'style.css', '_fonts']
    
    >>> os.rename("_fonts", "/home/saeid/Documents/dir/dir2/_fonts")
    
    >>> os.listdir(os.getcwd())
    ['index.html', 'style.css']
    
    >>> os.chdir('/home/saeid/Documents/dir/dir2')
    >>> os.listdir(os.getcwd())
    ['_fonts']
    

    در گنولینوکس چنانچه بخواهیم نام فایلی به یک نام از پیش موجود تغییر داده شود؛‌ [در صورتی که کاربر نیز اجازه دسترسی (Permission) لازم را داشته باشد] یک عمل جایگزینی (Replace) صورت می‌گیرد، ولی برای چنین مواقعی در سیستم عامل ویندوز یک خطای OSError رخ خواهد داد. رویداد این ماجرا در هنگام تغییر نام یک دایرکتوری، باعث بروز خطای OSError در هر دو سیستم عامل می‌شود.

  • (os.renames(old, new: عملکردی مشابه با تابع ()rename دارد با این تفاوت که اگر دایرکتورهای میانی از مسیر آرگومان new، وجود نداشته باشند، آن‌ها را نیز ایجاد می‌کند [اسناد پایتون]:

    >>> import os
    >>> os.getcwd()
    '/home/saeid/Documents/dir'
    >>> os.listdir(os.getcwd())
    ['index.html', 'style.css', '_fonts', 'js']
    
    >>> os.renames("style.css", "css/style.css")
    
    >>> os.listdir(os.getcwd())
    ['index.html', 'css', '_fonts', 'js']
    
  • (os.walk(rootdirpath: مسیر یک دایرکتوری را به عنوان دایرکتوری ریشه پیمایش می‌کند و مسیر هر دایرکتوری را که می‌بیند به همراه نام دایرکتوری‌ها و فایل‌های درون آن برمی‌گرداند. [اسناد پایتون]:

    dir1
    ├── dir2
    │   └── file21
    ├── file11
    └── file12
    
    >>> import os
    
    >>> tuple(os.walk('/home/saeid/Documents/dir1'))
    (('/home/saeid/Documents/dir1', ['dir2'], ['file12', 'file11']), ('/home/saeid/Documents/dir1/dir2', [], ['file21']))
    
    >>> import os
    
    >>> for root, dirs, files in os.walk('/home/saeid/Documents/dir1'):
    ...     print('Found directory: {}'.format(root))
    ...     for filename in files:
    ...         print('\t{}'.format(filename))
    ...
    Found directory: /home/saeid/Documents/dir1
      file12
      file11
    Found directory: /home/saeid/Documents/dir1/dir2
      file21
    >>>
    

    جهت پیمایش دایرکتوری‌ها به صورت پیش‌فرض از بالا (دایرکتوری ریشه) به پایین است که می‌توان با False قرار دادن آرگومان اختیاری topdown آن را معکوس نمود:

    >>> for root, dirs, files in os.walk('/home/saeid/Documents/dir1', topdown=False):
    ...     print('Found directory: {}'.format(root))
    ...     for filename in files:
    ...         print('\t{}'.format(filename))
    ...
    Found directory: /home/saeid/Documents/dir1/dir2
        file21
    Found directory: /home/saeid/Documents/dir1
        file12
        file11
    >>>
    
  • os.sep: این متغیر حاوی کاراکتری می‌باشد که سیستم‌عامل از آن برای جدا سازی اجزای یک مسیر استفاده می‌کند. مانند: / در گنولینوکس یا \\ در ویندوز [اسناد پایتون]

  • os.extsep: این متغیر حاوی کاراکتری می‌باشد که در سیستم‌عامل جاری از آن برای جدا سازی نام فایل از پسوند آن استفاده می‌گردد. مانند: . (نام فایل: script.py) [اسناد پایتون]

  • os.pardir: حاوی مقداری است که در سیستم‌عامل جاری از آن برای اشاره به یک دایرکتوری بالاتر از دایرکتوری جاری استفاده می‌گردد (Parent Directory). مانند: .. در گنولینوکس و ویندوز [اسناد پایتون]:

    # GNU/Linux
    
    ~ pwd
    /home/saeid/Documents
    
    ~ cd ..
    
    ~ pwd
    /home/saeid
    
  • os.curdir: حاوی مقداری است که در سیستم‌عامل جاری از آن برای اشاره به دایرکتوری جاری استفاده می‌گردد (Current Directory). مانند: . در گنولینوکس و ویندوز [اسناد پایتون]:

    # GNU/Linux
    
    ~ pwd
    /home/saeid
    
    ~ cd .
    
    ~ pwd
    /home/saeid
    
    ~ cd ./..
    
    ~ pwd
    /home
    

os.path

این ماژول توابعی مفیدی برای کار با مسیر فایل‌ها و دایرکتوری‌ها پیاده‌سازی کرده است [اسناد پایتون].

Caution

برای خواندن و نوشتن فایل‌ها از ()open و برای دسترسی به سیستم‌فایل از ماژول os استفاده نمایید.

  • (os.path.split(path: مسیر path دریافتی را به یک تاپل (dirname, basename) تجزیه می‌کند که در آن basename آخرین بخش از مسیر path و dirname نیز هر آنچه قبل از basename باشد، خواهند بود [اسناد پایتون]:

    >>> import os.path
    
    >>> for path in [ '/one/two/three',
    ...               '/one/two/three/',
    ...               '/',
    ...               '.',
    ...               '']:
    ...     print ('"%s" : "%s"' % (path, os.path.split(path)))
    ...
    "/one/two/three" : "('/one/two', 'three')"
    "/one/two/three/" : "('/one/two/three', '')"
    "/" : "('/', '')"
    "." : "('', '.')"
    "" : "('', '')"
    >>>
    
  • (os.path.basename(path: مقداری برابر با بخش دوم از تاپل خروجی تابع (os.path.split(path را برمی‌گرداند [اسناد پایتون]:

    >>> import os.path
    >>>
    >>> for path in [ '/one/two/three',
    ...               '/one/two/three/',
    ...               '/',
    ...               '.',
    ...               '']:
    ...     print ('"%s" : "%s"' % (path, os.path.basename(path)))
    ...
    "/one/two/three" : "three"
    "/one/two/three/" : ""
    "/" : ""
    "." : "."
    "" : ""
    >>>
    
  • (os.path.dirname(path: مقداری برابر با بخش یکم از تاپل خروجی تابع (os.path.split(path را برمی‌گرداند [اسناد پایتون]:

    >>> import os.path
    >>>
    >>> for path in [ '/one/two/three',
    ...               '/one/two/three/',
    ...               '/',
    ...               '.',
    ...               '']:
    ...     print ('"%s" : "%s"' % (path, os.path.dirname(path)))
    ...
    "/one/two/three" : "/one/two"
    "/one/two/three/" : "/one/two/three"
    "/" : "/"
    "." : ""
    "" : ""
    >>>
    
  • (os.path.splitext(path: مشابه تابع (os.path.split(path است با این تفاوت که پسوند را از path جدا کرده و نتیجه را به شکل تاپل بر می‌گرداند [اسناد پایتون]:

    >>> import os.path
    >>>
    >>> for path in [ 'filename.txt',
    ...               'filename',
    ...               '/path/to/filename.txt',
    ...               '/',
    ...               '.',
    ...               '']:
    ...     print ('"%s" : "%s"' % (path, os.path.splitext(path)))
    ...
    "filename.txt" : "('filename', '.txt')"
    "filename" : "('filename', '')"
    "/path/to/filename.txt" : "('/path/to/filename', '.txt')"
    "/" : "('/', '')"
    "." : "('.', '')"
    "" : "('', '')"
    >>>
    
  • (os.path.join(*paths: اجزای یک مسیر را به یکدیگر متصل می‌کند [اسناد پایتون]:

    # GNU/Linux
    
    import os
    
    >>> os.path.join('one', 'two', 'three')
    'one/two/three'
    
    >>> os.path.join(os.sep, 'one', 'two', 'three')
    '/one/two/three'
    
    # Windows
    
    import os
    
    >>> os.path.join('one', 'two', 'three')
    'one\\two\\three'
    
    >>> os.path.join(os.sep, 'one', 'two', 'three')
    '\\one\\two\\three'
    

    همچنین برای ایجاد چندین مسیر به صورت همزمان، می‌توان اجزای هر مسیر را به صورت یک تاپل (یا لیست) درون یک لیست قرار داد و سپس با استفاده از حلقه for، اجزای هر مسیر را جداگانه به تابع join ارسال نمود. البته باید توجه داشت که می‌بایست پارامتر مشخص شده در تعریف تابع join با یک ستاره مشخص شده باشد؛ در این حالت اجزای درون یک تاپل (یا لیست) به صورت پارامترهای جدا تابع در نظر گرفته می‌شوند، چیزی مانند نمونه کد بالا - در درس تابع دوباره به این شیوه ارسال پارامتر اشاره خواهد شد - به نمونه کد پایین توجه نمایید:

    >>> import os
    
    >>> for parts in [ ('one', 'two', 'three'),
    ...                ('/', 'one', 'two', 'three'),
    ...                ('/one', 'two', '/three', 'four'),
    ...                ]:
    ...     print (parts, ':', os.path.join(*parts))
    ...
    ('one', 'two', 'three') : one/two/three
    ('/', 'one', 'two', 'three') : /one/two/three
    ('/one', 'two', '/three', 'four') : '/three/four'
    >>>
    

    Note

    هر مسیر می‌بایست دقیقا شامل یک کاراکتر جدا کننده دایرکتوری (os.sep) باشد در غیر این صورت اجزا فقط از آخرین نمونه به بعد در نظر گرفته می‌شوند. این اتفاق در تاپل سوم ('one', 'two', '/three', 'four/') از نمونه کد بالا رخ داده است.

  • (os.path.expanduser(path: این تابع تنها یک پارامتر با ترکیب user~ می‌پذیرد و کاراکتر ~ را به مسیر دایرکتوری کاربر user در سیستم عامل تبدیل می‌کند [اسناد پایتون]:

    # GNU/Linux
    
    >>> os.path.expanduser('~saeid')
    '/home/saeid'
    
    # Windows
    
    >>> os.path.expanduser('~saeid')
    'C:\\Documents and Settings\\saeid'
    
    # GNU/Linux
    
    >>> for user in [ '', 'saeid', 'www-data', 'postgres' ]:
    ...     lookup = '~' +  user
    ...     print (lookup, ':', os.path.expanduser(lookup))
    ...
    ~ : /home/saeid
    ~saeid : /home/saeid
    ~www-data : /var/www
    ~postgres : /var/lib/postgresql
    >>>
    
  • (os.path.expandvars(path: این تابع مقدار متغیرهای محیطی موجود در پارامتر دریافتی را جایگزین کرده و حاصل را برمی‌گرداند. نام متغیرها می‌بایست با الگوی name$ داخل پارامتر ذکر گردند. [اسناد پایتون]:

    >>> import os
    
    >>> os.environ['MYVAR'] = 'VALUE'
    >>> os.path.expandvars('/path/to/$MYVAR')
    '/path/to/VALUE'
    
  • (os.path.normpath(path: مسیر را نرمال‌سازی می‌کند. در این راه تمام مسیرهایی که به یکی از اشکال A//B A/B/ A/./B A/foo/../B هستند، به صورت A/B ارزیابی می‌شوند. همچنین در سیستم عامل ویندوز کاراکتر جداکننده دایرکتوری گنولینوکس (/) را به \ تبدیل می‌کند [اسناد پایتون]:

    >>> for path in [ 'one//two//three',
    ...               'one/./two/./three',
    ...               'one/../one/two/three',
    ...               ]:
    ...     print (path, ':', os.path.normpath(path))
    ...
    one//two//three : one/two/three
    one/./two/./three : one/two/three
    one/../one/two/three : one/two/three
    >>>
    
    # Windows
    
    >>> for path in [ 'one/two/three',
    ...
    ...               'one\\two\\three',
    ...               'one\\.\\two\\.\\three',
    ...               'one\\..\\one\\two\\three',
    ...               ]:
    ...     print (path, ':', os.path.normpath(path))
    ...
    one/two/three : one\two\three
    one\two\three : one\two\three
    one\.\two\.\three : one\two\three
    one\..\one\two\three : one\two\three
    
  • (os.path.abspath(path: مسیر نسبی را نرمال‌سازی کرده و به مسیر مطلق (Absolute - مسیری از ابتدا یا همان روت سیستم فایل - در گنولینوکس: مسیری که با / شروع شده باشد - در ویندوز: مسیری که با نام یک درایو شروع شده باشد) تبدیل می‌کند. حاصل این تابع برابر با حاصل (os.path.normpath(os.path.join(os.getcwd(), path) می‌باشد. [اسناد پایتون]:

    >>> import os
    
    >>> os.getcwd()
    '/mnt/Data/WorkSpace/PythonPersianTutorial'
    
    >>> for path in [ '.',
    ...               '..',
    ...               './one/two/three',
    ...               '../one/two/three']:
    ...     print ('"%s" : "%s"' % (path, os.path.abspath(path)))
    ...
    "." : "/mnt/Data/WorkSpace/PythonPersianTutorial"
    ".." : "/mnt/Data/WorkSpace"
    "./one/two/three" : "/mnt/Data/WorkSpace/PythonPersianTutorial/one/two/three"
    "../one/two/three" : "/mnt/Data/WorkSpace/one/two/three"
    >>>
    
    # Windows
    
    >>> import os
    
    >>> os.getcwd()
    'C:\\Python34'
    
    >>> for path in [ '.',
    ...               '..',
    ...               './one/two/three',
    ...               '../one/two/three']:
    ...     print ('"%s" : "%s"' % (path, os.path.abspath(path)))
    ...
    "." : "C:\Python34"
    ".." : "C:\"
    "./one/two/three" : "C:\Python34\one\two\three"
    "../one/two/three" : "C:\one\two\three"
    >>>
    
  • گاهی لازم است که یک مسیر بررسی شود که آیا مربوط به یک فایل است یا دایرکتوری یا لینک نمادین (Symbolic link)، مسیر مطلق (Absolute) است یا خیر، اصلا وجود دارد یا خیر و … برای این منظور می‌توان از توابع پایین استفاده کرد:

    isabs(path): چنانچه مسیر مطلق باشد True برمی‌گرداند [اسناد پایتون]

    isfile(path): چنانچه مسیر مربوط به یک فایل که موجود نیز هست باشد True برمی‌گرداند. این تابع لینک‌های به فایل را نیز دنبال می‌کند، پس این تابع می‌تواند همراه با تابع islink برای یک مسیر مشخص مقدار True را برگرداند. [اسناد پایتون]

    isdir(path): چنانچه مسیر مربوط به یک دایرکتوری که موجود نیز هست باشد True برمی‌گرداند. این تابع لینک‌های به دایرکتوری را نیز دنبال می‌کند، پس این تابع می‌تواند همراه با تابع islink برای یک مسیر مشخص مقدار True را برگرداند. [اسناد پایتون]

    islink(path): چنانچه مسیر مربوط به یک لینک نمادین باشد True برمی‌گرداند. [اسناد پایتون]

    exists(path): چنانچه مسیر دریافتی صرف نظر از اینکه مربوط به یک فایل است یا دایرکتوری، موجود باشد True برمی‌گرداند. [اسناد پایتون]

    lexists(path):چنانچه مسیر لینک نمادین دریافتی موجود باشد True برمی گرداند. این تابع لینک را دنبال نمی‌کند و بررسی نمی‌کند که لینک سالم هست یا خیر. [اسناد پایتون]

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    # Python 3.x
    # File Name: file_script.py
    
    import os
    
    for path in [ __file__, os.path.dirname(__file__), '/', '/var/www/html/wordpress']:
        print ('Path            :', path)
        print ('Absolute        :', os.path.isabs(path))
        print ('Is File?        :', os.path.isfile(path))
        print ('Is Directory?   :', os.path.isdir(path))
        print ('Is Link?        :', os.path.islink(path))
        print ('Is Mount point? :', os.path.ismount(path))
        print ('Exists?         :', os.path.exists(path))
        print ('Link Exists?    :', os.path.lexists(path))
        print ()
    
    Path            : /home/saeid/Desktop/file_script.py
    Absolute        : True
    Is File?        : True
    Is Directory?   : False
    Is Link?        : False
    Is Mount point? : False
    Exists?         : True
    Link Exists?    : True
    
    Path            : /home/saeid/Desktop
    Absolute        : True
    Is File?        : False
    Is Directory?   : True
    Is Link?        : False
    Is Mount point? : False
    Exists?         : True
    Link Exists?    : True
    
    Path            : /
    Absolute        : True
    Is File?        : False
    Is Directory?   : True
    Is Link?        : False
    Is Mount point? : True
    Exists?         : True
    Link Exists?    : True
    
    Path            : /var/www/html/wordpress
    Absolute        : True
    Is File?        : False
    Is Directory?   : True
    Is Link?        : True
    Is Mount point? : False
    Exists?         : True
    Link Exists?    : True
    

    متغیر __file__ در هر اسکریپتی به نام کامل آن اسکریپت اشاره دارد.

    مسیر چهارم در نمونه کد بالا در واقع مسیر لینکی است به یک دایرکتوری دیگر.



😊 امیدوارم مفید بوده باشه

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

گزارش توسعه

00109 - سه‌شنبه ۲۶ اردیبهشت ۱۳۹۶

درس یازدهم کامل شد. 😉


00108 - یک‌شنبه ۲۱ آذر ۱۳۹۵

ببخشید؛ بابت تاخیر بسیار طولانی در بروزرسانی کتاب. درس یازدهم با عنوان «کتابخانه استاندارد (بخش ۱)» به فهرست کتاب افزوده شد.

  • بخش پیش‌گفتار ایجاد گردید.
  • پاراگراف‌هایی از دروس گذشته اصلاح گردید.
  • فونت قالب به «بهداد» تغییر داده شد.

00107 - جمعه ۲۰ آذر ۱۳۹۴

درس دهم با عنوان «ورودی و خروجی» به فهرست کتاب افزوده شد. 😉


00106 - دوشنبه ۲۰ مهر ۱۳۹۴

درس نهم با عنوان «دستورهای کنترلی» به فهرست کتاب افزوده شد.


00105 - شنبه ۲۸ شهریور ۱۳۹۴

درس هشتم با عنوان «انواع آماده شی - بخش دوم» به فهرست کتاب افزوده شد.


00104 - پنج‌شنبه ۲۶ شهریور ۱۳۹۴

تعدادی اشتباه نوشتاری از دروس موجود (۱-۷) اصلاح گردید. توضیح بخش عملگر NOT بیتی از درس ششم نیز به منظور درک پذیری بیشتر تغییر داده شد.


00103 - جمعه ۶ شهریور ۱۳۹۴

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


00102 - چهار‌شنبه ۲۸ مرداد ۱۳۹۴

درس هفتم با عنوان «انواع آماده شی - بخش یکم» به فهرست کتاب افزوده شد.


00101 - سه‌شنبه ۲۷ مرداد ۱۳۹۴

افزودن صفحه «گزارش رویداد‌ها» - این صفحه با هدف آگاه‌ ساختن خوانندگان از تغییرات محتوا کتاب ایجاد شده است. از آنجا که این کتاب به تدریج و با فاصله زمانی کامل می‌شود؛ بنابراین امکان تغییر و اصلاح در نوشته‌های آن، چه در زمان تهیه و چه حتی پس از پایان وجود دارد و همچنین ممکن است بخشی از نوشته‌ها با تذکر یا پیشنهاد خوانندگان تغییر، اصلاح یا اضافه گردد که بر همین اساس نیاز به صفحه‌ای برای درج این تغییرات و ذکر علت یا نام افراد موثر ناگزیر می‌بود.


Note

کتاب در حال تکمیل است!.