کتاب عصر پایتون/فصل سوم: انواع داده‌های استاندارد در پایتون

ویکی‎کتاب، کتابخانهٔ آزاد

کتاب عصر پایتون به کمک علاقه‌مندان ایرانی پایتون جمع‌آوری شده است.

فصل سوم: انواع داده‌های استاندارد در پایتون[ویرایش]

ساختمان داده چیست ؟[ویرایش]

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

در زبان‌های سطح‌پایین‌تر ـ که اکثر آن‌ها از پایه‌های پایتون به حساب می آیند ـ انواع دادۀ پیش‌فرض انواعی ابتدایی هستند که در زبان اسمبلی نیز قابل تعریف می‌باشند. به عنوان مثال در زبان C از انواع int , char,float, double, long ,short استفاده می‌شود که همگی دارای خاصیتی مشترک هستند و این خاصیت این است که روی پردازنده به طور مستقیم دارای دستورالعمل‌هایی هستند که می‌توان با آن‌ها کار کرد. همچنین برای ایجاد یک زنجیره (آرایه) از این انواع از علامت “[]” استفاده می‌شد، ولی از این انواع داده غیر از عملیات ریاضی کاری بر نمی‌آید، مگر این که از آن‌ها با قراردادهای خاصی ساختمان‌داده‌هایی بسازیم.

انواع ساختمان داده در پایتون[ویرایش]

  1. یکی از مهم‌ترین و پرکاربردترین این ساختمان‌های داده رشته‌های کاراکتری هستند؛ که در واقع یک دنباله (Sequence) از بایت‌ها می‌باشند که در کار با ورودی‌ها، خروجی‌ها و ارتباطات گوناگون نقش مهمی ایفا می‌کنند. زیرا یکی از راه‌های محدود فهم انسان از دنیای کامپیوتر ارتباط متنی با این جهان است.
  2. دیگر ساختمان داده‌ای مهم در این زبان لیست‌ها (آرایه‌ها) هستند. در واقع این نوع داده یک نوع بسیار پیشرفته از آرایه‌های زبان‌های سطح پایین است که علاوه‌بر خاصیت اندیس‌پذیری، خاصیت تغییر اندازه و نگهداری انواع داده را به‌طور هم‌زمان دارا است.
  3. چندتایی‌های مرتب (Tuple) در پایتون نوعی از داده با شباهت‌هایی به لیست است که در بخش مربوطه به تفاوت‌ها و شباهت‌های این دو نوع خواهیم پرداخت.
  4. یک نوع دیگر داده در پایتون چرخنده (Iterator) است که به عنوان یک فریم یا واحد چرخنده در طول لیست‌ها، چندتایی‌ها و رشته‌ها محسوب می‌شود.

ساختمان داده‌های دیگر[ویرایش]

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

  1. لیست‌های پیوندی
    1. یک‌طرفه
    2. دوطرفه
    3. حلقوی
  2. صف‌ها
    1. صف‌های دو طرفه
    2. صف‌های با اولویت
  3. درخت‌ها
    1. دودویی
    2. دودویی جستجو
    3. درخت‌های دو-سه
  4. heap
    1. Deap
    2. MinMax Heap

رشته[ویرایش]

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

تعریف رشته[ویرایش]

برای تعریف رشته بعد از علامت مساوی متن مورد نظر خود را در دو کُتیشن (‘) و یا داخل دو دابل کتیشن (“) قرار می‌دهیم برای فهم بیشتر به مثال زیر توجه کنید

>>>Bijoo = 'Hi Python'      # Single quotes
>>>Bijoo = "Hi Python"      # Double quotes

رشته‌های چندخطی[ویرایش]

برای تعریف این نوع رشته‌ها متن را باید در داخل دو علامت “”” قرار دهید، به‌عنوان مثال اگر شما کد زیر را وارد نمایید و کلید اینتر را بزنید؛ باز هم می‌توانید متن را وارد نرم‌افزار کنید و تا زمانی که دوباره علامت “”” را به کار نبرده‌اید می‌توانید تایپ کنید و از اینتر استفاده کنید.

>>>Bijoo = """ hi

برای فهم بهتر به مثال زیر توجه کنید.

>>>Bijoo = """ hi
i like python
what about
you"""
>>>

رشته‌های مخلوط[ویرایش]

برای استفاده از علامت ” یا ‘ در متن خود استفاده کنید؛ به دو مثال زیر توجه نمایید.

برای استفاده از ‘ در متن:

>>>Bijoo = "'Hi Py'thon'"
>>>print Bijoo
'Hi Py'thon'

برای استفاده از ” در متن:

>>>Bijoo = '"Hi "Py"th"on"'
>>>print Bijoo
"Hi "Py"th"on"

نمایش مقدار رشته‌ها[ویرایش]

برای اینکار می توانید از دستور print استفاده نمایید

>>>Bijoo = 'Hi Python'
>>>print Bijoo
Hi Python

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

کد زیر را در مفسر یا همان قسمتی که در آن کد می نویسید وارد کنید

>>>print u'Bijoo'

نتیجه Bijoo خواهد بود و حرف u از بین می رود ؟! به نظر شما چرا؟ برای خود چند مثال بزنید و نتیجه‌ها را ببینید

کد زیر را هم امتحان کنید

>>>u'Bijoo'

نتیجه چه خواهد بود؟ توجه داشته باشید که حرف u بیرون از کتیشن است پس چرا؟

لیست[ویرایش]

لیست‌ها نوعی متغیر هستند که می‌توان در آن‌ها داده‌ها و اطلاعات از انواع مختلف را ذخیره کرد

به طور مثال در کد زیر لیستی به نام L ایجاد شده است که در آن یک متغیر از نوع رشته یا string ، یک float یا عدد اعشاری و یک integer یا عدد صحیح در آن وجود دارد

>>> L = [ 'mahdy' , 20 , 1.2 ]

دسترسی به داده‌های درون لیست[ویرایش]

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

عدد اندیس بین صفر و بی‌نهایت است و به ترتیب از چپ به راست به مقدارهای درون لیست داده می‌شود. [ 'mahdy' , 20 , 1.2 ] در مثال بالا رشتۀ 'mahdy' با اندیس 0 و عدد 20 با اندیس 1 و عدد اعشاری 1.2 با اندیس 2 مشخص می‌شوند برای به‌دست آوردن دادۀ یک اندیس کافی است فقط اندیس مورد نظر را درون [] جلوی نام لیست قرار دهیم.

>>> L = [ 'mahdy' , 20 , 1.2 ]
>>> L[1]
20

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

>>> L=[ 'mahdy' , 20 , [ 'ali' , 99 ] , 1.2]
>>> L[2][0]
'ali'

در مثال بالا دیدید که اندیس اول ([2]L) به داده‌ای اشاره دارد که خود یک لیست است ([ ali' , 99' ]) و اندیس دوم ([0][2]L) به دادۀ درون این لیست اشاره دارد ('ali'). این روش قابل تعمیم به لیست‌هایی با پیچیدگی بیشتر است.

نکتۀ ۱: اگر درون [] عبارت محاسبه‌ای قرار بگیرد ابتدا عبارت محاسبه می‌شود و سپس بقیۀ عملیات طبق روال توضیح داده شده در بالا انجام می‌پذیرد.

نکتۀ ۲: اگر اندیس قرار گرفته در [] در محدودۀ شمارۀ اندیس‌ها نباشد پیغام خطا ظاهر می‌شود.

نکتۀ ۳: از خواص لیست‌ها انتساب هر یک از داده‌های درون لیست به متغیرهایی است که همگی تشکیل یک لیست می‌دهند.

نکتۀ ۴: در شماره‌گذاری اندیس‌های لیست برنامه‌نویس دخیل نیست بدین ترتیب که می‌توان از راست به چپ هم به داده‌ها درون لیست دسترسی داشت. در این صورت اندیس از -1 شروع شده و به صورت نزولی اندیس‌ها شماره‌گذاری می‌شوند. البته انتخاب هر روش به دلخواه برنامه‌نویس است.

نکتۀ ۵: فقط عملگرهای + و * روی لیست‌ها تعریف شده‌اند. عملگر + بین یک لیست و لیستی دیگر تعریف شده و اپراتور * بین یک لیست و یک عدد تعریف شده است و هر دو شبیه به رشته‌ها عمل می‌کنند.

دسترسی به مجموعه‌ای از داده‌های درون لیست[ویرایش]

ممکن است بخواهیم به بُرشی از داده‌های درون لیست دسترسی داشته باشیم برای این کار به جای [] از [:] استفاده می‌کنیم. به مثال زیر توجه کنید.

>>> L=[ 'mahdy' , 'ali' , 100 , 99 , 'reza' , 20 ]
>>> L[1:5]
['ali', 100, 99, 'reza']

خوب، دیدید که [1:5]L از داده‌ای که اندیسش 1 است تا ماقبل 5 را درون یک لیست قرار می‌دهد.

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

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

>>> L=[ 'mahdy' , 'ali' , 100 , 99 , 'reza' , 20 ]
>>> L[1:]
[ 'ali' , 100 , 99 , 'reza' , 20 ]
>>> L[1:1]
[]

تغییر مقادیر درون لیست[ویرایش]

لیست‌ها از داده‌های تغییرپذیرند و می‌توان با استفاده از عمل انتساب (=) مقادیر یک لیست را تغییر داد.

>>> L = [ 'mahdy' , 'ali' , 100 , 99 , 'reza' , 20 ]
>>> L[1] = 'boys'
>>> L[1]
'boys'
>>> L
['mahdy' , 'boys' , 100 , 99 , 'reza' , 20 ]

اضافه کردن داده در لیست[ویرایش]

بدون استفاده از عملیات محاسباتی می‌توان داده‌ای را به لیست اضافه کرد.

>>> L = [ 1 , 2 , 3 ]
>>> L[3:3] = [4]
>>> L
[ 1 , 2 , 3 , 4 ]

حذف داده از لیست[ویرایش]

برای حذف داده می‌توانیم از عمل انتساب استفاده کنیم. بدین ترتیب که داده را به [] انتساب بدهیم.

>>> L = [ 1 , 2 , 3 , 4 ]
>>> L[1:2] = []
>>> L
[ 1 , 3 , 4 ]

نكتۀ مهم در این قسمت این است كه [1:2]L تنها بخشی از لیست را حذف می‌كند كه اندیس آن 1 است. حال اگر بنویسم [0:2]L بخش‌هایی كه اندیس آن‌ها 0 و 1 است حذف می‌شوند. از ابتدا تا قبل از انتها با استفاده از دستور del می‌توان هر داده یا کل لیست را حذف کرد.

متد های مهم برای لیست[ویرایش]

دستور (با فرض اینکه L لیست باشد) توضیحات
(L.append(x دادۀ x را به انتهای لیست L اضافه کن
(L.remove(x دادۀ x را از لیست L حذف کن
(L.index(x اندیس x در لیست L را برمی‌گرداند
(L.count(x تعداد دفعات تکرار x را در لیست L را برمی‌گرداند
(L.extend(x لیست x را با لیست L الحاق می‌کند
(L.insert(I,x دادۀ x را درشماره اندیس I به لیست اضافه می‌کند

تاپل[ویرایش]

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

تاپل‌ها با کاما (,) از هم جدا می‌شوند. شکل ظاهری تاپل‌ها همانند این است که چند داده را به یک متغیر انتساب بدهید اما باید بدانید که نوع دادۀ نگهداری شده از نوع تاپل است. شما می‌توانید برای تشخیص راحت و زیبایی کدتان از پرانتز ( ) استفاده کنید و داده‌ها را در داخل پرانتز قرار دهید اما به این نکته توجه داشته باشید که علامت ( ) نشان‌دهندۀ تاپل بودن داده نیست.

مثالی برای درک بهتر:

در این مثال دو متغیر از نظر نوع داده‌ها و مقدار داده‌ها با هم تفاوتی ندارند. اما از نظر مکان ذخیره‌سازی داده‌ها با هم متفاوت هستند.

a = 1, 2, 3, 4
b = (1, 2, 3, 4)

نکتۀ ۱: توجه داشته باشید که داده‌های چندقسمتی می‌توانند داده‌های چندقسمتی دیگر را در خود نگه دارند. نکتۀ ۲: برای تاپل‌های تک‌عضوی باید به صورت زیر عمل کنید:

a = 33      # اين يک متغير ساده است
b = 33, # اين يک داده از نوع تاپل است

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

اپراتورها در تاپل[ویرایش]

اپراتورهایی که برای تاپل‌ها تعریف شده‌اند عبارت‌اند از: + بین دو تاپل و * بین یک عدد و تاپل.

سعی کنید برای این کار تاپل‌ها را درمیان پرانتز قرار دهید یا به یک متغیر انتساب دهید به مثال توجه کنید:

>>>1, 2, 3 + 4, 5, 6
(1, 2, 7, 5, 6)
>>>(1, 2, 3) + (4, 5, 6)
(1, 2, 3, 4, 5, 6)

دسترسی به داده‌های درون تاپل این قسمت همانند لیست‌ها است. و نیازی به توضیح بیشتر نیست. (به آموزش مربوطه در قسمت لیست‌ها مراجعه کنید).

فقط یک مثال ساده...

>>> T = (1, 2, 3)
>>> T[0]
1

نکته: تاپل‌ها از نوع داده‌های تغییرناپذیرند. یعنی نمی‌توان آن‌ها را به‌طور مستقیم تغییر داد. ولی به‌طور غیرمستقیم امکان دارد. به مثال زیر توجه کنید.

>>> T = (11, 22, 33, 44)
>>> T [0] = 55

Traceback (most recent call last):
File "<pyshell#1>", line 1, in toplevel-
    t[0] = 11
TypeError: object does not support item assignment

>>> T = (55,) + T[0:3]
>>> T
(55, 22, 33, 44)

نکتۀ بعدی این است که بعضی از اعمال روی لیست‌ها روی تاپل نیز جواب می‌دهند. پس امتحان کنید...

نکات زیادی در مورد تاپل‌ها (و همۀ قسمت‌های پایتون) وجود دارد که در این مقوله نمی‌گنجد. پس سعی کنید که خودتان به این نکات دست پیدا کنید.

دیکشنری[ویرایش]

دیکشنری‌ها نیز از جمله داده‌های چند قسمتی هستند آغاز دیکشنری‌ها با } و پایان آن‌ها با { مشخص می‌شود و داده‌های آن با علامت , از هم جدا می‌شوند. در هر خانه و هر قسمت دیکشنری علاوه‌بر داده، اندیس مربوط به آن نیز آمده است بر خلاف رشته‌ها، لیست‌ها و تاپل‌ها، اندیس داده‌ها در دیکشنری به دلخواه برنامه‌نویس مشخص می‌شود. اندیس داده‌ها علاوه‌بر عدد؛ رشته، تاپل و هر دادۀ غیرقابل تغییر دیگر نیز می‌تواند باشد. به کمک علامت : اندیس هر داده را مشخص می‌کنیم بدین ترتیب که داده در سمت راست علامت : و اندیس آن در سمت چپ : نوشته می‌شود. قابل ذکر است که اندیس‌ها در دیکشنری نمی‌تواند یک دادۀ تغییرپذیر لیست، یا دیکشنری باشد. داده‌های درون دیکشنری از هر نوع می‌تواند باشد.

{ 'ali':20 , 'mahdy':'m' , 22:11 }

دسترسی به داده‌های درون دیکشنری دسترسی به داده‌های درون یک دیکشنری با قرار دادن اندیس دادۀ مورد نظر درون [ ] در مقابل دیکشنری امکان‌پذیر است.

>>> D = { (1,2):11 , 'mahdy':'m' , 78:88 }
>>> D['mahdy']
'm'
>>> D[(1,2)]
11

توجه داشته باشید که ممکن است در اندیس داده‌های دیکشنری اندیس‌های مثل هم وجود داشته باشد که در این صورت تنها مقدار اولین داده از سمت راست با همان اندیس نشان داده می‌شود و در حقیقت دیگر داده‌های موجود با آن اندیس از دیکشنری حذف می‌شوند.

>>> d = { 'mahdy':'m' , 'python':'c' , 'mahdy':55 }
>>> d['mahdy']
55
>>> d
{'python': 'c', 'mahdy': 55}

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

تغییر و افزودن داده به دیکشنری[ویرایش]

دیکشنری‌ها از داده‌های تغییرپذیرند و می‌توان با علامت انتساب داده‌های هر اندیس را تغییر داد همچنین می‌توان دادۀ جدیدی به همراه اندیس آن به دیکشنری اضافه نمود

>>> d ={'mahdy':'m' , 2:'ali' }
>>> d['reza'] = 66
>>> d
{ 'mahdy':'m' , 2:'ali' , 'reza':66 }

توجه داشته باشید که عملگرهای + و * برای دیکشنری‌ها تعریف نشده‌اند.

دستور del[ویرایش]

با استفاده از این دستور می‌توان هر یک از داده‌های درون دیکشنری و یا حتی کل متغیر را حذف کرد

>>> d = {'mahdy':'m' , 2:'ali' }
>>> del d[2]
>>> d
{ 'mahdy':'m' }

تابع ()len[ویرایش]

این تابع یک دادۀ چندقسمتی به عنوان پارامتر گرفته و تعداد خانه‌های این دادۀ چند قسمتی را برمی‌گرداند. یعنی حاصل تابع عدد صحیح است.

کاربرد دستور for برای دیکشنری[ویرایش]

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

متدهای مربوط به دیکشنری[ویرایش]

نحوۀ فراخوانی متد: نام متد + . + دیکشنری

دستورات مهم دیکشنری (اگر d را یک دیکشنری در نظر بگیریم) توضیحات
( )d.clear تمام داده‌های درون d را حذف می‌کند
( )d.copy یک کپی از d را برمی‌گرداند
(m(d.has_key اگر اندیس m در d باشد True در غیر این صورت False برمی‌گرداند
( )d.keys لیستی از تمام اندیس‌ها را برمی‌گرداند
( )d.values لیستی از تمام داده‌ها را برمی‌گرداند

مجموعه‌ها[ویرایش]

ماژول جدید sets شامل یک پیاده‌سازی از طرف یک مجموعه Datatype است. مجموعه کلاسی است برای مجموعه‌های تغییرپذیر. مجموعه‌هایی که می‌تواند عضو اضافه شده یا کم شده داشته باشد. (برای اطلاعات بیشتر از مجموعه‌های تغییرپذیر به آموزش‌های دیگر در سایت مراجعه کنید)

به مثال زیر توجه کنید.

>>> import sets
>>> S = sets.Set([1,2,3])
>>> S
Set([1, 2, 3])
>>> 1 in S
True
>>> 0 in S
False
>>> S.add(5)
>>> S.remove(3)
>>> S
Set([1, 2, 5])
>>>

اجتماع و اشتراک را در این ماژول می‌توان با استفاده از متدهای union() و intersection() به‌دست آورد. و راه ساده‌تر استفاده از نمادهای & و | است.

>>> S1 = sets.Set([1,2,3])
>>> S2 = sets.Set([4,5,6])
>>> S1.union(S2)
Set([1, 2, 3, 4, 5, 6])
>>> S1 | S2                  # نماد دیگر
Set([1, 2, 3, 4, 5, 6])
>>> S1.intersection(S2)
Set([])
>>> S1 & S2                  # نماد دیگر
Set([])
>>> S1.union_update(S2)
>>> S1
Set([1, 2, 3, 4, 5, 6])

همچنین ممکن است تفاوت و شباهت میان دو مجموعه را نشان داد. در این مجموعه‌ها همۀ عناصر در اجتماع و اشتراک‌ها نیستند. و ممکن است با هم تفاوت داشته باشند. برای این کار ما می‌توانیم از متد symmetric_difference() و یا نماد ^ استفاده کنیم.

>>> S1 = sets.Set([1,2,3,4])
>>> S2 = sets.Set([3,4,5,6])
>>> S1.symmetric_difference(S2)
Set([1, 2, 5, 6])
>>> S1 ^ S2
Set([1, 2, 5, 6])
>>>

همچنین متدهای issubset() و issuperset() برای چک کردن این که آیا یک مجموعه زیرمجموعۀ یا مجوعۀ مرجع دیگری است یا نه به‌کار می‌روند.

>>> S1 = sets.Set([1,2,3])
>>> S2 = sets.Set([2,3])
>>> S2.issubset(S1)
True
>>> S1.issubset(S2)
False
>>> S1.issuperset(S2)
True
>>>