1
0
mirror of https://github.com/satwikkansal/wtfpython synced 2025-05-19 18:53:46 +02:00

Unify the translation of explanations

This commit is contained in:
Leo Alavi 2025-04-05 21:51:35 +02:00
parent ebe443e0af
commit 78aab13e40

View File

@ -238,7 +238,7 @@ SyntaxError: invalid syntax
#### 💡 توضیحات
#### 💡 توضیح
**مرور سریع بر عملگر Walrus**
@ -359,7 +359,7 @@ False
منطقیه، نه؟
#### 💡 توضیحات:
#### 💡 توضیح:
+ در قطعهکد اول و دوم، رفتار کد به دلیل یک بهینه سازی در CPython است (به نام داوطلب سازی رشتهها) که باعث میشود از برخی مقادیر غیرقابل تغییر، به جای مقداردهی مجدد، دوباره استفاده شود.
+ بیشتر متغیرهایی که بهاین صورت جایگزین میشوند، در حافظه دستگاه به مقدار داوطلب خود اشاره میکنند (تا از حافظه کمتری استفاده شود)
+ در قطعهکدهای بالا، رشتهها بهصورت غیرمستقیم داوطلب میشوند. تصمیم اینکه رشتهها چه زمانی به صورت غیرمستقیم داوطلب شوند به نحوه پیادهسازی و مقداردهی آنها بستگی دارد. برخی قوانین وجود دارند تا بتوانیم داوطلب شدن یا نشدن یک رشته را حدس بزنیم:
@ -406,7 +406,7 @@ False
False
```
#### 💡 توضیحات:
#### 💡 توضیح:
طبق https://docs.python.org/3/reference/expressions.html#comparisons
> اگر a، b، c، ...، y، z عبارتهای عملیات و op1، op2، ...، opN عملگرهای عملیات باشند، آنگاه عملیات a op1 b op2 c ... y opN z معادل عملیات a op1 b and b op2 c and ... y opN z است. فقط دقت کنید که هر عبارت یک بار ارزیابی میشود.
@ -476,7 +476,7 @@ True
False
```
#### 💡 توضیحات:
#### 💡 توضیح:
**فرض بین عملگرهای `is` و `==`**
@ -582,7 +582,7 @@ complex
خب، چرا Python همه جارو گرفت؟
#### 💡 توضیحات
#### 💡 توضیح
* تو دیکشنریهای پایتون چیزی که کلیدها رو یگانه میکنه مقدار کلیدهاست، نه شناسه اونها. پس با اینکه `5`، `5.0` و `5 + 0j` شیءهای متمایزی از نوعهای متفاوتی هستند ولی از اون جایی که مقدارشون با هم برابره، نمیتونن داخل یه `dict` به عنوان کلید جدا از هم باشن (حتی به عنوان مقادیر داخل یه `set` نمیتونن باشن). وقتی بخواید داخل یه دیکشنری جستوجو کنید، به محض اینکه یکی از این دادهها رو وارد کنید، مقدار نگاشتهشده به کلیدی که مقدار برابر با اون داده داره ولی نوعش متفاوته، با موفقیت برگردونده میشه (به جای اینکه به ارور `KeyError` بردخورد کنید.).
```py
>>> 5 == 5.0 == 5 + 0j
@ -636,7 +636,7 @@ True
True
```
#### 💡 توضیحات:
#### 💡 توضیح:
* وقتی `id` صدا زده شد، پایتون یک شیء با کلاس `WTF` ساخت و اون رو به تابع `id` داد. تابع `id` شناسه این شیء رو میگیره (درواقع آدرس اون شیء در حافظه دستگاه) و شیء رو حذف میکنه.
* وقتی این کار رو دو بار متوالی انجام بدیم، پایتون آدرس یکسانی رو به شیء دوم اختصاص میده. از اونجایی که (در CPython) تابع `id` از آدرس شیءها توی حافظه به عنوان شناسه برای اونها استفاده میکنه، پس شناسه این دو شیء یکسانه.
* پس، شناسه یک شیء تا زمانی که اون شیء وجود داره، منحصربهفرده. بعد از اینکه اون شیء حذف میشه یا قبل از اینکه اون شیء به وجود بیاد، چیز دیگهای میتونه اون شناسه رو داشته باشه.
@ -727,7 +727,7 @@ TypeError: unhashable type: 'dict'
چی شد؟
#### 💡 توضیحات:
#### 💡 توضیح:
- دلیل اینکه این مقایسه بین متغیرهای `dictionary`، `ordered_dict` و `another_ordered_dict` به درستی اجرا نمیشه به خاطر نحوه پیادهسازی تابع `__eq__` در کلاس `OrderedDict` هست. طبق [مستندات](https://docs.python.org/3/library/collections.html#ordereddict-objects)
> مقایسه برابری بین شیءهایی از نوع OrderedDict به ترتیب اعضای آنها هم بستگی دارد و به صورت `list(od1.items())==list(od2.items())` پیاده سازی شده است. مقایسه برابری بین شیءهای `OrderedDict` و شیءهای قابل نگاشت دیگر به ترتیب اعضای آنها بستگی ندارد و مقایسه همانند دیکشنریهای عادی انجام میشود.
@ -819,7 +819,7 @@ Iteration 0
```
#### 💡 توضیحات:
#### 💡 توضیح:
- وقتی یک عبارت `return`، `break` یا `continue` داخل بخش `try` از یک عبارت "try...finally" اجرا میشه، بخش `fianlly` هم هنگام خارج شدن اجرا میشه.
- مقدار بازگشتی یک تابع از طریق آخرین عبارت `return` که داخل تابع اجرا میشه، مشخص میشه. از اونجایی که بخش `finally` همیشه اجرا میشه، عبارت `return` که داخل بخش `finally` هست آخرین عبارتیه که اجرا میشه.
@ -843,7 +843,7 @@ for i, some_dict[i] in enumerate(some_string):
{0: 'w', 1: 't', 2: 'f'}
```
#### 💡 توضیحات:
#### 💡 توضیح:
* یک حلقه `for` در [گرامر پایتون](https://docs.python.org/3/reference/grammar.html) این طور تعریف میشه:
```
for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
@ -866,7 +866,7 @@ for i, some_dict[i] in enumerate(some_string):
آیا انتظار داشتید که حلقه فقط یک بار اجرا بشه؟
**💡 توضیحات:**
**💡 توضیح:**
- عبارت مقداردهی `i = 10` به خاطر نحوه کار کردن حلقهها، هیچوقت باعث تغییر در تکرار حلقه نمیشه. قبل از شروع هر تکرار، مقدار بعدی که توسط شیء قابل تکرار (که در اینجا `range(4)` است) ارائه میشه، از بسته خارج میشه و به متغیرهای لیست هدف (که در اینجا `i` است) مقداردهی میشه.
@ -935,7 +935,7 @@ array_4 = [400, 500, 600]
[401, 501, 601, 402, 502, 602, 403, 503, 603]
```
#### 💡 توضیحات
#### 💡 توضیح
- در یک عبارت [تولیدکننده](https://wiki.python.org/moin/Generators)، عبارت بند `in` در هنگام تعریف محاسبه میشه ولی عبارت شرطی در زمان اجرا محاسبه میشه.
- پس قبل از زمان اجرا، `array` دوباره با لیست `[2, 8, 22]` مقداردهی میشه و از آنجایی که در مقدار جدید `array`، بین `1`، `8` و `15`، فقط تعداد `8` بزرگتر از `0` است، تولیدکننده فقط مقدار `8` رو برمیگردونه
@ -958,7 +958,7 @@ True
False
```
#### 💡 توضیحات
#### 💡 توضیح
- عملگر `is not` یک عملگر باینری واحده و رفتارش متفاوت تر از استفاده `is` و `not` به صورت جداگانهست.
- عملگر `is not` مقدار `False` رو برمیگردونه اگر متغیرها در هردو سمت این عملگر به شیء یکسانی اشاره کنند و درغیر این صورت، مقدار `True` برمیگردونه
- در مثال بالا، عبارت `(not None)` برابره با مقدار `True` از اونجایی که مقدار `None` در زمینه boolean به `False` تبدیل میشه. پس کل عبارت معادل عبارت `'something' is True` میشه.
@ -992,7 +992,7 @@ board = [row] * 3
ما که سهتا `"X"` نذاشتیم. گذاشتیم مگه؟
#### 💡 توضیحات:
#### 💡 توضیح:
وقتی متغیر `row` رو تشکیل میدیم، تصویر زیر نشون میده که چه اتفاقی در حافظه دستگاه میافته.
@ -1060,7 +1060,7 @@ funcs_results = [func() for func in funcs]
[512, 512, 512, 512, 512, 512, 512, 512, 512, 512]
```
#### 💡 توضیحات:
#### 💡 توضیح:
* وقتی یک تابع رو در داخل یک حلقه تعریف میکنیم که در بدنهاش از متغیر اون حلقه استفاده شده، بست این تابع به *متغیر* وصله، نه *مقدار* اون. تابع به جای اینکه از مقدار `x` در زمان تعریف تابع استفاده کنه، در زمینه اطرافش دنبال `x` میگرده. پس همه این توابع از آخرین مقداری که به متغیر `x` مقداردهی شده برای محاسباتشون استفاده میکنند. ما میتونیم ببینیم که این توابع از متغیر `x` که در زمینه اطرافشون (*نه* از متغیر محلی) هست، استفاده میکنند، به این صورت:
```py
@ -1143,7 +1143,7 @@ False
```
#### 💡 توضیحات
#### 💡 توضیح
- در پایتون، `type` یک [متاکلاس](https://realpython.com/python-metaclasses/) است.
- در پایتون **همه چیز** یک `object` است، که کلاسها و همچنین نمونههاشون (یا همان instance های کلاسها) هم شامل این موضوع میشن.
@ -1172,7 +1172,7 @@ False
ما انتظار داشتیم که روابط بین زیرکلاسها، انتقالی باشند، درسته؟ (یعنی اگه `A` زیرکلاس `B` باشه و `B` هم زیرکلاس `C` باشه، کلس `A` __باید__ زیرکلاس `C` باشه)
#### 💡 توضیحات:
#### 💡 توضیح:
* روابط بین زیرکلاسها در پایتون لزوما انتقالی نیستند. همه مجازند که تابع `__subclasscheck__` دلخواه خودشون رو در یک متاکلاس تعریف کنند.
* وقتی عبارت `issubclass(cls, Hashable)` اجرا میشه، برنامه دنبال یک تابع "غیر نادرست" (یا non-Falsy) در `cls` یا هرچیزی که ازش ارثبری میکنه، میگرده.
@ -1238,7 +1238,7 @@ True
دسترسی به `classm` یا `method` دو بار، اشیایی برابر اما نه *یکسان* را برای همان نمونه از `SomeClass` ایجاد میکند.
#### 💡 توضیحات
#### 💡 توضیح
* تابعها [وصاف](https://docs.python.org/3/howto/descriptor.html) هستند. هر زمان که تابعی به عنوان یک ویژگی فراخوانی شود، وصف فعال میشود و یک شیء متد ایجاد میکند که تابع را به شیء صاحب آن ویژگی "متصل" میکند. اگر این متد فراخوانی شود، تابع را با ارسال ضمنی شیء متصلشده به عنوان اولین آرگومان صدا میزند (به این ترتیب است که `self` را به عنوان اولین آرگومان دریافت میکنیم، با وجود اینکه آن را بهطور صریح ارسال نکردهایم).
```py
>>> o1.method
@ -1494,7 +1494,7 @@ I have lost faith in truth!
#### 💡 توضیحات:
#### 💡 توضیح:
* در پایتون، `bool` زیرکلاسی از `int` است
@ -1751,7 +1751,7 @@ True
#### 💡 توضیحات:
#### 💡 توضیح:
- `'inf'` و `'nan'` رشتههایی خاص هستند (نسبت به حروف بزرگ و کوچک حساس نیستند) که وقتی بهطور صریح به نوع `float` تبدیل شوند، به ترتیب برای نمایش "بی‌نهایت" ریاضی و "عدد نیست" استفاده میشوند.
@ -1800,7 +1800,7 @@ TypeError: 'tuple' object does not support item assignment
اما من فکر میکردم تاپلها تغییرناپذیر هستند...
#### 💡 توضیحات:
#### 💡 توضیح:
* نقلقول از https://docs.python.org/3/reference/datamodel.html
@ -1836,7 +1836,7 @@ except Exception as e:
NameError: name 'e' is not defined
```
#### 💡 توضیحات:
#### 💡 توضیح:
* منبع: [مستندات رسمی پایتون](https://docs.python.org/3/reference/compound_stmts.html#except)
هنگامی که یک استثنا (Exception) با استفاده از کلمهی کلیدی `as` به متغیری تخصیص داده شود، این متغیر در انتهای بلاکِ `except` پاک میشود. این رفتار مشابه کد زیر است:
@ -1916,7 +1916,7 @@ str
str
```
#### 💡 توضیحات:
#### 💡 توضیح:
* هر دو شیء `s` و رشتهی `"s"` به دلیل ارثبری `SomeClass` از متد `__hash__` کلاس `str`، هش یکسانی دارند.
* عبارت `SomeClass("s") == "s"` به دلیل ارثبری `SomeClass` از متد `__eq__` کلاس `str` برابر با `True` ارزیابی میشود.
@ -2290,7 +2290,7 @@ for idx, item in enumerate(list_4):
```
عنصر `3` از لیست `numbers` چه شد؟
#### 💡 توضیحات:
#### 💡 توضیح:
- بر اساس [مستندات](https://docs.python.org/3.3/library/functions.html#zip) پایتون، پیاده‌سازی تقریبی تابع `zip` به شکل زیر است:
```py
@ -2374,7 +2374,7 @@ print(x, ': x in global')
1
```
#### 💡 توضیحات:
#### 💡 توضیح:
- در پایتون، حلقههای `for` از حوزه (*scope*) فعلی که در آن قرار دارند استفاده میکنند و متغیرهای تعریفشده در حلقه حتی بعد از اتمام حلقه نیز باقی میمانند. این قاعده حتی در مواردی که متغیر حلقه پیشتر در فضای نام سراسری (*global namespace*) تعریف شده باشد نیز صدق میکند؛ در چنین حالتی، متغیر موجود مجدداً به مقدار جدید متصل میشود.
@ -2405,7 +2405,7 @@ def some_func(default_arg=[]):
['some_string', 'some_string', 'some_string']
```
#### 💡 توضیحات:
#### 💡 توضیح:
- آرگومانهای تغییرپذیر پیشفرض در توابع پایتون، هر بار که تابع فراخوانی میشود مقداردهی نمیشوند؛ بلکه مقداردهی آنها تنها یک بار در زمان تعریف تابع انجام میشود و مقدار اختصاصیافته به آنها به عنوان مقدار پیشفرض برای فراخوانیهای بعدی استفاده خواهد شد. هنگامی که به صراحت مقدار `[]` را به عنوان آرگومان به `some_func` ارسال کردیم، مقدار پیشفرض برای متغیر `default_arg` مورد استفاده قرار نگرفت، بنابراین تابع همانطور که انتظار داشتیم عمل کرد.
@ -2474,7 +2474,7 @@ ValueError: list.remove(x): x not in list
SyntaxError: invalid syntax
```
#### 💡 توضیحات
#### 💡 توضیح
* To add multiple Exceptions to the except clause, you need to pass them as parenthesized tuple as the first argument. The second argument is an optional name, which when supplied will bind the Exception instance that has been raised. Example,
```py
@ -2549,7 +2549,7 @@ a += [5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
```
#### 💡 توضیحات:
#### 💡 توضیح:
* عملگر `a += b` همیشه همانند `a = a + b` رفتار نمیکند. کلاسها *ممکن است* عملگرهای *`op=`* را به گونهای متفاوت پیادهسازی کنند، و لیستها نیز چنین میکنند.
* عبارت `a = a + [5,6,7,8]` یک لیست جدید ایجاد میکند و مرجع `a` را به این لیست جدید اختصاص میدهد، بدون آنکه `b` را تغییر دهد.
@ -2594,7 +2594,7 @@ class SomeClass:
5
```
#### 💡 توضیحات
#### 💡 توضیح
- حوزههایی که درون تعریف کلاس تو در تو هستند، نامهای تعریفشده در سطح کلاس را نادیده میگیرند.
- عبارتهای جنراتور (generator expressions) حوزهی مختص به خود دارند.
- از پایتون نسخهی ۳ به بعد، لیستهای فشرده (list comprehensions) نیز حوزهی مختص به خود دارند.
@ -2625,7 +2625,7 @@ def get_middle(some_list):
```
به نظر میرسد که پایتون عدد ۲٫۵ را به ۲ گرد کرده است.
#### 💡 توضیحات:
#### 💡 توضیح:
- این یک خطای مربوط به دقت اعداد اعشاری نیست؛ بلکه این رفتار عمدی است. از پایتون نسخه 3.0 به بعد، تابع `round()` از [گرد کردن بانکی](https://en.wikipedia.org/wiki/Rounding#Rounding_half_to_even) استفاده می‌کند که در آن کسرهای `.5` به نزدیک‌ترین عدد **زوج** گرد می‌شوند:
@ -2785,7 +2785,7 @@ def similar_recursive_func(a):
4
```
#### 💡 توضیحات:
#### 💡 توضیح:
* برای مورد ۱، عبارت صحیح برای رفتار مورد انتظار این است:
`x, y = (0, 1) if True else (None, None)`
@ -2847,7 +2847,7 @@ def similar_recursive_func(a):
1
```
#### 💡 توضیحات:
#### 💡 توضیح:
- در نگاه اول ممکن است به نظر برسد جداکنندهی پیشفرض متد `split` یک فاصلهی تکی (`' '`) است؛ اما مطابق با [مستندات رسمی](https://docs.python.org/3/library/stdtypes.html#str.split):
> اگر `sep` مشخص نشده یا برابر با `None` باشد، یک الگوریتم متفاوت برای جدا کردن اعمال میشود: رشتههایی از فاصلههای متوالی به عنوان یک جداکنندهی واحد در نظر گرفته شده و در نتیجه، هیچ رشتهی خالیای در ابتدا یا انتهای لیست خروجی قرار نمیگیرد، حتی اگر رشتهی اولیه دارای فاصلههای اضافی در ابتدا یا انتها باشد. به همین دلیل، تقسیم یک رشتهی خالی یا رشتهای که فقط شامل فضای خالی است با جداکنندهی `None` باعث بازگشت یک لیست خالی `[]` میشود.
@ -2891,7 +2891,7 @@ Traceback (most recent call last):
NameError: name '_another_weird_name_func' is not defined
```
#### 💡 توضیحات:
#### 💡 توضیح:
- اغلب توصیه میشود از واردسازی عمومی (wildcard imports) استفاده نکنید. اولین دلیل واضح آن این است که در این نوع واردسازیها، اسامی که با زیرخط (`_`) شروع شوند، وارد نمیشوند. این مسئله ممکن است در زمان اجرا به خطا منجر شود.
- اگر از ساختار `from ... import a, b, c` استفاده کنیم، خطای `NameError` فوق اتفاق نمیافتاد.
@ -2939,7 +2939,7 @@ True
False
```
#### 💡 توضیحات:
#### 💡 توضیح:
- متد `sorted` همیشه یک لیست (`list`) برمیگرداند، و در پایتون مقایسهی لیستها و تاپلها (`tuple`) همیشه مقدار `False` را برمیگرداند.
@ -2988,7 +2988,7 @@ if noon_time:
```
The midnight time is not printed.
#### 💡 توضیحات:
#### 💡 توضیح:
Before Python 3.5, the boolean value for `datetime.time` object was considered to be `False` if it represented midnight in UTC. It is error-prone when using the `if obj:` syntax to check if the `obj` is null or some equivalent of "empty."
@ -3568,7 +3568,7 @@ timeit.timeit('add_string_with_plus(10000)', number=1000, globals=globals())
86.3 µs ± 2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
```
#### 💡 توضیحات
#### 💡 توضیح
توضیحات
- برای اطلاعات بیشتر دربارهی [timeit](https://docs.python.org/3/library/timeit.html) یا [%timeit](https://ipython.org/ipython-doc/dev/interactive/magics.html#magic-timeit)، می‌توانید به این لینک‌ها مراجعه کنید. این توابع برای اندازه‌گیری زمان اجرای قطعه‌کدها استفاده می‌شوند.
- برای تولید رشتههای طولانی از `+` استفاده نکنید در پایتون، نوع دادهی `str` تغییرناپذیر (immutable) است؛ بنابراین برای هر الحاق (concatenation)، رشتهی چپ و راست باید در رشتهی جدید کپی شوند. اگر چهار رشتهی ۱۰ حرفی را متصل کنید، بهجای کپی ۴۰ کاراکتر، باید `(10+10) + ((10+10)+10) + (((10+10)+10)+10) = 90` کاراکتر کپی کنید. این وضعیت با افزایش تعداد و طول رشتهها بهصورت درجه دو (مربعی) بدتر میشود (که توسط زمان اجرای تابع `add_bytes_with_plus` تأیید شده است).
@ -3693,7 +3693,7 @@ def dict_size(o):
<!-- Example ID: f885cb82-f1e4-4daa-9ff3-972b14cb1324 --->
* متد `join()` عملیاتی مربوط به رشته (`str`) است، نه لیست (`list`). (در نگاه اول کمی برخلاف انتظار است.)
** 💡 توضیح:** اگر `join()` بهعنوان متدی روی رشته پیادهسازی شود، میتواند روی هر شیء قابل پیمایش (`iterable`) از جمله لیست، تاپل و هر نوع تکرارشوندهی دیگر کار کند. اگر بهجای آن روی لیست تعریف میشد، باید بهطور جداگانه برای هر نوع دیگری نیز پیادهسازی میشد. همچنین منطقی نیست که یک متد مختص رشته روی یک شیء عمومی مانند `list` پیاده شود.
**توضیح:** اگر `join()` بهعنوان متدی روی رشته پیادهسازی شود، میتواند روی هر شیء قابل پیمایش (`iterable`) از جمله لیست، تاپل و هر نوع تکرارشوندهی دیگر کار کند. اگر بهجای آن روی لیست تعریف میشد، باید بهطور جداگانه برای هر نوع دیگری نیز پیادهسازی میشد. همچنین منطقی نیست که یک متد مختص رشته روی یک شیء عمومی مانند `list` پیاده شود.
* تعدادی عبارت با ظاهری عجیب اما از نظر معنا صحیح:
+ عبارت `[] = ()` از نظر معنایی صحیح است (باز کردن یا `unpack` کردن یک تاپل خالی درون یک لیست خالی).
@ -3712,7 +3712,7 @@ def dict_size(o):
5
```
** 💡 توضیح:**
💡 **توضیح:**
+ در گرامر پایتون عملگری بهنام `++` وجود ندارد. در واقع `++` دو عملگر `+` جداگانه است.
+ عبارت `++a` بهشکل `+(+a)` تفسیر میشود که معادل `a` است. بههمین ترتیب، خروجی عبارت `--a` نیز قابل توجیه است.
+ این [تاپیک در StackOverflow](https://stackoverflow.com/questions/3654830/why-are-there-no-and-operators-in-python) دلایل نبودن عملگرهای افزایش (`++`) و کاهش (`--`) در پایتون را بررسی میکند.