لیست مطالب

تاپل‌ها (tupples) در پایتون: سیر تا پیاز

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

تاپل در زبان پایتون، یک نوع داده غیرقابل تغییر (immutable) است و می‌تواند چند مقدار را به صورت همزمان نگه دارد. برای مثال، می‌توانید از تاپل برای ذخیره‌سازی مختصات یک نقطه مختصات (x, y) یا رنگ RGB (red, green, blue) و حتی یک رکورد پایگاه داده مانند (name, age, job) استفاده کنید. این ویژگی‌ها باعث می‌شوند که تاپل گزینه مناسبی برای موقعیت‌هایی باشد که تعداد اعضا ثابت است و نیازی به تغییر مقادیر وجود ندارد.

توابع و عملگرهای مشترک دنباله‌ها مانند ()len، عملگرهای مقایسه، و همچنین عملیات index، slicing و تکرار (repetition) روی تاپل‌ها نیز قابل استفاده است. اکنون به بررسی دقیق‌تر روش‌های ایجاد و کار با تاپل می‌پردازیم.

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

برای ساختن یک تاپل، باید در یک عبارت تمام اعضا را مشخص کنید. دو روش اصلی برای ساختن تاپل وجود دارد:
  • ساده‌ترین روش؛ اعضا را با کاما از هم جدا می‌کنیم.
  • تابع سازنده ()tuple: می‌توان هر iterable (لیست، مجموعه، رشته و…) را به تاپل تبدیل کرد.

روش ساده ساخت tupple

 لیستی از اشیاء که با کاما از هم جدا شده‌اند. غالباً برای خوانایی بهتر، این موارد را داخل پرانتز قرار می‌دهیم، اگرچه قرار دادن پرانتز ضروری نیست. برای مثال:
				
					
colors = (255, 0, 0)
person = ("Ali", 30, "Engineer")
point = (2, 7)

				
			

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

				
					
days = (
     "Monday",
     "Tuesday",
     "Wednesday",
     "Thursday",
     "Friday",
     "Saturday",
     "Sunday",
 )
days
('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday')

				
			

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

				
					
single = ("Hello",)
print(single) #('Hello',)

print(type(single)) #<class 'tuple'>


not_tuple = (42)
print(not_tuple) #42

type(not_tuple) #<class 'int'>


				
			

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

				
					
empty = ()
print(empty) #()
print(type(empty)) #<class 'tuple'>


				
			

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

				
					print(tuple([1, 2, 3]))                 # خروجی: (1,2,3)

print(tuple("Hello"))                  # خروجی: ('H', 'e', 'l', 'l', 'o')

print(tuple({"a": 1, "b": 2}.values())) # خروجی: (1,2)

print(tuple())                         # خروجی: ()
				
			

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

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

				
					print(tuple(5)) # TypeError: 'int' object is not iterable

t = tuple((5,))
print(t) #  (5,)    خروجی

				
			

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

در مثال بالا 5 یک عدد صحیح (int) است و قابل پیمایش (iterable) نیست.

tuple((5,)):در اینجا یک تاپل تک‌عضوی به تابع داده می‌شود و نتیجه آن همان تاپل (,5) است.

 همچنین اگر آرگومان ()tuple یک iterator مانند عبارت مولد (generator expression) باشد، تابع تمام داده‌های تولیدشده را می‌خواند و در یک تاپل قرار می‌دهد. برای نمونه:

				
					print(tuple(x**2 for x in range(6))) # خروجی: (25, 16, 9, 4, 1, 0)

				
			

در این مثال از یک عبارت مولد برای تولید مربع اعداد ۰ تا ۵ استفاده کردیم و سپس با ()tuple آن‌ها را در یک تاپل قرار دادیم. استفاده از ()tuple زمانی مفید است که بخواهید خروجی یک iterable را به صورت یک‌جا به تاپل تبدیل کنید.

دسترسی به عناصر یک تاپل: اندیس‌گذاری

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

				
					person = ("Sara", 28, "Data Scientist")

print(person[0])   # خروجی: Sara
print(person[1])   # خروجی: 28
print(person[-1])  # خروجی: Data Scientist

				
			

در این مثال، person[0] برابر نامِ فرد و person[1] برابر سن او می‌شود. به همین ترتیب، person[-1] عضو آخر تاپل را برمی‌گرداند. عمل اندیس‌گذاری پیچیدگی زمانی O(1) دارد (مثل لیست)، یعنی دسترسی به هر عنصر زمان ثابت و کمی را می‌برد. اگر بخواهیم طول تاپل را بدانیم، می‌توانیم از تابع ()len استفاده کنیم:

				
					print(len(person))  # خروجی: 3

				
			

تابع ()len تعداد اعضای تاپل را برمی‌گرداند. اگر از اندیسی بزرگ‌تر یا مساوی طول تاپل استفاده کنید، خطای IndexError خواهید گرفت (مثلاً person[3] در مثال بالا خطا می‌دهد). اندیس‌های منفی نیز برای دسترسی از انتها کاربرد دارند (مثلاً person[-2] دومین عضو از انتها را برمی‌گرداند).

استخراج چندین عضو از یک تاپل: برش (Slicing)

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

				
					
tuple[start:stop:step]

				
			
  • start اندیس شروع (شامل آن)،
  • stop اندیس پایان (شامل نمی‌شود)،
  • step گام پیمایش.

هر سه پارامتر اختیاری هستند (به طوری پیش‌فرض start مقادر 0 و stop برابر با طول تاپل و step مقادر ۱ را دارد). برای مثال:

				
					
days = ('Mon','Tue','Wed','Thu','Fri','Sat','Sun')
days[:5]   # پنج روز اول هفته
('Mon', 'Tue', 'Wed', 'Thu', 'Fri')
days[5:]   # دو روز آخر هفته
('Sat', 'Sun')

				
			

در مثال بالا، days[:5] اعضای با اندیس ۰ تا ۴ را (شامل پنج‌شنبه) و days[5:] اعضای با اندیس ۵ و ۶ را برمی‌گردانند. با دستکاری مقادیر شروع، پایان و گام می‌توانید قسمت‌های مختلف تاپل را استخراج کنید. نکته مهم این است که عملگر برش یک تاپل جدید می‌سازد و روی تاپل اصلی تغییری نمی‌دهد.

بررسی تغییرناپذیری تاپل

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

				
					jane = ("Jane Doe", 25, 1.75, "Canada")

jane[3] = "USA"  
# خروجی:
# Traceback (most recent call last):
#   File "your_file.py", line 3, in <module>
#     jane[3] = "USA"
# TypeError: 'tuple' object does not support item assignment

				
			

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

بسته‌بندی و بازگشایی تاپل‌ها (Packing/Unpacking)

پایتون امکان بسته‌بندی (pack) و بازگشایی (unpack) مقادیر با تاپل‌ها را فراهم می‌کند. برای مثال، وقتی بنویسید point = x, y, z، در واقع سه مقدار x, y, z را در یک تاپل جدید بسته‌بندی کرده‌اید. در مقابل، می‌توانید یک تاپل را به متغیرهای جداگانه واگشایی کنید. برای مثال:

				
					
point = (7, 14, 21)
x, y, z = point
x   # 7
y   # 14
z   # 21

				
			

در این مثال، محتویات تاپل point به ترتیب به سه متغیر x، y و z اختصاص داده شدند. ترتیب اهمیت دارد؛ یعنی مقدار اول تاپل به اولین متغیر، مقدار دوم به دومین و الی آخر می‌رود. اگر تعداد متغیرها با تعداد اعضای تاپل هماهنگ نباشد، پایتون خطای ValueError می‌دهد.

یکی از کاربردهای خوب unpacking، جابجایی مقادیر بدون متغیر موقت است. مثلاً برای جابجایی دو مقدار در متغیرهای a و b می‌توان نوشت:

				
					
a = 200
b = 400
a, b = b, a
a   # 400
b   # 200

				
			

بدین ترتیب با یک خط ساده، دو مقدار با هم عوض می‌شوند.

همچنین عملگر ستاره (*) را می‌توان در unpacking به‌کار برد تا تعدادی از مقادیر را در یک متغیر لیست‌وار جمع‌آوری کند. برای نمونه:

				
					
numbers = (1, 2, 3, 4, 5)
*head, last = numbers
head   # [1, 2, 3, 4]
last   # 5

first, *middle, last = numbers
first   # 1
middle  # [2, 3, 4]
last    # 5

				
			

در مثال بالا، با قراردادن * پایتون باقی‌مانده‌ی عناصر تاپل را (که هنوز به متغیر خاصی اختصاص داده نشده‌اند) در آن متغیر قرار می‌دهد

 می‌توان دو یا چند تاپل را با هم ترکیب کرد و سپس unpacking کرد. مثلاً اگر دو تاپل name = (“John”,”Doe”) و contact = (“john@example.com”, “123456”) داشته باشیم، با نوشتن (*name, *contact) می‌توان همه عناصر هر دو تاپل را در یک تاپل جدید کنار هم قرار داد:

				
					
name = ("John", "Doe")
contact = ("john@example.com", "123456")
(*name, *contact)
('John', 'Doe', 'john@example.com', '123456')

				
			

برگرداندن تاپل در توابع

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

				
					def describe(sample):
    from statistics import mean, median, mode
    return mean(sample), median(sample), mode(sample)

result = describe([10, 2, 4, 7, 9])
print(result)         # خروجی: (6.5, 7, 7)
print(type(result))   # خروجی: <class 'tuple'>
				
			

در مثال بالا، تابع describe سه مقدار (median، mean و mode) را برمی‌گرداند که در قالب یک تاپل در result قرار می‌گیرند. با unpack کردن آن نیز می‌توان مستقیماً هر یک از این مقادیر را در متغیر جداگانه گرفت.

ساخت کپی از یک تاپل

از آنجایی که تاپل‌ها تغییرناپذیر هستند، معمولاً نیازی به ساخت کپی جدید از آن‌ها نیست. تکنیک‌های معمول کپی (مانند slice کل تاپل یا استفاده از تابع copy) در واقع تنها یک اشاره جدید به همان شیء اصلی ایجاد می‌کنند و نه یک شیء جدید. مثلاً:

				
					student_info = ("Linda", 18, ["Math", "Physics", "History"])
student_profile = student_info[:]  # یا استفاده از student_info.copy()

print(student_info is student_profile)  # خروجی: True

				
			

نتیجه نشان می‌دهد که student_profile همان شیء تاپل اصلی است و فقط یک alias جدید است. بنابراین هیچ کپی مجزایی ایجاد نشده است. تنها نکته این است که اگر درون تاپل آیتم‌های تغییرپذیر وجود داشته باشند (مثلاً لیست در مثال بالا)، تغییر در آن آیتم روی هر دو “کپی” تأثیر می‌گذارد، زیرا در واقع همان شیء لیست است.

الحاق و تکرار تاپل‌ها

الحاق تاپل‌ها

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

				
					
personal_info = ("John", 35)
professional_info = ("Computer science", ("Python", "Django"))
profile = personal_info + professional_info
profile
('John', 35, 'Computer science', ('Python', 'Django'))

				
			

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

همچنین از عملگر الحاق افزایشی =+می‌توان استفاده کرد که همانند x = x + y عمل می‌کند. حتی در این حالت نیز یک تاپل جدید ساخته می‌شود (چون تاپل تغییرناپذیر است)، بنابراین هویت (id) تاپل اصلی تغییر می‌کند. به هر حال، نتیجه نهایی یک تاپل حاوی همه عناصر هر دو تاپل اولیه است.

تکرار محتوای یک تاپل

برای تکرار محتویات یک تاپل می‌توانید از عملگر ضرب (*) استفاده کنید. این عملگر یک تاپل و یک عدد صحیح در سمت راست می‌گیرد و محتوای تاپل را به تعداد مشخص تکرار می‌کند. مثلاً:

				
					numbers = (1, 2, 3)

print(numbers * 3)  # خروجی: (1, 2, 3, 1, 2, 3, 1, 2, 3)
print(4 * numbers)  # خروجی: (1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3)

				
			

در این مثال، با numbers * 3 محتوای تاپل (1,2,3) سه بار پشت سر هم تکرار شده است. اگر عدد صفر یا منفی باشد، معمولاً در ورژن های مختلف یک تاپل خالی برمی‌گردد. این عمل نیز یک تاپل جدید می‌سازد و تاپل اصلی را تغییر نمی‌دهد.

معکوس کردن و مرتب‌سازی تاپل‌ها

معکوس کردن تاپل با ()reversed

برای معکوس کردن اعضای یک تاپل می‌توانید از تابع داخلی ()reversed استفاده کنید. این تابع یک iterator ایجاد می‌کند که عناصر را برعکس برمی‌گرداند. برای تبدیل آن به تاپل می‌توانید از سازنده‌ی ()tuple استفاده کنید. به عنوان مثال:

				
					days = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
rev = tuple(reversed(days))

print(rev)
# خروجی: ('Sunday', 'Saturday', 'Friday', 'Thursday', 'Wednesday', 'Tuesday', 'Monday')

				
			

در اینجا، ابتدا reversed(days) یک iterator معکوس برمی‌گرداند و سپس با تابع ()tuple آن را به یک تاپل جدید معکوس تبدیل کردیم.

معکوس کردن تاپل با عملگر برش

روش دیگر معکوس کردن تاپل، استفاده از عملگر برش با گام 1- است. کافی است مانند زیر بنویسید:

				
					
reversed_days = days[::-1]
reversed_days
('Sunday', 'Saturday', 'Friday', 'Thursday', 'Wednesday', 'Tuesday', 'Monday')

				
			

اینجا [1-::] به معنی «از انتها به ابتدا» است و همانند ()reversed یک تاپل جدید با آرایش معکوس می‌سازد.

مرتب‌سازی تاپل با ()sorted

اگر نیاز باشد تا اعضای یک تاپل را مرتب کنید، می‌توانید از تابع ()sorted استفاده کنید. این تابع هر iterable را گرفته و یک لیست مرتب‌شده برمی‌گرداند. مثلاً:

				
					numbers = (2, 9, 5, 1, 6)
print(sorted(numbers))  # خروجی: [1, 2, 5, 6, 9]

				
			

در این مثال، یک لیست مرتب‌شده از اعضای تاپل برمی‌گردد. دقت کنید که نتیجه ()sorted یک لیست است، نه یک تاپل. همچنین مرتب‌سازی روی تاپل حاوی انواع داده نامرتبط (مثلاً ترکیب عدد و رشته) مجاز نیست و منجر به خطای TypeError می‌شود. تابع ()sorted پارامترهای reverse=True (برای معکوس کردن ترتیب) و =key (برای تعیین معیار مرتب‌سازی) را نیز می‌پذیرد.

 

پیمایش تاپل‌ها در پایتون

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

				
					fruits = ("apple", "banana", "cherry")

for fruit in fruits:
    print(fruit)

# خروجی:
# apple
# banana
# cherry

				
			

در اینجا در هر تکرار، متغیر fruit یکی از عناصر تاپل fruits را می‌گیرد و چاپ می‌کند. همچنین می‌توانید در خود حلقه از unpacking استفاده کنید. مثلاً اگر تاپلی از تاپل‌های دوبخشی داشته باشید:

				
					monthly = (("Jan", 100), ("Feb", 150), ("Mar", 200))
total = 0

for month, income in monthly:
    print(month, income)
    total += income

print("Total income:", total)
# خروجی:
# Jan 100
# Feb 150
# Mar 200
# Total income: 450

				
			

در این مثال دو متغیر month و income به ترتیب مقدارهای درون هر تاپل کوچکتر را می‌گیرند.

یک راه دیگر برای پیمایش یا تبدیل تاپل‌ها استفاده از عبارات comprehension یا عبارات مولد (generator expression) است. مثلاً فرض کنید تاپلی از اعداد به صورت رشته داریم و می‌خواهیم یک تاپل جدید از اعداد صحیح بسازیم:

				
					fruits = ("apple", "banana", "orange", "apple", "kiwi")

print(fruits.count("apple"))   #  2
print(fruits.index("orange"))  #  2
				
			

در مثال بالا، ابتدا با list comprehension مقادیر رشته‌ای را به عدد تبدیل کردیم و سپس با tuple() آن‌ها را در یک تاپل جدید قرار دادیم. نسخه دوم با حذف براکت تبدیل به یک عبارت مولد شده است که حافظه‌ی کمتری مصرف می‌کند اما نتیجه یکسان است.

سایر ویژگی‌های تاپل

تاپل‌ها فقط دو متد از پیش تعریف شده دارند:

  • count(item): تعداد تکرار یک مقدار را در تاپل می‌شمارد. 
  • index(item): اندیس اولین وقوع یک مقدار را برمی‌گرداند (اگر مقدار نباشد، خطای ValueError می‌دهد). 

برای مثال:

				
					fruits = ("apple", "banana", "orange", "apple", "kiwi")

print(fruits.count("apple"))   # خروجی: 2
print(fruits.index("orange"))  # خروجی: 2

				
			

یافتن عضو در تاپل

برای بررسی وجود یک مقدار خاص در تاپل، می‌توان از عملگرهای in و not in استفاده کرد. این عملگرها عملیات عضویت را به صورت خطی انجام می‌دهند (یعنی کل تاپل را جستجو می‌کنند). مثال:

				
					skills = ("Python", "Django", "Flask")

print("Flask" in skills)         # خروجی: True
print("JavaScript" not in skills)  # خروجی: True

				
			

در اینجا in وجود مقدار را بررسی می‌کند (مثلاً “Flask” in skills مقدار True می‌دهد). اگر مقدار در تاپل نباشد، in نتیجه False و not in نتیجه True خواهد داد.

دریافت طول تاپل

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

مقایسه تاپل‌ها

می‌توانید تاپل‌ها را با یکدیگر مقایسه کنید؛ پایتون از روش مقایسه لغت‌نامه‌ای (lexicographical) استفاده می‌کند. یعنی ابتدا عنصر اول هر دو را مقایسه می‌کند و اگر برابر بود، به عنصر دوم می‌رود و الی آخر. برای مثال:

				
					print((2, 3) == (2, 3))       # خروجی: True
print((5, 6, 7) < (7, 5, 6))  # خروجی: True

				
			

در مثال دوم، چون عدد اول ۵ کوچکتر از ۷ است، کل عبارت True می‌شود. اگر طول تاپل‌ها متفاوت باشد، ولی همه عناصر با ترتیب تا انتها برابر باشد، تاپل کوتاه‌تر کوچکتر در نظر گرفته می‌شود. اگر در فرآیند مقایسه به عنصرهایی از نوع‌های غیرقابل مقایسه برسیم (مثلاً عدد با رشته)، پایتون خطای TypeError می‌دهد. به این نکته توجه کنید که اگر نوع‌ها سازگار باشند، مقایسه طبق ترتیب طبیعی آن نوع انجام خواهد شد.

اشتباهات رایج در استفاده از تاپل‌ها

  • تعریف تاپل تک عضوی: فراموش کردن کامای انتهای یک تاپل با یک عضو متداول‌ترین اشتباه است. اگر کاما را حذف کنید، تاپل ایجاد نمی‌شود؛ برای مثال (42) عدد صحیح ۴۲ است نه تاپل. برای ساخت تاپل تک‌عضوی حتماً باید کاما باشد: (42,).

     

  • هش‌پذیری با اعضای تغییرپذیر: خیلی وقت‌ها گفته می‌شود چون تاپل تغییرناپذیر است، می‌توان از آن به عنوان کلید در دیکشنری استفاده کرد. اما اگر داخل تاپل، اشیاء تغییرپذیر (مثلاً یک لیست) داشته باشید، آن تاپل قابل هش نیست و نمی‌توانید از آن به عنوان کلید استفاده کنید. یعنی باید تمام اعضای تاپل خود تغییرناپذیر باشند تا تاپل نیز هش‌پذیر باشد.

استفاده از جایگزین‌های tuple

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

  • collections.namedtuple: این تابع یک کلاس زیرمجموعه‌ی تاپل می‌سازد که فیلدهای نام‌دار (named fields) دارد. در این حالت می‌توانید به جای اندیس عددی، از نام فیلد برای دسترسی استفاده کنید. برای مثال، با :
  •  Person = namedtuple(“Person”, “name age position”) می‌توانیم شیء Person(“Ali”, 30, “Engineer”) بسازیم و سپس person.name به‌جای person[0] مقدار نام را بدهد. این روش خوانایی کد را بسیار افزایش می‌دهد.

     

  • typing.NamedTuple: از نسخه‌ی ۳.۵ به بعد، ماژول typing کلاسی به نام NamedTuple دارد که شبیه namedtuple عمل می‌کند ولی می‌توانید type hint برای فیلدها و مقادیر پیش‌فرض تعریف کنید. مثلاً می‌توانید کلاس Employee(NamedTuple) تعریف کنید و فیلدها را با نوع مشخص بنویسید. این کار هم به خوانایی و هم به بررسی نوع مقادیر (type checking) کمک می‌کند.
				
					from typing import NamedTuple

class Employee(NamedTuple):
    name: str
    age: int
    department: str = "General"  # مقدار پیش‌فرض

# ایجاد چند نمونه از کلاس
emp1 = Employee("Ali", 28, "HR")
emp2 = Employee("Sara", 34)  # department از مقدار پیش‌فرض استفاده می‌کند

# استفاده از داده‌ها
print(emp1.name)        # خروجی: Ali
print(emp1.department)  # خروجی: HR
print(emp2.department)  # خروجی: General

# بررسی نوع (برای ابزارهای type checker مثل mypy مفید است)
print(type(emp1))       # خروجی: <class '__main__.Employee'>

				
			
  • dataclasses: از پایتون ۳.۷ به بعد، ماژول dataclasses معرفی شده که می‌تواند جایگزین قوی‌تری برای namedtuple باشد. دِکوراتور dataclass@ به شما اجازه می‌دهد کلاس‌هایی با فیلدهای نام‌دار و قابلیت‌های اضافه ایجاد کنید (مثلاً متدها، مقادیر پیش‌فرض، و قابلیت‌های mutable). این کلاس‌ها به‌طور پیش‌فرض تغییرپذیر هستند و اگر لازم باشد می‌توانید آن‌ها را با پارامتر frozen=True تغییرناپذیر کنید. در نتیجه، اگر نیاز به ساختار داده‌ای پیچیده‌تر و قابل فهم‌تر دارید، ممکن است namedtuple، NamedTuple یا کلاس‌های داده (dataclass@) گزینه‌های بهتری از تاپل ساده باشند.
				
					from dataclasses import dataclass

@dataclass
class Book:
    title: str
    author: str
    pages: int
    available: bool = True  # مقدار پیش‌فرض

# ایجاد نمونه‌ای از کلاس
book1 = Book("1984", "George Orwell", 328)
book2 = Book("Python Basics", "Ali Ahmadi", 200, False)

# دسترسی و تغییر مقادیر
print(book1.title)       # خروجی: 1984
print(book2.available)   # خروجی: False

book1.available = False  # تغییر مقدار فیلد (mutable بودن)

print(book1)             # خروجی: Book(title='1984', author='George Orwell', pages=328

				
			

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

نوشته های مرتبط

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *