diff --git a/translations/fa-farsi/section1-temp.md b/translations/fa-farsi/section1-temp.md index f14400d..7c37b26 100644 --- a/translations/fa-farsi/section1-temp.md +++ b/translations/fa-farsi/section1-temp.md @@ -585,6 +585,7 @@ TypeError: unhashable type: 'dict' >>> len(another_set) 2 ``` + پس بی‌ثباتی تو این رفتار به خاطر اینه که مقدار `another_ordered_dict in another_set` برابر با `False` هست چون `ordered_dict` از قبل داخل `another_set` هست و همونطور که قبلا مشاهده کردید، مقدار `ordered_dict == another_ordered_dict` برابر با `False` هست. --- @@ -788,3 +789,219 @@ False - در مثال بالا، عبارت `(not None)` برابره با مقدار `True` از اونجایی که مقدار `None` در زمینه boolean به `False` تبدیل میشه. پس کل عبارت معادل عبارت `'something' is True` میشه. --- + + +### ▶ یک بازی دوز که توش X همون اول برنده میشه! + + +```py +# بیاید یک سطر تشکیل بدیم +row = [""] * 3 #row i['', '', ''] +# حالا بیاید تخته بازی رو ایجاد کنیم +board = [row] * 3 +``` + +**خروجی:** + +```py +>>> board +[['', '', ''], ['', '', ''], ['', '', '']] +>>> board[0] +['', '', ''] +>>> board[0][0] +'' +>>> board[0][0] = "X" +>>> board +[['X', '', ''], ['X', '', ''], ['X', '', '']] +``` + +ما که سه‌تا `"X"` نذاشتیم. گذاشتیم مگه؟ + +#### 💡 توضیحات: + +وقتی متغیر `row` رو تشکیل میدیم، تصویر زیر نشون میده که چه اتفاقی در حافظه دستگاه میافته. + +

+ + + + Shows a memory segment after row is initialized. + +

+ +و وقتی متغیر `board` رو با ضرب کردن متغیر `row` تشکیل میدیم، تصویر زیر به صورت کلی نشون میده که چه اتفاقی در حافظه میافته (هر کدوم از عناصر `board[0]`، `board[1]` و `board[2]` در حافظه به لیست یکسانی به نشانی `row` اشاره میکنند). + +

+ + + + Shows a memory segment after board is initialized. + +

+ +ما می‌تونیم با استفاده نکردن از متغیر `row` برای تولید متغیر `board` از این سناریو پرهیز کنیم. (در [این](https://github.com/satwikkansal/wtfpython/issues/68) موضوع پرسیده شده). + +```py +>>> board = [['']*3 for _ in range(3)] +>>> board[0][0] = "X" +>>> board +[['X', '', ''], ['', '', ''], ['', '', '']] +``` + +--- + + +### ▶ متغیر شرودینگر * + + + +```py +funcs = [] +results = [] +for x in range(7): + def some_func(): + return x + funcs.append(some_func) + results.append(some_func()) # note the function call here + +funcs_results = [func() for func in funcs] +``` + +**خروجی:** +```py +>>> results +[0, 1, 2, 3, 4, 5, 6] +>>> funcs_results +[6, 6, 6, 6, 6, 6, 6] +``` + +مقدار `x` در هر تکرار حلقه قبل از اضافه کردن `some_func` به لیست `funcs` متفاوت بود، ولی همه توابع در خارج از حلقه مقدار `6` رو برمیگردونند. + +2. + +```py +>>> powers_of_x = [lambda x: x**i for i in range(10)] +>>> [f(2) for f in powers_of_x] +[512, 512, 512, 512, 512, 512, 512, 512, 512, 512] +``` + +#### 💡 توضیحات: +* وقتی یک تابع رو در داخل یک حلقه تعریف می‌کنیم که در بدنه‌اش از متغیر اون حلقه استفاده شده، بست این تابع به *متغیر* وصله، نه *مقدار* اون. تابع به جای اینکه از مقدار `x` در زمان تعریف تابع استفاده کنه، در زمینه اطرافش دنبال `x` می‌گرده. پس همه این توابع از آخرین مقداری که به متغیر `x` مقداردهی شده برای محاسباتشون استفاده می‌کنند. ما می‌تونیم ببینیم که این توابع از متغیر `x` که در زمینه اطرافشون (*نه* از متغیر محلی) هست، استفاده می‌کنند، به این صورت: + +```py +>>> import inspect +>>> inspect.getclosurevars(funcs[0]) +ClosureVars(nonlocals={}, globals={'x': 6}, builtins={}, unbound=set()) +``` + +از اونجایی که `x` یک متغیر سراسریه (گلوبال)، ما می‌تونیم مقداری که توابع داخل `funcs` دنبالشون می‌گردند و برمیگردونند رو با به‌روز کردن `x` تغییر بدیم: + +```py +>>> x = 42 +>>> [func() for func in funcs] +[42, 42, 42, 42, 42, 42, 42] +``` + +* برای رسیدن به رفتار موردنظر شما می‌تونید متغیر حلقه رو به عنوان یک متغیر اسم‌دار به تابع بدید. **چرا در این صورت کار می‌کنه؟** چون اینجوری یک متغیر در دامنه خود تابع تعریف میشه. تابع دیگه دنبال مقدار `x` در دامنه اطراف (سراسری) نمی‌گرده ولی یک متغیر محلی برای ذخیره کردن مقدار `x` در اون لحظه می‌سازه. + +```py +funcs = [] +for x in range(7): + def some_func(x=x): + return x + funcs.append(some_func) +``` + +**خروجی:** + +```py +>>> funcs_results = [func() for func in funcs] +>>> funcs_results +[0, 1, 2, 3, 4, 5, 6] +``` + +دیگه از متغیر `x` در دامنه سراسری استفاده نمی‌کنه: + +```py +>>> inspect.getclosurevars(funcs[0]) +ClosureVars(nonlocals={}, globals={}, builtins={}, unbound=set()) +``` + +--- + + +### ▶ اول مرغ بوده یا تخم مرغ؟ * + +1\. +```py +>>> isinstance(3, int) +True +>>> isinstance(type, object) +True +>>> isinstance(object, type) +True +``` + +پس کدوم کلاس پایه "نهایی" هست؟ راستی سردرگمی بیشتری هم تو راهه. + +2\. + +```py +>>> class A: pass +>>> isinstance(A, A) +False +>>> isinstance(type, type) +True +>>> isinstance(object, object) +True +``` + +3\. + +```py +>>> issubclass(int, object) +True +>>> issubclass(type, object) +True +>>> issubclass(object, type) +False +``` + + +#### 💡 توضیحات + +- در پایتون، `type` یک [متاکلاس](https://realpython.com/python-metaclasses/) است. +- در پایتون **همه چیز** یک `object` است، که کلاس‌ها و همچنین نمونه‌هاشون (یا همان instance های کلاس‌ها) هم شامل این موضوع میشن. +- کلاس `type` یک متاکلاسه برای کلاس `object` و همه کلاس‌ها (همچنین کلاس `type`) به صورت مستقیم یا غیرمستقیم از کلاس `object` ارث بری کرده است. +- هیچ کلاس پایه واقعی بین کلاس‌های `object` و `type` وجود نداره. سردرگمی که در قطعه‌کدهای بالا به وجود اومده، به خاطر اینه که ما به این روابط (یعنی `issubclass` و `isinstance`) از دیدگاه کلاس‌های پایتون فکر می‌کنیم. رابطه بین `object` و `type` رو در پایتون خالص نمیشه بازتولید کرد. برای اینکه دقیق‌تر باشیم، رابطه‌های زیر در پایتون خالص نمی‌تونند بازتولید بشن. + + کلاس A یک نمونه از کلاس B، و کلاس B یک نمونه از کلاس A باشه. + + کلاس A یک نمونه از خودش باشه. +- +- این روابط بین `object` و `type` (که هردو نمونه یکدیگه و همچنین خودشون باشند) به خاطر "تقلب" در مرحله پیاده‌سازی، وجود دارند. + +--- + + +### ▶ روابط بین زیرمجموعه کلاس‌ها + +**خروجی:** +```py +>>> from collections.abc import Hashable +>>> issubclass(list, object) +True +>>> issubclass(object, Hashable) +True +>>> issubclass(list, Hashable) +False +``` + +ما انتظار داشتیم که روابط بین زیرکلاس‌ها، انتقالی باشند، درسته؟ (یعنی اگه `A` زیرکلاس `B` باشه و `B` هم زیرکلاس `C` باشه، کلس `A` __باید__ زیرکلاس `C` باشه) + +#### 💡 توضیحات: + +* روابط بین زیرکلاس‌ها در پایتون لزوما انتقالی نیستند. همه مجازند که تابع `__subclasscheck__` دلخواه خودشون رو در یک متاکلاس تعریف کنند. +* وقتی عبارت `issubclass(cls, Hashable)` اجرا میشه، برنامه دنبال یک تابع "غیر نادرست" (یا non-Falsy) در `cls` یا هرچیزی که ازش ارث‌بری می‌کنه، می‌گرده. +* از اونجایی که `object` قابل هش شدنه، ولی `list` این‌طور نیست، رابطه انتقالی شکسته میشه. +* توضیحات با جزئیات بیشتر [اینجا](https://www.naftaliharris.com/blog/python-subclass-intransitivity/) پیدا میشه. + +---