آشنایی با انواع آرایه در پایتون

آرایه در پایتون

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

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


آشنایی با آرایه در پایتون

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

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

از لحاظ عملکرد، دسترسی خواندن به عناصر یک آرایه با استفاده از اندیس آن بسیار سریع بوده و هزینه‌ زمانی برابر با (۱)O دارد. آرایه‌ها در پایتون و کتابخانه‌های استاندارد آن به گونه‌های مختلفی پیاده سازی شده‌اند که در ادامه نگاهی به انواع آن‌ها خواهیم انداخت.


list در پایتون – آرایه‌های تغییر پذیر

لیست در پایتون جزٰء هسته‌ی اصلی این زبان است. علی‌رغم نام آن، از لیست در پایتون به عنوان آرایه‌هایی تغییر پذیر استفاده می‌شود.

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

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

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

>>> arr = ['one', 'two', 'three']
>>> arr[0]
'one'
 
# Lists have a nice repr:
>>> arr
['one', 'two', 'three']
 
# Lists are mutable:
>>> arr[1] = 'hello'
>>> arr
['one', 'hello', 'three']
 
>>> del arr[1] 
>>> arr
['one', 'three']
 
# Lists can hold arbitrary data types:
>>> arr.append(23) 
>>> arr
['one', 'three', 23]

tuple در پایتون – آرایه‌های تغییر ناپذیر

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

تاپل‌ها نیز می‌توانند انواع مختلفی از داده‌ها را درون خود نگه دارند. اما همانند لیست‌ها، این عمل باعث می‌شود تا یک تاپل فضای حافظه‌ی بیشتری اشغال کند.

>>> arr = 'one', 'two', 'three'
>>> arr[0]
'one'

# Tuples have a nice repr:
>>> arr
('one', 'two', 'three')
 
# Tuples are immutable:
>>> arr[1] = 'hello'
TypeError:
"'tuple' object does not support item assignment"
 
>>> del arr[1]
TypeError:
"'tuple' object doesn't support item deletion"
 
# Tuples can hold arbitrary data types:
# (Adding elements creates a copy of the tuple) 
>>> arr + (23,)
('one', 'two', 'three', 23)

array.array در پایتون – ساختار پایه‌ای آرایه‌ها

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

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

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

>>> import array
>>> arr = array.array('f', (1.0, 1.5, 2.0, 2.5)) 
>>> arr[1]
۱.۵
 
# Arrays have a nice repr:
>>> arr
array('f', [1.0, 1.5, 2.0, 2.5])
 
# Arrays are mutable:
>>> arr[1] = 23.0
>>> arr
array('f', [1.0, 23.0, 2.0, 2.5])
 
>>> del arr[1]
>>> arr
array('f', [1.0, 2.0, 2.5])
 
>>> arr.append(42.0)
>>> arr
array('f', [1.0, 2.0, 2.5, 42.0])
 
# Arrays are "typed":
>>> arr[1] = 'hello'
TypeError: "must be real number, not str"

str در پایتون – آرایه‌هایی تغییر ناپذیر از کاراکترها

پایتون از آبجکت‌های str به منظور ذخیره سازی دنباله‌ای از کاراکترهای یونیکدِ تغییر ناپذیر استفاده می‌کند. یعنی str را می‌توان به عنوان آرایه‌ای از کاراکترها در نظر گرفت. به بیان دیگر هر کاراکتر در رشته نیز خود یک آبجکت str به طول ۱ است. این نوع آرایه در پایتون از نظر مصرف حافظه بهینه است.

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

>>> arr = 'abcd' 
>>> arr[1]
'b'
 
>>> arr 
'abcd'
 
# Strings are immutable:
>>> arr[1] = 'e'
TypeError:
"'str' object does not support item assignment"
 
>>> del arr[1]
TypeError:
"'str' object doesn't support item deletion"
 
# Strings can be unpacked into a list to 
# get a mutable representation:
>>> list('abcd')
['a', 'b', 'c', 'd']
>>> ''.join(list('abcd')) 
'abcd'
 
# Strings are recursive data structures:
>>> type('abc') 
"<class 'str'>" 
>>> type('abc'[0]) 
"<class 'str'>"

bytes – آرایه‌هایی تغییر ناپذیر از بایت‌ها

آبجکت‌هایی از بایت، دنباله‌ای تغییر ناپذیر متشکل از تعداد زیادی بایت (اعداد صحیح در بازه‌ی ۰ تا ۲۵۵) هستند. از لحاظ مفهومی، آن‌ها همانند آبجکت str هستند که بجای کاراکتر شامل بایت می‌باشند.

برای ساخت آبجکت‌هایی از نوع بایت باید از سینتکس مخصوص به آن استفاده نمود و آرایه bytes از نظر مصرف حافظه بهینه است. البته نوعی دیگر از این آرایه در پایتون با نام bytearray وجود دارد که برخلاف bytes و str تغییر پذیر هستند.

>>> arr = bytes((0, 1, 2, 3)) 
>>> arr[1]
۱

# Bytes literals have their own syntax:
>>> arr
b'\x00\x01\x02\x03'
>>> arr = b'\x00\x01\x02\x03'

# Only valid "bytes" are allowed:
>>> bytes((0, 300))
ValueError: "bytes must be in range(0, 256)"

# Bytes are immutable:
>>> arr[1] = 23
TypeError:
"'bytes' object does not support item assignment"

>>> del arr[1]
TypeError:
"'bytes' object doesn't support item deletion"

bytearray – آرایه‌هایی تغییرپذیر از بایت‌ها

این نوع از آرایه‌ها متشکل از بایت‌ها (اعداد صحیح در بازه‌ی ۰ تا ۲۵۵) بوده که تغییر پذیر هستند. Bytearrayها بسیار شبیه به bytes در بخش قبل هستند با این تفاوت که شما می‌توانید این نمونه از آرایه‌ها را به راحتی تغییر دهید (عنصری را حذف یا اضافه نمایید).

این نوع از آرایه در پایتون را می‌توان به آرایه‌های تغییر ناپذیر bytes تبدیل نمود. اما توجه داشته باشید که این عمل به صورت کپی کردن تمام محتویات bytearray انجام می‌گیرد که عملی بسیار کند با هزینه‌ی O(n) است.

>>> arr = bytearray((0, 1, 2, 3))
>>> arr[1]
۱

# The bytearray repr:
>>> arr
bytearray(b'\x00\x01\x02\x03')

# Bytearrays are mutable:
>>> arr[1] = 23
>>> arr
bytearray(b'\x00\x17\x02\x03')

>>> arr[1]
۲۳

# Bytearrays can grow and shrink in size:
>>> del arr[1]
>>> arr
bytearray(b'\x00\x02\x03')

>>> arr.append(42)
>>> arr
bytearray(b'\x00\x02\x03*')

# Bytearrays can only hold "bytes"
# (integers in the range 0 <= x <= 255) 
>>> arr[1] = 'hello'
TypeError: "an integer is required"

>>> arr[1] = 300
ValueError: "byte must be in range(0, 256)"

# Bytearrays can be converted back into bytes objects: 
# (This will copy the data)
>>> bytes(arr)
b'\x00\x02\x03*'

نکات کلیدی در هنگام کار با آرایه در پایتون

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

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

  • در صورتی که قصد دارید داده‌هایی با نوع مختلف را در یک آرایه ذخیره کنید، بهتر است از list یا tuple در پایتون استفاده کنید.
  • در صورتی که تنها داده‌هایی به صورت اعداد صحیح یا اعشاری دارید و سرعت عملکرد کار با آرایه‌ها برای شما نیز مهم است، بهتر است تا از array.array در برنامه خود استفاده کنید. همچنین استفاده از کتابخانه‌هایی مانند NumPy و Pandas نیز برای کار با این نوع از داده‌ها پیشنهاد می‌شود.
  • در صورتی که قصد دارید با داده‌هایی به صورت متن کار کنید، بهتر است تا آن‌ها را در متغیری به صورت str ذخیره کنید و یا اگر قصد دارید تا محتویات متن خود را تغییر دهید، در برنامه‌ی خود می‌توانید این متغیر را به صورت کاراکترهایی جداگانه در یک لیست ذخیره نمایید.
  • و اگر قصد دارید داده‌هایی را به صورت بایت ذخیره کنید، بهتر از bytes یا bytearray استفاده نمایید.

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

محمد بابازاده
متخصص DevOps و توسعه دهنده Python