در این مطلب، ویدئو فوق العاده، اشتباه ترین ویژگی پایتون. با زیرنویس فارسی را برای دانلود قرار داده ام. شما میتوانید با پرداخت 15 هزار تومان ، این ویدیو به علاوه تمامی فیلم های سایت را دانلود کنید.اکثر فیلم های سایت به زبان انگلیسی می باشند. این ویدئو دارای زیرنویس فارسی ترجمه شده توسط هوش مصنوعی می باشد که میتوانید نمونه ای از آن را در قسمت پایانی این مطلب مشاهده کنید.
مدت زمان فیلم: 00:21:07
تصاویر این ویدئو:
قسمتی از زیرنویس این فیلم:
00:00:00,000 –> 00:00:02,892
سلام، من جیمز مورفی هستم و این mCoding است.
2
00:00:02,892 –> 00:00:06,160
در قسمت امروز، ما در مورد فوق العاده پایتون صحبت می کنیم.
3
00:00:06,160 –> 00:00:09,914
super احتمالاً اشتباهترین ویژگی پایتون است.
4
00:00:09,914 –> 00:00:12,000
بنابراین، امروز ما قصد داریم آن را تجزیه کنیم.
5
00:00:12,000 –> 00:00:16,114
ما کاربرد اصلی آن را برای ارث بری تک و چندگانه پوشش میدهیم
6
00:00:16,114 –> 00:00:21,040
، برخی از تصورات نادرست در مورد نحوه کارکرد و عملکرد آن را مرور میکنیم
7
00:00:21,040 –> 00:00:24,369
و در نهایت پیادهسازی پایتون خالص آن را مشاهده میکنیم.
8
00:00:24,369 –> 00:00:28,531
همچنین مجوزهای حرفهای را برای PyCharm و CLion میدهم.
9
00:00:28,531 –> 00:00:32,871
بنابراین، اگر علاقه دارید، #pycharm یا #clion را کامنت کنید.
10
00:00:32,871 –> 00:00:36,579
بسیار خوب، در اینجا ساده ترین و رایج ترین استفاده از سوپر است.
11
00:00:36,579 –> 00:00:39,367
ما یک کلاس Base داریم که تابع f را تعریف میکند.
12
00:00:39,367 –> 00:00:44,021
سپس یک کلاس Derived داریم که از کلاس Base مشتق شده و تابع f را نیز تعریف می کند.
13
00:00:44,021 –> 00:00:47,892
کلاس Derived می خواهد اساساً همان کاری را که کلاس Base انجام می دهد انجام دهد،
14
00:00:47,892 –> 00:00:50,104
اما شاید با کمی تغییر.
15
00:00:50,104 –> 00:00:54,161
به جای کپی پیست کد از کلاس Base که کد اضافی را معرفی می کند
16
00:00:54,161 –> 00:00:55,976
و همچنین بسیار مستعد خطا است، در
17
00:00:55,976 –> 00:00:58,088
عوض از super استفاده می کنیم.
18
00:00:58,088 –> 00:01:02,085
در داخل مشتق شده، f فوقالعاده x، f Base را از x فراخوانی میکند.
19
00:01:02,085 –> 00:01:06,267
نتیجه در این مورد این است که میبینیم F مشتق شده نامیده میشود، سپس پایه f فراخوانی میشود
20
00:01:06,267 –> 00:01:08,267
و سپس F مشتق شده تمام میشود.
21
00:01:08,273 –> 00:01:10,664
توجه داشته باشید که ما خود را به سوپر منتقل نکردیم.
22
00:01:10,664 –> 00:01:15,342
اما وقتی تابع پایه فراخوانی می شود، می بینیم که self به عنوان یک پارامتر ارسال شده است.
23
00:01:15,342 –> 00:01:18,252
بنابراین، نباید سعی کنید پارامتر self را به صورت دستی وارد کنید.
24
00:01:18,252 –> 00:01:21,400
این پارامتر بهطور خودکار پر میشود و بعداً در مورد آن بیشتر خواهیم دید.
25
00:01:21,400 –> 00:01:26,435
شما فقط باید هر آرگومان موقعیتی و کلیدواژه باقیمانده را که در این مورد وجود دارد، فقط x ارسال کنید.
26
00:01:26,435 –> 00:01:28,580
super همچنین با متدهای کلاس به خوبی کار می کند.
27
00:01:28,580 –> 00:01:32,667
و در این صورت، بهجای نمونه، بهطور خودکار در کلاس ارسال میشود.
28
00:01:32,667 –> 00:01:34,347
در اینجا یک مثال ملموس تر است.
29
00:01:34,347 –> 00:01:36,918
فرض کنید، ما یک فرهنگ لغت گزارشگیری میخواهیم.
30
00:01:36,918 –> 00:01:39,118
من می خواهم دقیقاً مانند دیکشنری قابل استفاده باشد.
31
00:01:39,118 –> 00:01:44,547
اما هر زمان که کلیدی را دریافت، تنظیم یا حذف میکنم، میخواهم پیام ورود به سیستم به صورت استاندارد چاپ شود.
32
00:01:44,547 –> 00:01:48,501
بهجای تلاش برای پیادهسازی فرهنگ لغت خود، فقط از dict داخلی ارث میبریم
33
00:01:48,501 –> 00:01:52,393
و سپس از super در روشهای setitem، getitem و delitem استفاده میکنیم.
34
00:01:52,393 –> 00:01:58,640
ما پیام گزارش خود را چاپ می کنیم و سپس تماس فوق العاده تضمین می کند که عملکرد دیکشنری واقعی همچنان ادامه دارد.
35
00:01:58,640 –> 00:02:02,560
سپس میتوانیم از فرهنگ لغت ورود به سیستم به همان روشی که از یک فرهنگ لغت معمولی استفاده میکنیم استفاده کنیم.
36
00:02:02,560 –> 00:02:06,960
آن را ایجاد کنید. سپس می توانیم d از 0 را برابر با “subscribe” قرار دهیم.
37
00:02:06,960 –> 00:02:10,491
میتوانیم مقدار d صفر را برداریم و آن را حذف کنیم.
38
00:02:10,491 –> 00:02:14,447
تنها در چند خط کد، super به ما اجازه داد تا یک فرهنگ لغت کاملاً کارآمد داشته
39
00:02:14,447 –> 00:02:17,267
باشیم که پیامهای گزارش مورد نظر ما را نیز به ما میدهد.
40
00:02:17,280 –> 00:02:21,132
قبل از اینکه ادامه دهیم، اگرچه فکر میکنم درک
41
00:02:21,132 –> 00:02:24,342
نحوه عملکرد سوپر و ویژگیهای پیچیدهتر آن بسیار مهم است،
42
00:02:24,342 –> 00:02:30,369
من فکر میکنم برای ۹۹٪ از شما، این مورد اساسی استفاده از سوپر تمام چیزی است که همیشه به آن نیاز دارید.
43
00:02:30,369 –> 00:02:34,240
و برای ۱٪ از شما، به خاطر امنیت شغلی باورنکردنیتان تبریک میگویم.
44
00:02:34,240 –> 00:02:35,829
باشه وقت امتحان
45
00:02:35,829 –> 00:02:39,561
فرض کنید، یک کلاس A داریم و یک نقطه f کار می کند.
46
00:02:39,561 –> 00:02:44,456
سپس یک کلاس B داریم که از A مشتق شده است که f خود را تعریف می کند و super f را می نامد.
47
00:02:44,456 –> 00:02:48,472
آیا سوپر f برای یافتن a لزوماً f را صدا می کند؟
48
00:02:48,472 –> 00:02:50,398
مکث کنید و در صورت تمایل به آن فکر کنید.
49
00:02:50,398 –> 00:02:52,389
بسیار خوب، پاسخ اینجاست.
50
00:02:52,389 –> 00:02:53,833
پاسخ این است…
51
00:02:53,833 –> 00:02:55,137
52
00:02:55,137 –> 00:02:59,969
خیر. در این مورد، اگرچه میتوانید f را در نمونهای از A فراخوانی کنید، A f خود را تعریف نکرده است.
53
00:02:59,969 –> 00:03:04,165
بنابراین، هنگامی که شما super f را صدا می زنید، در واقع به f روت می رسد.
54
00:03:04,165 –> 00:03:10,000
بنابراین، در این مورد، super f به والد B نمیرود. از زنجیره بالاتر میرود.
55
00:03:10,000 –> 00:03:14,560
بسیار خوب، سوال دوم: فرض کنید یک کلاس ریشه و A داریم که از Root به ارث میبریم.
56
00:03:14,560 –> 00:03:19,108
در این مورد، هر دو کلاس Root و A نسخه خود را از f تعریف میکنند.
57
00:03:19,108 –> 00:03:24,653
بنابراین، سوال من این است: آیا این super f لزوماً تابع f ریشه را صدا می کند؟
58
00:03:24,653 –> 00:03:27,840
یک بار دیگر مکث کنید تا به آن فکر کنید.
59
00:03:27,840 –> 00:03:30,467
یک بار دیگر پاسخ منفی است.
60
00:03:30,467 –> 00:03:34,083
وقتی مثالی را که میخواهم به شما نشان دهم اجرا میکنم، این A dot f را میبینیم.
61
00:03:34,083 –> 00:03:35,759
بنابراین، آن کد در حال اجرا است.
62
00:03:35,759 –> 00:03:40,187
اما فراخوانی به فراخوانی تابع دیگر B نقطه f ختم شد.
63
00:03:40,187 –> 00:03:45,201
نقطه ریشه f هرگز چاپ نشد. بنابراین، کلاس والد f هرگز فراخوانی نشد.
64
00:03:45,201 –> 00:03:49,073
این اتفاق به این دلیل رخ داد که نقطه f در نمونه ای از A فراخوانی نشد.
65
00:03:49,073 –> 00:03:52,567
این نتیجه یک تماس فوق العاده از یک کلاس کودک بود.
66
00:03:52,567 –> 00:03:56,963
من یک کلاس خواهر و برادر A B ایجاد کردم که از Root نیز به ارث می رسد.
67
00:03:56,963 –> 00:04:00,307
سپس یک C ایجاد کردم که از A و B به ارث میبرد.
68
00:04:00,307 –> 00:04:04,160
نمونهای از کلاس C را نمونهسازی میکنیم و تابع f آن را صدا میزنیم.
69
00:04:04,160 –> 00:04:07,098
کلاس C از super f، A را f می نامد.
70
00:04:07,098 –> 00:04:12,026
اما به دلیل وراثت چندگانه، تماس فوقالعاده در A به والد A نمیرود، در
71
00:04:12,026 –> 00:04:14,864
عوض به خواهر و برادر A میرود.
72
00:04:14,864 –> 00:04:20,755
اتفاقاً کلاس B هیچ تماس فوقالعادهای برقرار نمیکند. بنابراین، کلاسهای ریشه f هرگز فراخوانی نمیشوند.
73
00:04:20,755 –> 00:04:24,918
اگر فراخوانی را به کلاس B اضافه کنیم، در نهایت Root فراخوانی می شود.
74
00:04:24,918 –> 00:04:29,391
اما توجه کنید، فراخوانی A همچنان B نامیده میشود، نه ریشه مادر.
75
00:04:29,391 –> 00:04:33,909
خب، اینجا چه خبر است؟ چرا سوپر گاهی اوقات با والدین تماس می گیرد، گاهی اوقات با خواهر و برادر تماس می گیرد؟
76
00:04:33,909 –> 00:04:37,520
حتی میتواند بر اساس کلاسی که از آن فراخوانی شده است، چیزهای مختلفی را فراخوانی کند.
77
00:04:37,520 –> 00:04:40,964
اگر من نمونه ای از A داشته باشم، این فراخوانی به ریشه می رود.
78
00:04:40,964 –> 00:04:45,007
اما از یک نمونه از C، همان تماس فوقالعاده به B رسید
79
00:04:45,007 –> 00:04:50,493
. پاسخ مربوط به چیزی است که به آن ترتیب وضوح روش کلاس یا MRO میگویند.
80
00:04:50,493 –> 00:04:56,090
این در واقع نوعی نام اشتباه است زیرا برای همه دسترسیهای ویژگی اعمال میشود نه فقط جستجوی روش.
81
00:04:56,090 –> 00:05:01,472
همان سلسله مراتب وراثت را در نظر بگیرید، اما به جای اینکه f یک تابع باشد، بگذارید یک متغیر باشد.
82
00:05:01,472 –> 00:05:03,969
یک شی C ایجاد می کنیم و c.f را چاپ می کنیم.
83
00:05:03,969 –> 00:05:07,644
البته C یک f تعریف می کند، بنابراین باید C را چاپ کند.
84
00:05:07,644 –> 00:05:10,315
اما اگر C f خودش را تعریف نمی کرد چه می شد.
85
00:05:10,315 –> 00:05:14,584
خوب، C از A و B به ارث میبرد. و A و B هر دو f را تعریف میکنند.
86
00:05:14,584 –> 00:05:18,966
بنابراین، وقتی c.f را جستجو میکنیم، باید بتوانیم یکی از این fها را پیدا کنیم.
87
00:05:18,966 –> 00:05:21,280
اما کدام را انتخاب کنیم؟
88
00:05:21,280 –> 00:05:26,880
و اگر نه A و نه B، f را تعریف نکردند، همچنان باید بتوانیم آن را تا آخر در ریشه پیدا کنیم.
89
00:05:26,880 –> 00:05:30,320
در حال حاضر، امیدوارم بتوانید ببینید که این یک مشکل جستجو است.
90
00:05:30,320 –> 00:05:32,912
با توجه به یک کلاس، وقتی سعی میکنم یک ویژگی را جستجو
91
00:05:32,912 –> 00:05:36,392
کنم، باید در مورد ترتیبی تصمیم بگیرم تا آن کلاس
92
00:05:36,392 –> 00:05:39,867
و والدین و والدین آنها و غیره و غیره را بررسی کنم.
93
00:05:39,867 –> 00:05:43,370
این همان کاری است که ترتیب تفکیک روش برای یک کلاس انجام میدهد.
94
00:05:43,370 –> 00:05:45,718
در اینجا، نمایش های کامل کلاس به نوعی طولانی هستند.
95
00:05:45,718 –> 00:05:49,124
بنابراین، من فقط نام کلاسها را در MRO چاپ میکنم.
96
00:05:49,124 –> 00:05:54,299
بنابراین، همانطور که می بینید، MRO برای کلاس C C، A، B، Root، شی است.
97
00:05:54,299 –> 00:05:56,308
این بدان معناست که وقتی میخواهید یک مقدار را در C جستجو کنید
98
00:05:56,308 –> 00:06:00,798
، ابتدا در C، سپس در A، سپس در B، سپس در Root و سپس در شی بررسی میشود.
99
00:06:00,798 –> 00:06:06,188
اگر پایتون همه این موارد را جستجو کند و همچنان نتواند ویژگی شما را پیدا کند، یک خطای ویژگی ایجاد میشود.
100
00:06:06,188 –> 00:06:08,633
هوم ج، الف، ب، ریشه.
101
00:06:08,633 –> 00:06:13,281
این دقیقاً همان ترتیبی است که هنگام پرینت گرفتن با تماسهای فوقالعاده مشاهده کردیم.
102
00:06:13,281 –> 00:06:18,224
این مثال را به خاطر بسپارید. ما C.f و سپس A.f و سپس B.f و سپس Root.f را دیدیم
103
00:06:18,224 –> 00:06:22,240
بنابراین، در نهایت میتوانیم بفهمیم که super ما را به کجا میبرد.
104
00:06:22,240 –> 00:06:26,314
فراخوانی شما را به کلاس والد شی نمی برد.
105
00:06:26,314 –> 00:06:32,105
این شما را به مورد بعدی بعد از کلاس فعلی در MRO شی می برد.
106
00:06:32,105 –> 00:06:36,939
روشی که باید بخوانید و در ذهن خود درباره سوپر فکر کنید، در ردیف بعدی قرار دارد.
107
00:06:36,939 –> 00:06:39,749
super به معنای بعدی در صف است.
108
00:06:39,749 –> 00:06:42,599
در یک مورد ارثی، آن خط ساده است.
109
00:06:42,599 –> 00:06:45,320
در صف بعدی پدر و مادر شما هستند.
110
00:06:45,320 –> 00:06:48,720
اما در مورد ارث چندگانه، لزوماً اینطور نیست.
111
00:06:48,720 –> 00:06:53,226
به عنوان یک برنامه نویس، فقط چند ویژگی مختلف از MRO وجود دارد که باید آنها را در نظر داشته باشید.
112
00:06:53,226 –> 00:06:57,565
MRO هر کلاس با کلاس شروع می شود و در نهایت به شی ختم می شود.
113
00:06:57,565 –> 00:07:01,138
زیرا تمام اشیاء پایتون در نهایت از شی به ارث می برند.
114
00:07:01,138 –> 00:07:04,015
خاصیت بعدی این است که کودک جلوتر از والدین خود می رود
115
00:07:04,015 –> 00:07:09,613
و والدین باید نظم نسبی خود را همانطور که در اظهارنامه کودک آمده است حفظ کنند.
116
00:07:09,613 –> 00:07:12,850
بنابراین، C قبل از A و A قبل از B می رود.
117
00:07:12,850 –> 00:07:16,640
در این مورد، MRO حاصل C، A، B، شی است.
118
00:07:16,640 –> 00:07:22,799
سومین ویژگی مهم این است که MRO یک کودک باید بسط MRO هر یک از والدین آن باشد.
119
00:07:22,799 –> 00:07:26,800
این بدان معناست که MRO هر یک از والدین دنباله ای از MRO فرزند است.
120
00:07:26,800 –> 00:07:32,953
این ویژگی تضمین می کند که والدین یک شی و والدین آنها و والدین آنها و غیره همه در MRO ظاهر می شوند.
121
00:07:32,953 –> 00:07:35,441
و آخرین ویژگی مهم MRO این است که
122
00:07:35,441 –> 00:07:39,885
اگر این قوانین تناقضی ایجاد کنند، وقتی میخواهید کلاس را تعریف کنید، با خطا مواجه میشوید.
123
00:07:39,885 –> 00:07:44,245
در تلاش برای ایجاد این کلاس D با خطا مواجه میشویم زیرا A باید قبل از C باشد.
124
00:07:44,245 –> 00:07:46,950
اما C باید قبل از A باشد.
125
00:07:46,950 –> 00:07:52,000
این یک تناقض است. بنابراین، خطایی دریافت میکنیم که به ما میگوید نمیتوانیم یک MRO ثابت ایجاد کنیم.
126
00:07:52,000 –> 00:07:55,101
اما در دنیای واقعی، برای تشخیص MRO نیازی به استفاده از منطق
127
00:07:55,101 –> 00:07:57,744
ندارید، فقط به ویژگی dunder MRO دسترسی پیدا کنید.
128
00:07:57,744 –> 00:08:00,042
با این حال، حتی اگر MRO را درک کنید
129
00:08:00,042 –> 00:08:04,258
و بدانید که فوق العاده یعنی رفتن به مورد بعدی در MRO و آن را فراخوانی کنید،
130
00:08:04,258 –> 00:08:07,318
این هنوز یک چالش طراحی جالب است.
131
00:08:07,318 –> 00:08:13,584
وقتی کلاسی را طراحی میکنم، نمیتوانم تک تک کلاسهای ممکن را تصور کنم که میتواند مورد بعدی در MRO باشد.
132
00:08:13,584 –> 00:08:15,855
این دو مسئله اساسی را مطرح می کند.
133
00:08:15,855 –> 00:08:20,159
اول: اگر یک فراخوان لزوماً نسخه تابع والدین من را فراخوانی نمیکند،
134
00:08:20,159 –> 00:08:24,716
پس چگونه مطمئن شوم که نسخه والدینم از تابع در نهایت فراخوانی میشود؟
135
00:08:24,716 –> 00:08:29,545
احتمالاً من به آن عملکرد نیاز دارم. به همین دلیل است که از والدینم ارث میبرم.
136
00:08:29,545 –> 00:08:33,227
و ثانیاً، از آنجایی که یک تماس فوقالعاده میتواند اساساً به همه جا برود،
137
00:08:33,227 –> 00:08:36,575
چگونه میتوانم بدانم که پارامترهایی که به آن تماس ارسال میکنم صحیح هستند؟
138
00:08:36,575 –> 00:08:41,366
برای مثال، چه میشود اگر کلاس بعدی در خط به پارامتر x نیاز داشته باشد که من مجبور نیستم آن را بدهم.
139
00:08:41,366 –> 00:08:46,080
به طور کلی، نمیتوان با یک سلسله مراتب کلاس دلخواه، کار فوقالعاده انجام داد.
140
00:08:46,080 –> 00:08:49,536
در عوض، راه حل، ارث تعاونی است.
141
00:08:49,536 –> 00:08:53,045
تنها راهی که میتوانید این کار را انجام دهید این است که از طریق برخی ابزارها اطمینان حاصل کنید که
142
00:08:53,045 –> 00:08:56,464
همه طبقات در سلسله مراتب از قوانین خاصی پیروی میکنند.
143
00:08:56,464 –> 00:09:01,840
اولین قانون این است که باید یک کلاس Root وجود داشته باشد که همه چیز در سلسله مراتب از آن به ارث ببرد.
144
00:09:01,840 –> 00:09:04,563
یک کلاس Root صریح اغلب سادهترین کار برای کار است.
145
00:09:04,563 –> 00:09:09,233
اما اگر همه چیز در نهایت از یک مجموعه داخلی مانند مجموعه یا دیکت به ارث برده شود نیز اشکالی ندارد.
146
00:09:09,233 –> 00:09:12,869
قانون دوم این است که اگر از یک فراخوانی در یک نسخه از یک روش استفاده
147
00:09:12,869 –> 00:09:17,450
میکنید، باید از فراخوانی فوقالعاده در تمام نسخههای متد در کل سلسله مراتب استفاده کنید
148
00:09:17,450 –> 00:09:19,189
، به جز، احتمالاً، روت.
149
00:09:19,189 –> 00:09:25,371
این چیزی است که تضمین میکند که یک تماس فوقالعاده در نهایت منجر به فراخوانی نسخه کلاسهای والدین شما از تابع میشود.
150
00:09:25,371 –> 00:09:27,824
ممکن است کلاس والد در ردیف بعدی نباشد.
151
00:09:27,824 –> 00:09:32,513
اما هر چیزی که هست، یک تماس فوقالعاده نیز ایجاد میکند و سپس هر آنچه که بعدی باشد، یک تماس فوقالعاده برقرار میکند
152
00:09:32,513 –> 00:09:35,032
و در نهایت به والدین شما میرسد.
153
00:09:35,032 –> 00:09:40,376
سپس نسخههای شی Root آن روش به عنوان یک سینک برای پایان دادن به زنجیره فراخوانیها عمل میکنند.
154
00:09:40,376 –> 00:09:44,821
اکنون، بیایید ببینیم چگونه مطمئن میشویم که استدلالهایی که به یک فراخوان منتقل میکنیم، منطقی هستند.
155
00:09:44,821 –> 00:09:48,898
راه حل اول راه حلی است که قبلاً دیده ایم و راه حلی است که dict از آن استفاده می کند.
156
00:09:48,898 –> 00:09:52,972
فقط کاری کنید که تمام نسخههای تابع همان آرگومانها را داشته باشند.
157
00:09:52,972 –> 00:09:56,070
این اولین انتخاب عالی است، اما همچنین بسیار محدود کننده است.
158
00:09:56,070 –> 00:09:58,209
یک روش init را در نظر بگیرید.
159
00:09:58,209 –> 00:10:00,441
اگر من یک سلسله مراتب کامل از کلاسها داشته
160
00:10:00,441 –> 00:10:04,513
باشم، نمیتوانم انتظار داشته باشم که آنها همان پارامترها را در ابتدای کار خود داشته باشند.
161
00:10:04,513 –> 00:10:08,480
در این مورد، من چیزی را توصیه میکنم که آن را لایه برداری استدلال کلیدواژه مینامم.
162
00:10:08,480 –> 00:10:11,409
آیا می دانید چه امضایی می تواند با هر عملکردی مطابقت داشته باشد؟
163
00:10:11,409 –> 00:10:13,785
*args **kwargs
164
00:10:13,785 –> 00:10:17,554
کاری کنید که تابع شما از هر آرگومان موقعیتی و هر آرگومان کلمه کلیدی استفاده کند.
165
00:10:17,554 –> 00:10:21,117
و سپس فقط آرگومان های کلمه کلیدی را که واقعاً می خواهید بردارید.
166
00:10:21,117 –> 00:10:23,372
در این مورد، من یک ValidatedSet را تعریف میکنم.
167
00:10:23,372 –> 00:10:28,133
این فقط یک مجموعه است. اما وقتی میخواهید عنصری را به آن اضافه کنید، بررسی میکند که آن عنصر معتبر است.