You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
>>>len({ordered_dict, another_ordered_dict, dictionary}) # ترتیب رو عوض میکنیم
550
+
2
551
+
```
552
+
553
+
چی شد؟
554
+
555
+
#### 💡 توضیحات:
556
+
557
+
- دلیل اینکه این مقایسه بین متغیرهای `dictionary`، `ordered_dict` و `another_ordered_dict` به درستی اجرا نمیشه به خاطر نحوه پیادهسازی تابع `__eq__` در کلاس `OrderedDict` هست. طبق [مستندات](https://docs.python.org/3/library/collections.html#ordereddict-objects)
558
+
> مقایسه برابری بین شیءهایی از نوع OrderedDict به ترتیب اعضای آنها هم بستگی دارد و به صورت `list(od1.items())==list(od2.items())` پیاده سازی شده است. مقایسه برابری بین شیءهای `OrderedDict` و شیءهای قابل نگاشت دیگر به ترتیب اعضای آنها بستگی ندارد و مقایسه همانند دیکشنریهای عادی انجام میشود.
559
+
- این رفتار باعث میشه که بتونیم `OrderedDict` ها رو هرجایی که یک دیکشنری عادی کاربرد داره، جایگزین کنیم و استفاده کنیم.
560
+
- خب، حالا چرا تغییر ترتیب روی طول مجموعهای که از دیکشنریها ساختیم، تاثیر گذاشت؟ جوابش همین رفتار مقایسهای غیرانتقالی بین این شیءهاست. از اونجایی که `set` ها مجموعهای از عناصر غیرتکراری و بدون نظم هستند، ترتیبی که عناصر تو این مجموعهها درج میشن نباید مهم باشه. ولی در این مورد، مهم هست. بیاید کمی تجزیه و تحلیلش کنیم.
561
+
```py
562
+
>>> some_set =set()
563
+
>>> some_set.add(dictionary) # این شیءها از قطعهکدهای بالا هستند.
564
+
>>> ordered_dict in some_set
565
+
True
566
+
>>> some_set.add(ordered_dict)
567
+
>>>len(some_set)
568
+
1
569
+
>>> another_ordered_dict in some_set
570
+
True
571
+
>>> some_set.add(another_ordered_dict)
572
+
>>>len(some_set)
573
+
1
574
+
575
+
>>> another_set =set()
576
+
>>> another_set.add(ordered_dict)
577
+
>>> another_ordered_dict in another_set
578
+
False
579
+
>>> another_set.add(another_ordered_dict)
580
+
>>>len(another_set)
581
+
2
582
+
>>> dictionary in another_set
583
+
True
584
+
>>> another_set.add(another_ordered_dict)
585
+
>>>len(another_set)
586
+
2
587
+
```
588
+
پس بیثباتی تو این رفتار به خاطر اینه که مقدار `another_ordered_dict in another_set` برابر با `False` هست چون `ordered_dict` از قبل داخل `another_set` هست و همونطور که قبلا مشاهده کردید، مقدار `ordered_dict == another_ordered_dict` برابر با `False` هست.
589
+
590
+
---
591
+
592
+
593
+
### ▶ تلاش کن... *
594
+
<!-- Example ID: b4349443-e89f-4d25-a109-82616be9d41a--->
595
+
```py
596
+
defsome_func():
597
+
try:
598
+
return'from_try'
599
+
finally:
600
+
return'from_finally'
601
+
602
+
defanother_func():
603
+
for _ inrange(3):
604
+
try:
605
+
continue
606
+
finally:
607
+
print("Finally!")
608
+
609
+
defone_more_func():
610
+
try:
611
+
for i inrange(3):
612
+
try:
613
+
1/ i
614
+
exceptZeroDivisionError:
615
+
# بذارید اینجا ارور بدیم و بیرون حلقه بهش
616
+
# رسیدگی کنیم
617
+
raiseZeroDivisionError("A trivial divide by zero error")
618
+
finally:
619
+
print("Iteration", i)
620
+
break
621
+
exceptZeroDivisionErroras e:
622
+
print("Zero division error occurred", e)
623
+
```
624
+
625
+
**خروجی:**
626
+
627
+
```py
628
+
>>> some_func()
629
+
'from_finally'
630
+
631
+
>>> another_func()
632
+
Finally!
633
+
Finally!
634
+
Finally!
635
+
636
+
>>>1/0
637
+
Traceback (most recent call last):
638
+
File "<stdin>", line 1, in<module>
639
+
ZeroDivisionError: division by zero
640
+
641
+
>>> one_more_func()
642
+
Iteration 0
643
+
644
+
```
645
+
646
+
#### 💡 Explanation:
647
+
648
+
- وقتی یک عبارت `return`، `break` یا `continue` داخل بخش `try` از یک عبارت "try...finally" اجرا میشه، بخش `fianlly` هم هنگام خارج شدن اجرا میشه.
649
+
- مقدار بازگشتی یک تابع از طریق آخرین عبارت `return` که داخل تابع اجرا میشه، مشخص میشه. از اونجایی که بخش `finally` همیشه اجرا میشه، عبارت `return` که داخل بخش `finally` هست آخرین عبارتیه که اجرا میشه.
650
+
- نکته اینجاست که اگه بخش داخل بخش `finally` یک عبارت `return` یا `break` اجرا بشه، `exception` موقتی که ذخیره شده، رها میشه.
651
+
652
+
---
653
+
654
+
655
+
### ▶ برای چی?
656
+
<!-- Example ID: 64a9dccf-5083-4bc9-98aa-8aeecde4f210 --->
657
+
```py
658
+
some_string ="wtf"
659
+
some_dict = {}
660
+
for i, some_dict[i] inenumerate(some_string):
661
+
i =10
662
+
```
663
+
664
+
**Output:**
665
+
```py
666
+
>>> some_dict # یک دیکشنری مرتبشده نمایان میشه.
667
+
{0: 'w', 1: 't', 2: 'f'}
668
+
```
669
+
670
+
#### 💡 توضیحات:
671
+
* یک حلقه `for` در [گرامر پایتون](https://docs.python.org/3/reference/grammar.html) این طور تعریف میشه:
672
+
```
673
+
for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
674
+
```
675
+
به طوری که `exprlist` یک هدف برای مقداردهیه. این یعنی، معادل عبارت `{exprlist} = {next_value}`**برای هر شیء داخل `testlist` اجرا میشود**.
676
+
یک مثال جالب برای نشون دادن این تعریف:
677
+
```py
678
+
for i inrange(4):
679
+
print(i)
680
+
i =10
681
+
```
682
+
683
+
**خروجی:**
684
+
```
685
+
0
686
+
1
687
+
2
688
+
3
689
+
```
690
+
691
+
آیا انتظار داشتید که حلقه فقط یک بار اجرا بشه؟
692
+
693
+
**💡 توضیحات:**
694
+
695
+
- عبارت مقداردهی `i = 10` به خاطر نحوه کار کردن حلقهها، هیچوقت باعث تغییر در تکرار حلقه نمیشه. قبل از شروع هر تکرار، مقدار بعدی که توسط شیء قابل تکرار (که در اینجا `range(4)` است) ارائه میشه، از بسته خارج میشه و به متغیرهای لیست هدف (که در اینجا `i` است) مقداردهی میشه.
696
+
697
+
* تابع `enumerate(some_string)`، یک متغیر `i` (که یک شمارنده اقزایشی است) و یک حرف از حروف رشته `some_string` رو در هر تکرار برمیگردونه. و بعدش برای کلید `i` (تازه مقداردهیشده) در دیکشنری `some_dict`، مقدار اون حرف رو تنظیم میکنه. بازشده این حلقه میتونه مانند مثال زیر ساده بشه:
698
+
```py
699
+
>>> i, some_dict[i] = (0, 'w')
700
+
>>> i, some_dict[i] = (1, 't')
701
+
>>> i, some_dict[i] = (2, 'f')
702
+
>>> some_dict
703
+
```
704
+
705
+
---
706
+
707
+
### ▶ اختلاف زمانی در محاسبه
708
+
<!-- Example ID: 6aa11a4b-4cf1-467a-b43a-810731517e98 --->
709
+
1\.
710
+
```py
711
+
array = [1, 8, 15]
712
+
# یک عبارت تولیدکننده عادی
713
+
gen = (x for x in array if array.count(x) >0)
714
+
array = [2, 8, 22]
715
+
```
716
+
717
+
**خروجی:**
718
+
719
+
```py
720
+
>>>print(list(gen)) # پس بقیه مقدارها کجا رفتن؟
721
+
[8]
722
+
```
723
+
724
+
2\.
725
+
726
+
```py
727
+
array_1 = [1,2,3,4]
728
+
gen_1 = (x for x in array_1)
729
+
array_1 = [1,2,3,4,5]
730
+
731
+
array_2 = [1,2,3,4]
732
+
gen_2 = (x for x in array_2)
733
+
array_2[:] = [1,2,3,4,5]
734
+
```
735
+
736
+
**خروجی:**
737
+
```py
738
+
>>>print(list(gen_1))
739
+
[1, 2, 3, 4]
740
+
741
+
>>>print(list(gen_2))
742
+
[1, 2, 3, 4, 5]
743
+
```
744
+
745
+
3\.
746
+
747
+
```py
748
+
array_3 = [1, 2, 3]
749
+
array_4 = [10, 20, 30]
750
+
gen = (i + j for i in array_3 for j in array_4)
751
+
752
+
array_3 = [4, 5, 6]
753
+
array_4 = [400, 500, 600]
754
+
```
755
+
756
+
**خروجی:**
757
+
```py
758
+
>>>print(list(gen))
759
+
[401, 501, 601, 402, 502, 602, 403, 503, 603]
760
+
```
761
+
762
+
#### 💡 توضیحات
763
+
764
+
- در یک عبارت [تولیدکننده](https://wiki.python.org/moin/Generators)، عبارت بند `in` در هنگام تعریف محاسبه میشه ولی عبارت شرطی در زمان اجرا محاسبه میشه.
765
+
- پس قبل از زمان اجرا، `array` دوباره با لیست `[2, 8, 22]` مقداردهی میشه و از آنجایی که در مقدار جدید `array`، بین `1`، `8` و `15`، فقط تعداد `8` بزرگتر از `0` است، تولیدکننده فقط مقدار `8` رو برمیگردونه
766
+
- تفاوت در مقدار `gen_1` و `gen_2` در بخش دوم به خاطر نحوه مقداردهی دوباره `array_1` و `array_2` است.
767
+
- در مورد اول، متغیر `array_1` به شیء جدید `[1,2,3,4,5]` وصله و از اون جایی که عبارت بند `in` در هنگام تعریف محاسبه میشه، `array_1` داخل تولیدکننده هنوز به شیء قدیمی `[1,2,3,4]` (که هنوز حذف نشده)
768
+
- در مورد دوم، مقداردهی برشی به `array_2` باعث بهروز شدن شیء قدیمی این متغیر از `[1,2,3,4]` به `[1,2,3,4,5]` میشه و هر دو متغیر `gen_2` و `array_2` به یک شیء اشاره میکنند که حالا بهروز شده.
769
+
- خیلیخب، حالا طبق منطقی که تا الان گفتیم، نباید مقدار `list(gen)` در قطعهکد سوم، `[11, 21, 31, 12, 22, 32, 13, 23, 33]` باشه؟ (چون `array_3` و `array_4` قراره درست مثل `array_1` رفتار کنن). دلیل این که چرا (فقط) مقادیر `array_4` بهروز شدن، توی [PEP-289](https://www.python.org/dev/peps/pep-0289/#the-details) توضیح داده شده.
770
+
771
+
> فقط بیرونیترین عبارت حلقه `for` بلافاصله محاسبه میشه و باقی عبارتها به تعویق انداخته میشن تا زمانی که تولیدکننده اجرا بشه.
772
+
773
+
---
774
+
775
+
776
+
### ▶ هر گردی، گردو نیست
777
+
<!-- Example ID: b26fb1ed-0c7d-4b9c-8c6d-94a58a055c0d --->
778
+
```py
779
+
>>>'something'isnotNone
780
+
True
781
+
>>>'something'is (notNone)
782
+
False
783
+
```
784
+
785
+
#### 💡 توضیحات
786
+
- عملگر `is not` یک عملگر باینری واحده و رفتارش متفاوت تر از استفاده `is` و `not` به صورت جداگانهست.
787
+
- عملگر `is not` مقدار `False` رو برمیگردونه اگر متغیرها در هردو سمت این عملگر به شیء یکسانی اشاره کنند و درغیر این صورت، مقدار `True` برمیگردونه
788
+
- در مثال بالا، عبارت `(not None)` برابره با مقدار `True` از اونجایی که مقدار `None` در زمینه boolean به `False` تبدیل میشه. پس کل عبارت معادل عبارت `'something' is True` میشه.
0 commit comments