بسیار خب بیایید به جواب این سوال بپردازیم:
جواب این سوال در واقع به سه موضوع کوواریانس (Covariance)، کونتراواریانس (Contravariance) و اینواریانس (Invariance) بر میگردد. این سه مفهوم، مفاهیم مهمی در نظریهی نوعها (type theory) و typing در زبانهای برنامهنویسی هستند. این مفاهیم به چگونگی رابطهی بین type های مختلف و subtypes های آنها مربوط میشوند.
در ادامه مختصری از هر یک توضیح داده میشود :
1. Covariance
کوواریانس (Covariance) زمانی رخ میدهد که یک type از نوع
B
که subtype عه
A
است، قابل assign کردن به یک مجموعه (Collection) از نوع
B
باشد. به عبارت دیگر، در Covariance، اگر
A
یک نوع باشد و
B
نوعی باشد که از
A
ارث بری میکند، یک شیء از نوع
B
میتواند جایگزین یک شیء از نوع
A
شود.
برخی زبان ها مانند سی شارپ، جاوا، سی پلاس پلاس از این مفهوم استفاده میکنند.
2. Contravariance
مفهوم Contravariance برعکس Covariance است. در این حالت ما میتوانیم از نوع پایه یا base به جای subtype استفاده کنیم. به عبارت دیگر، در Contravariance، اگر
A
یک نوع باشد و
B
نوعی باشد که از
A
مشتق شده است، یک شیء از نوع
A
میتواند جایگزین یک شیء از نوع
B
شود.
3. Invariance
بر خلاف کوواریانس و کونتراواریانس، اینواریانس به این معنی است که یک نوع نمیتواند به یک نوع دیگری (حتی subtype یا supertype) تبدیل شود. به عبارت دیگر، اگر یک متغیر یا پارامتر از یک نوع خاص باشد، فقط میتواند همان نوع خاص را بپذیرد و نه نوعی دیگر.
بسیاری از ساختارهای داده در زبانهای برنامهنویسی اینواریانس هستند.
حالا که این مفاهیم را فهمیدیم بیایید به سوال برگردیم:
ما تابعی به شکل زیر داریم:
def f(l: list[object], k: list[int]) -> None:
l = k
در این تابع ما دو پارامتر داریم:
- پارامتر l که لیستی از object ها است.
- پارامتر k که لیستی از int ها است.
در بدنه تابع، ما میخواهیم لیست k که از نوع [list[int است را به l که از نوع [list[object است، اختصاص دهیم.
در نگاه اول ممکن است به نظر برسد که این کد باید کار کند زیرا int نوعی object است. اما نکته ای که وجود دارد این است که
لیست ها
در پایتون از مفهوم Invariance بهره میبرند.
لیستها و به طور کلی بیشتر نوعهای Generic در پایتون invariance هستند.
این به این معنی است که شما نمیتوانید [list[int را به [list[object تبدیل کنید، حتی اگر int نوعی object باشد.
* دلیل این خطا این است که اگر اجازه چنین کاری داده شود، ممکن است باعث بروز خطاهای runtime شود!
برای مثال، فرض کنید که بعد از تخصیص k به l، شما میخواهید یک مقدار str رو به لیست l اضافه کنید (str هم یک object هست) :
def f(l: list[object], k: list[int]) -> None:
l = k
l.append("a string")
در اینجا، l در واقع یک [list[int است (لیستی از اعداد صحیح) و اضافه کردن یک مقدار str به آن باعث خطا میشود.
یادگیری type annotation یکی از اون دسته بحثای جالب و گاهی پیچیده در پایتون است که پیشنهاد میشه حتما برید دنبال یادگیریش
😁موفق و پیروز باشید.