|
245 | 245 |
|
246 | 246 | این برنامهنویس است که تصمیم میگیرد یک کلاس چگونه طراحی شود. اینکه کدام متد باید از کدام نوع باشد مسئلهای است که برنامهنویس باید در زمان طراحی کلاس خود به آن فکر کند و از امکانات زبان برنامهنویسی پایتون به درستی در جهت بهتر و راحتتر به انجام رساندن مسئله خود بهره بگیرد. |
247 | 247 |
|
| 248 | + |
| 249 | +.. tip:: |
| 250 | + |
| 251 | + هر شی از یک کلاس علاوه بر اینکه از نوع آن کلاس محسوب میشود، از نوع superclass نیز به حساب میآید. در واقع یک شی نوع subclass، نوع superclass را نیز به ارث میبرد:: |
| 252 | + |
| 253 | + >>> class SuperClass: |
| 254 | + ... pass |
| 255 | + ... |
| 256 | + >>> class SubClass(SuperClass): |
| 257 | + ... pass |
| 258 | + ... |
| 259 | + >>> sub = SubClass() |
| 260 | + >>> |
| 261 | + >>> isinstance(sub, SubClass) |
| 262 | + True |
| 263 | + >>> isinstance(sub, SuperClass) |
| 264 | + True |
| 265 | + |
| 266 | + |
248 | 267 | وراثت چندگانه (Multiple Inheritance) |
249 | 268 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
250 | 269 |
|
| 270 | +پایتون جزو معدود زبانهای برنامهنویسی مدرنی است که از وراثت چندگانه پشتیبانی میکند، چیزی که در زبانی همچون Java نیز وجود ندارد. در واقع پیادهسازی وراثت چندگانه چالشهایی به همراه دارد، همانند Diamond Problem که در Java ترجیح داده شده است که از وراثت چندگانه پرهیز کند و نبود آن را با پیادهسازی مفهومی همچون Interface پوشش دهد [`ویکیپدیا <https://en.wikipedia.org/wiki/Interface_(Java)>`__]. |
| 271 | + |
| 272 | +فراموش نکنیم در پیادهسازی شی گرایی میبایست بنابر نیاز برنامه کدهای خود را به کوچکترین واحدهای ممکن تقسیم کنیم و اینکه یک شی بتواند صفات و رفتارهای چندین کلاس را به همراه خود داشته باشد یک نیاز اساسی در شی گرایی است. این الزام فلسفه سادگی پایتون است که مانع از آن میشود تا مفاهیمی موازی درکنار هم ایجاد شوند - همانند Class و Interface - وراثت چندگانه راه حل ساده و منطقی زبان برنامهنویسی پایتون برای حل این مشکل است و این امکان را میدهد که یک کلاس بتواند بیش از یک superclass داشته باشد: |
| 273 | +:: |
| 274 | + |
| 275 | + >>> class SuperClassA: |
| 276 | + ... pass |
| 277 | + ... |
| 278 | + >>> class SuperClassB: |
| 279 | + ... pass |
| 280 | + ... |
| 281 | + >>> class SuperClassC: |
| 282 | + ... pass |
| 283 | + ... |
| 284 | + >>> class SubClass(SuperClassA, SuperClassB, SuperClassC): |
| 285 | + ... pass |
| 286 | + ... |
| 287 | + >>> sub = SubClass() |
| 288 | + >>> |
| 289 | + >>> isinstance(sub, SubClass) |
| 290 | + True |
| 291 | + >>> isinstance(sub, SuperClassA) |
| 292 | + True |
| 293 | + >>> isinstance(sub, SuperClassB) |
| 294 | + True |
| 295 | + >>> isinstance(sub, SuperClassC) |
| 296 | + True |
| 297 | + |
| 298 | +نمونه کد بالا نمایش ساختار وراثت چندگانه در پایتون است که در آن کلاس SubClass به ترتیب از سه کلاس SuperClassA و SuperClassB و SuperClassC ارثبری دارد. |
| 299 | + |
| 300 | +اکنون مهمترین چالش چگونگی دسترسی به متدهای هر یک از این superclassها میباشد. تاکنون برای دسترسی به متدهای superclass از تابع ``super`` استفاده میکردیم ولی حالا که صحبت از چندین superclass است، مثلا مقدارهی متد ``__init__`` توسط این تابع چگونه میتواند انجام شود؟ چگونه باید به پایتون بگوییم آرگومانهایی را که میخواهیم دقیقا به متد خاصی از superclass مورد نظر ارسال کند؟ البته نگران نباشید، پایتون مشکلی نخواهد داشت. در ادامه، حالات مختلف حل این مسئله را بررسی خواهیم کرد. |
251 | 301 |
|
| 302 | +**شیوه یکم:** خیلی ساده، میتوانیم اصلا از تابع ``super`` استفاده نکنیم و متدهای هر superclass را مستقیم با نام خودش فراخوانی کنیم که البته در این روش لازم است به ازای تمام پارامترهای متد superclass آرگومان متناظر را ارسال نماییم، از جمله برای ``self``: |
| 303 | + |
| 304 | + |
| 305 | +.. code-block:: python |
| 306 | + :linenos: |
| 307 | +
|
| 308 | + class SuperClassA: |
| 309 | + def __init__(self, param_0, param_3): |
| 310 | + print('Called: SuperClassA.__init__()') |
| 311 | + self.param_0 = param_0 |
| 312 | + self.param_3 = param_3 |
| 313 | + |
| 314 | + |
| 315 | + class SuperClassB: |
| 316 | + def __init__(self, param_1): |
| 317 | + print('Called: SuperClassB.__init__()') |
| 318 | + self.param_1 = param_1 |
| 319 | + |
| 320 | + class SuperClassC: |
| 321 | + def __init__(self, param_2): |
| 322 | + print('Called: SuperClassC.__init__()') |
| 323 | + self.param_2 = param_2 |
| 324 | + |
| 325 | + |
| 326 | + class SubClass(SuperClassA, SuperClassB, SuperClassC): |
| 327 | + def __init__(self, param_0, param_1, param_2, param_3, param_4): |
| 328 | + SuperClassA.__init__(self, param_0, param_3) |
| 329 | + SuperClassB.__init__(self, param_1) |
| 330 | + SuperClassC.__init__(self, param_2) |
| 331 | + self.param_4 = param_4 |
| 332 | + |
| 333 | + |
| 334 | + sub = SubClass(0, 1, 2, 3, 4) |
| 335 | + |
| 336 | + print('param_0: ', sub.param_0) |
| 337 | + print('param_1: ', sub.param_1) |
| 338 | + print('param_2: ', sub.param_2) |
| 339 | + print('param_3: ', sub.param_3) |
| 340 | + print('param_4: ', sub.param_4) |
| 341 | +
|
| 342 | +:: |
| 343 | + |
| 344 | + Called: SuperClassA.__init__() |
| 345 | + Called: SuperClassB.__init__() |
| 346 | + Called: SuperClassC.__init__() |
| 347 | + param_0: 0 |
| 348 | + param_1: 1 |
| 349 | + param_2: 2 |
| 350 | + param_3: 3 |
| 351 | + param_4: 4 |
| 352 | + |
| 353 | + |
| 354 | +**شیوه دوم:** فراخوانی تابع ``super`` یک سینتکس معادل نیز دارد که میتوانیم از آن استفاده کنیم. |
| 355 | + |
| 356 | + |
| 357 | + |
| 358 | + |
| 359 | +**شیوه سوم:** رفتار تابع ``super`` را عمیقتر بشناسیم و درست از آن بهره بگیریم: |
| 360 | + |
| 361 | + |
| 362 | +.. code-block:: python |
| 363 | + :linenos: |
| 364 | +
|
| 365 | + class SuperClassA: |
| 366 | + def __init__(self, param_0, param_3, *args): |
| 367 | + print('Called: SuperClassA.__init__()') |
| 368 | + super().__init__(*args) |
| 369 | + self.param_0 = param_0 |
| 370 | + self.param_3 = param_3 |
| 371 | + |
| 372 | + |
| 373 | + class SuperClassB: |
| 374 | + def __init__(self, param_1, *args): |
| 375 | + print('Called: SuperClassB.__init__()') |
| 376 | + super().__init__(*args) |
| 377 | + self.param_1 = param_1 |
| 378 | + |
| 379 | + class SuperClassC: |
| 380 | + def __init__(self, param_2, *args): |
| 381 | + print('Called: SuperClassC.__init__()') |
| 382 | + super().__init__(*args) |
| 383 | + self.param_2 = param_2 |
| 384 | + |
| 385 | + |
| 386 | + class SubClass(SuperClassA, SuperClassB, SuperClassC): |
| 387 | + def __init__(self, param_0, param_1, param_2, param_3, param_4): |
| 388 | + super().__init__(param_0, param_3, param_1, param_2) |
| 389 | + self.param_4 = param_4 |
| 390 | + |
| 391 | + |
| 392 | + sub = SubClass(0, 1, 2, 3, 4) |
| 393 | +
|
| 394 | +.. code-block:: python |
| 395 | + :linenos: |
| 396 | +
|
| 397 | + class SuperClassA: |
| 398 | + def __init__(self, param_0, param_3, **kargs): |
| 399 | + print('Called: SuperClassA.__init__()') |
| 400 | + super().__init__(**kargs) |
| 401 | + self.param_0 = param_0 |
| 402 | + self.param_3 = param_3 |
| 403 | + |
| 404 | + |
| 405 | + class SuperClassB: |
| 406 | + def __init__(self, param_1, **kargs): |
| 407 | + print('Called: SuperClassB.__init__()') |
| 408 | + super().__init__(**kargs) |
| 409 | + self.param_1 = param_1 |
| 410 | + |
| 411 | + class SuperClassC: |
| 412 | + def __init__(self, param_2, **kargs): |
| 413 | + print('Called: SuperClassC.__init__()') |
| 414 | + super().__init__(**kargs) |
| 415 | + self.param_2 = param_2 |
| 416 | + |
| 417 | + |
| 418 | + class SubClass(SuperClassA, SuperClassB, SuperClassC): |
| 419 | + def __init__(self, p0, p1, p2, p3, p4): |
| 420 | + super().__init__(param_0=p0, param_3=p3, param_1=p1, param_2=p2) |
| 421 | + self.param_4 = p4 |
| 422 | + |
| 423 | + |
| 424 | + sub = SubClass(0, 1, 2, 3, 4) |
252 | 425 | |
253 | 426 | انجمن (Association) |
254 | 427 | ---------------------------------- |
|
0 commit comments