نگاهی اجمالی بر سیستم نوع داده پایتون
بهصورت کلی پایتون یکزبان با سیستم نوع داده پویا (dynamic) است که انعطافپذیری بسیار بالایی را به این زبان داده است. همچنین پایتون از نظر سختگیری در استفاده متغیرها یکزبان با نوع داده قوی (strongly typed) محسوب میشود. این ویژگی مانند محافظی برای کد عمل میکند و باعث میشود برنامهنویس بتواند مشکلات برنامه را بهراحتی در زمان توسعه پیدا و رفع کند تا باعث بروز مشکلات ناخواسته در ادامه نشود. سیستم نوع داده پایتون از مفهومی به نام نوع داده اردکی (duck typing) برای تطابق نوع دادهها استفاده میکند که بسیار شبیه به نوع داده ساختاری (structurally typed) است. همچنین با قابلیت جدید type hints در پایتون میتوان برخی از ویژگیهای زبانهای ایستا (static) را به پایتون اضافه کرد.
در ادامه این مقاله به بررسی عمیقتر ویژگیهای سیستم نوع داده پایتون از جهات مختلف میپردازیم.
هم رویش منتشر کرده است:
آموزش پایتون از صفر — برنامه نویسی مقدماتی تا پیشرفته Python
سیستم نوع داده پایتون از نظر زمان بررسی نوع داده (type checking)
یکی از ویژگیهای برجسته زبان برنامهنویسی پایتون که انعطاف زیادی را به این زبان میدهد، پویا (dynamic) بودن آن است. در زبانهای پویا، نوع دادهها در زمان اجرا (runtime) مشخص میشوند. به همین علت متغیرها میتوانند نوع داده خود را بر اساس داده ورودی تعیین کنند و در یک برنامه، دادهها با نوع دادههای مختلفی را ذخیره کنند.
به مثال زیر توجه کنید.
# Dynamic Typing Example
x = 5 # x is initially an integer
print(type(x)) # Output: <class 'int'>
x = "hello" # x is now a string
print(type(x)) # Output: <class 'str'>
x = [1, 2, 3] # x is now a list
print(type(x)) # Output: <class 'list'>
همانطور که میبینید، متغیر x ابتدا با دریافت عدد 5، نوع داده int را گرفت. سپس با دریافت یک رشته (string) به نوع داده str تغییر یافت و در نهایت با دریافت داده لیست، نوع داده آن به list تغییر پیدا کرد. این انعطاف بالا به لطف سیستم نوع داده پویا پایتون به وجود آمده است. البته باید در نظر گرفت که این انعطاف میتواند باعث بروز مشکلات پیشبینی نشدهای باشد که در ادامه به بررسی آنها میپردازیم.
سیستم نوع داده پایتون از نظر سختگیری در استفاده متغیرها
پایتون از نظر سختگیری در استفاده متغیرها، یک سیستم قوی (strongly typed) دارد. سیستم نوع داده قوی، محدودیتهای نوع دادههای مختلف را اعمال میکند و به ما اجازه استفاده از متغیر در عملیاتی که به آن مجاز نیست را نمیدهد. این سیستم کمک میکند تا انعطافپذیری زیاد پایتون باعث از کنترل خارجشدن آن نشود.
به مثال زیر توجه کنید.
# Strong Typing Example
a = 5 # a is an integer
b = "hello" # b is a string
# Attempting to perform an operation between incompatible types
result = a + b # This will raise a TypeError
در این مثال، زمانی که قصد انجام عملیات جمع (+) بین دو متغیر با نوع دادههایی که مجاز به آن نیستند میکنیم، مفسر پایتون به ما یک TypeError میدهد.
برای آشنایی به زبانهایی که نوع داده ضعیف (weak) دارند، میتوانید به این مقاله مراجعه کنید.
سیستم نوع داده پایتون از نظر تطابق نوع داده (type compatibility)
همانطور که میدانید، بهصورت کلی 2 نوع سیستم نوع داده از نظر تطابق نوع داده (type compatibility) وجود دارد. سیستم اسمی (nominally typed) و سیستم ساختاری (structurally typed).
نوع دیگر سیستم نوع داده از نظر تطابق، نوع داده اردکی (duck typing) است. نام اردک از اصطلاح “اگر چیزی شبیه اردک باشد، مانند اردک شنا کند و مانند اردک صدا بدهد، پس آن چیز اردک است” گرفته شده است. این فلسفه دربرگیرنده حالت کد زدن بسیار منعطف و پویا است.
سیستم نوع داده پایتون از نوع داده اردکی استفاده میکند.
به مثال زیر توجه کنید.
class Duck:
def quack(self):
print("Quack!")
class Dog:
def quack(self):
print("Dogs don't quack!")
def make_sound(animal):
animal.quack()
duck = Duck()
dog = Dog()
make_sound(duck) # "Quack!" - Duck typing, as long as it quacks, it's treated like a duck
make_sound(dog) # "Dogs don't quack!" - Duck typing, as long as it quacks, it's treated like a duck
در این مثال تابع make_sound انتظار ورودی را دارد که دارای متد quack است. هر دو کلاس Duck و Dog دارای متد quack هستند، پس در فضای تابع make_sound با آنها رفتار مشابهی میشود. این نمونه سادهای از سیستم نوع داده پایتون از لحاظ ترکیب و تطابق نوع دادههای مختلف بود.
نوع داده اردکی بسیار شبیه به نوع داده ساختاری است و هر دو به شکل و ساختار دادهها بهجای نام آنها اهمیت میدهند. اما نوع داده اردکی از لحاظ انعطاف بسیار فراتر رفته است و تنها به رفتار نوع داده در زمان استفاده از آن اهمیت میدهد.
برای درک بهتر این موضوع به نحوه کارکرد تابع len در پایتون دقت کنید.
class Smartphone:
def __len__(self):
return 256 # A smartphone is assumed to have 256 GB of storage!
class Book:
def __len__(self):
return 300 # A book is assumed to have 300 pages!
phone = Smartphone()
novel = Book()
print(len(phone)) # Output: 256 - Duck typing, as long as it has a __len__ method, it's treated like an object with a length
print(len(novel)) # Output: 300 - Duck typing, as long as it has a __len__ method, it's treated like an object with a length
print(len(“Hamruyesh”)) # Output: 9 - Duck typing, as long as it has a __len__ method, it's treated like an object with a length
در تابع len مهم نیست که ورودی از چه نوع دادهای باشد، تا زمانی که متد __length__ در آن نوع داده پیادهسازی شده باشد. دقت کنید که متد __length__ در نوع داده str نیز وجود دارد.
تکامل سیستم نوع داده در پایتون
همانطور که فهمیدیم، سیستم نوع داده پایتون انعطاف و سادگی بسیار زیادی را برای ما به ارمغان آورده است. اما این سیستم مشکلات و چالشهای مخصوص به خود را نیز دارد. بسیاری از این مشکلات به دلیل پویا بودن این سیستم به وجود میآیند. مشکلاتی مانند خطاهای پیشبینی نشده، خوانا نبودن و سخت بودن نگهداری (maintain) از کد.
معرفی Type hints در پایتون
پایتون برای حل این مشکلات ویژگی بسیار جالبی را در پایتون نسخه ۳.۵ و 484 PEP معرفی کرد. این ویژگی به ما این امکان را میدهد تا مانند زبانهای ایستا (static)، نوع داده متغیرها را تعیین کنیم. البته باید دقت کرد که مفسر پایتون type hints را نادیده میگیرد و کاربرد این ویژگی برای توسعهدهندگان و ابزارهای مختلف (محیطهای توسعه (IDE)، ابزارهای تشخیص خطا و…) است.
برای آشنایی بیشتر با این قابلیت میتوانید به PEP 484 مراجعه کنید.
مشکلات سیستم نوع داده پایتون و حل آنها
در این بخش به بررسی تعدادی از این چالشها و نحوه حلشدن آنها با type hints در پایتون را میپردازیم.
خطاهای منطقی و پیشبینی نشده
پویا بودن سیستم نوع داده پایتون باعث ایجادشدن خطاهای پیشبینی نشده میشود.
به مثال زیر توجه کنید.
def add_numbers(a, b):
return a + b
result = add_numbers("5", "7")
print(result)
قصد ما نوشتن تابعی است که ۲ عدد را بگیرد و جمع آنها را برگرداند. اما این تابع با دریافت ورودی رشته (str) و بعضی دیگر از نوع دادهها نیز بدون مشکل اجرا میشود. اما خروجی برنامه مورد انتظار ما نیست و به خطای منطقی برخورد میکنیم.
این تابع بعد از استفاده از type hints بهصورت زیر تغییر میکند.
def add_numbers(a: int, b: int) -> int:
return a + b
result = add_numbers(“5”, "7") # Type hint warns about the mismatch
print(result)
استفاده از type hints در پایتون کمک میکند تا به شکل درست از دادهها استفاده بکنیم. همچنین اغلب محیطهای توسعه (vs code, pycharm و…) با استفاده از type hints به ما در مورد استفاده ناصحیح از دادهها، قبل از اجرا برنامه اخطار میدهند.
هم رویش منتشر کرده است:
آموزش VSCode — از صفر در ۲ ساعت
توجه کنید که در عمل و نحوه اجرا کد تفاوتی ایجاد نشده است و مفسر پایتون type hints را نادیده میگیرد.
خوانا نبودن و سخت بودن نگهداری کد
در پروژههای بزرگ و کارهای تیمی، خوانا بودن کد به دلیل همکاری همزمان افراد مختلف روی آن بسیار اهمیت دارد.
به مثال زیر دقت کنید.
def get_last_two_chars_of_year(year):
"""Returns the last two characters of the given year."""
return year[-2:]
این تابع ۲ رقم آخر سال ورودی را بر میگرداند. اگر ورودی تابع نوع دادهای غیر از str باشد، برنامه با خطا منطقی و یا خطا نوع داده روبرو میشود. حال تصور کنید زمان زیادی از نوشتن این برنامه گذشته و شخص دیگری میخواهد از این تابع استفاده کند. خیلی احتمال دارد که توسعهدهنده سال را با نوع داده int به تابع بدهد و برنامه با مشکل روبرو شود.
حال به نسخه اصلاح شده دقت کنید.
def get_last_two_chars_of_year(year: str) -> str:
"""Returns the last two characters of the given year."""
return year[-2:]
حال هر برنامهنویسی که کد را بخواند میتواند بفهمد که ورودی و خروجی، هر دو از نوع str هستند. استفاده از type hints در پایتون باعث خوانایی و شفافیت بالا کد میشود که نگهداری و مدیریت کد را بسیار آسانتر میکند.
معرفی Mypy
Mypy کتابخانه پایتونی است که به ما کمک میکند تا خطاهای نوع داده (TypeError) را پیدا و آنها را رفع کنیم. این کتابخانه با استفاده از type hints کد را بررسی میکند و اشتباهات احتمالی توسعهدهندگان را پیش از اجرا خود برنامه به آنها گوشزد میکند. برای دیدن نحوه استفاده از کتابخانه Mypy میتوانید به مستندات آن سر بزنید.
سخن پایانی
سیستم نوع داده پایتون تأثیر عمیقی بر ساختار و نحوه استفاده از این زبان دارد. تکامل و ویژگیهای جدید این سیستم باعث شده است که پایتون تعادل مناسبی بین انعطافپذیری (flexibility) و قابلیت اطمینان (reliability) داشته باشد. همچنین این سیستم میتواند باعث خوانایی بیشتر کد شود و پایتون را زبانی مناسب برای استفاده در برنامههای پیچیده و بزرگ کند.
هدف این مقاله بررسی سیستم نوع داده پایتون و همچنین معرفی ویژگیهای جدید پایتون برای نوشتن کدهای بهتر و اصولیتر بود. استفاده از type hints در دنیا پایتون مدرن بسیار ضروری است.
شما میتوانید برای آشنایی بیشتر با این ویژگی به مستندات پایتون در این زمینه سر بزنید و آنها را مطالعه کنید. همچنین میتوانید همرویش را برای مطالب بیشتر در این زمینه دنبال کنید.
کلیدواژگان
type system پایتون | مشکلات سیستم نوع داده پایتون | سیستم نوع داده پایتون | نوع داده اردکی | duck typing | type system in python | type hints in python