|
376 | 376 | "We're repeating the code for the constructor, introduce and, eat. The main difference is the profession specific method!\n",
|
377 | 377 | "What if we want to change how a person should be introduced? We'd have to update the `introduce` method in `Person`, `ComputerScientist`, `Doctor`.\n",
|
378 | 378 | "\n",
|
379 |
| - "We can use *inheritance* to simplify our code, improve its maintainability, reduce development costs (avoids the scenario above which could introduce bugs!),\n", |
| 379 | + "We can use *inheritance* to improve its maintainability, reduce development costs (avoids the scenario above which could introduce bugs!),\n", |
380 | 380 | "and avoid repeating code."
|
381 | 381 | ]
|
382 | 382 | },
|
|
465 | 465 | "cell_type": "markdown",
|
466 | 466 | "metadata": {},
|
467 | 467 | "source": [
|
468 |
| - "**[INSERT diagram for class vs object]**" |
| 468 | + "### Intermission: Decorators\n", |
| 469 | + "Before we continue exploring object-oriented programming, let's have a look at decorators.\n", |
| 470 | + "\n", |
| 471 | + "Congratulations, you've just been hired by the *National X-Soc Co-op Bank Ltd* to develop their ATM system!\n", |
| 472 | + "\n", |
| 473 | + "They want you to implement the depositing and withdrawal functionality and you define the\n", |
| 474 | + "functions `deposit_monies` and `withdraw_monies`.\n", |
| 475 | + "These operations are, of course, very sensitive, so you check if the username matches\n", |
| 476 | + "the username of the authorised personnel." |
| 477 | + ] |
| 478 | + }, |
| 479 | + { |
| 480 | + "cell_type": "code", |
| 481 | + "execution_count": null, |
| 482 | + "metadata": {}, |
| 483 | + "outputs": [], |
| 484 | + "source": [ |
| 485 | + "def deposit_monies(user):\n", |
| 486 | + " if user not in {\"admin\", \"important_banker\"}:\n", |
| 487 | + " print(\"Unauthorised!\")\n", |
| 488 | + " return\n", |
| 489 | + " \n", |
| 490 | + " print(f\"Brrr brr very important operation. Depositing $44b into an account\")\n", |
| 491 | + "\n", |
| 492 | + "def withdraw_monies(user):\n", |
| 493 | + " if user not in {\"admin\", \"important_banker\"}:\n", |
| 494 | + " print(\"Unauthorised!\")\n", |
| 495 | + " return\n", |
| 496 | + " \n", |
| 497 | + " print(f\"Brrr brr very important operation. Withdrawing $44b from an account\")\n", |
| 498 | + "\n", |
| 499 | + "withdraw_monies(\"admin\")\n", |
| 500 | + "withdraw_monies(\"donald knuth\")\n", |
| 501 | + "\n", |
| 502 | + "deposit_monies(\"admin\")\n", |
| 503 | + "deposit_monies(\"donald knuth\")" |
469 | 504 | ]
|
470 | 505 | },
|
471 | 506 | {
|
472 | 507 | "cell_type": "markdown",
|
473 | 508 | "metadata": {},
|
474 | 509 | "source": [
|
475 |
| - "TBD:\n", |
476 |
| - "- polymorphism/abstraction/encapsulation a little bit\n", |
477 |
| - "- attributes (class and instance atttr)\n", |
478 |
| - "- inheritance example\n", |
479 |
| - "- then intermission on anotations\n", |
480 |
| - "- static and class methods" |
| 510 | + "However, after an FCA audit, the auditors notice that the authorisation code is repeated in each operation.\n", |
| 511 | + "If we want to update our authorisation scheme, we'd have to update the code of every operation. This is error prone and could introduce vulnerabilities into the ATM system\n", |
| 512 | + "so the FCA asked the *National X-Soc Co-op Bank Ltd* to investigate this issue.\n", |
| 513 | + "\n", |
| 514 | + "We could start, by introducing a function which \"adds\" this authorisation code before an operation.\n", |
| 515 | + "As we've learned, **everything** in Python is an object, including functions, so you can pass a function\n", |
| 516 | + "as an argument of a function or even return a function!\n", |
| 517 | + "\n", |
| 518 | + "Essentially, we define a function, which will return another function. The new function\n", |
| 519 | + "checks if the user is authorised, and if the user is authorised, we execute the operation!" |
| 520 | + ] |
| 521 | + }, |
| 522 | + { |
| 523 | + "cell_type": "code", |
| 524 | + "execution_count": null, |
| 525 | + "metadata": {}, |
| 526 | + "outputs": [], |
| 527 | + "source": [ |
| 528 | + "def requires_authorisation(operation):\n", |
| 529 | + " def secure_operation(user):\n", |
| 530 | + " if user not in {\"admin\", \"important_banker\"}:\n", |
| 531 | + " print(\"Unauthorised!\")\n", |
| 532 | + " return\n", |
| 533 | + " \n", |
| 534 | + " operation(user)\n", |
| 535 | + "\n", |
| 536 | + " return secure_operation\n", |
| 537 | + "\n", |
| 538 | + "def deposit_monies(user):\n", |
| 539 | + " print(f\"Brrr brr very important operation. Depositing $44b into an account\")\n", |
| 540 | + "\n", |
| 541 | + "def withdraw_monies(user):\n", |
| 542 | + " print(f\"Brrr brr very important operation. Withdrawing $44b from an account\")\n", |
| 543 | + "\n", |
| 544 | + "\n", |
| 545 | + "secure_withdraw_monies = requires_authorisation(withdraw_monies)\n", |
| 546 | + "\n", |
| 547 | + "secure_withdraw_monies(\"admin\")\n", |
| 548 | + "secure_withdraw_monies(\"donald knuth\")\n", |
| 549 | + "\n", |
| 550 | + "secure_deposit_monies = requires_authorisation(deposit_monies)\n", |
| 551 | + "\n", |
| 552 | + "secure_deposit_monies(\"admin\")\n", |
| 553 | + "secure_deposit_monies(\"donald knuth\")" |
481 | 554 | ]
|
482 | 555 | },
|
483 | 556 | {
|
484 | 557 | "cell_type": "markdown",
|
485 | 558 | "metadata": {},
|
486 | 559 | "source": [
|
487 |
| - "### Intermission: Decorators\n", |
488 |
| - "Before we continue exploring classes...\n" |
| 560 | + "However, we can go one step further and make our code a bit nicer with *syntatic sugar*" |
| 561 | + ] |
| 562 | + }, |
| 563 | + { |
| 564 | + "cell_type": "code", |
| 565 | + "execution_count": null, |
| 566 | + "metadata": {}, |
| 567 | + "outputs": [], |
| 568 | + "source": [ |
| 569 | + "def requires_authorisation(operation):\n", |
| 570 | + " def secure_operation(user):\n", |
| 571 | + " if user not in {\"admin\", \"important_banker\"}:\n", |
| 572 | + " print(\"Unauthorised!\")\n", |
| 573 | + " return\n", |
| 574 | + " \n", |
| 575 | + " operation(user)\n", |
| 576 | + "\n", |
| 577 | + " return secure_operation\n", |
| 578 | + "\n", |
| 579 | + "@requires_authorisation\n", |
| 580 | + "def deposit_monies(user):\n", |
| 581 | + " print(f\"Brrr brr very important operation. Depositing $44b into an account\")\n", |
| 582 | + "\n", |
| 583 | + "@requires_authorisation\n", |
| 584 | + "def withdraw_monies(user):\n", |
| 585 | + " print(f\"Brrr brr very important operation. Withdrawing $44b from an account\")\n", |
| 586 | + "\n", |
| 587 | + "withdraw_monies(\"admin\")\n", |
| 588 | + "withdraw_monies(\"donald knuth\")\n", |
| 589 | + "\n", |
| 590 | + "deposit_monies(\"admin\")\n", |
| 591 | + "deposit_monies(\"donald knuth\")" |
| 592 | + ] |
| 593 | + }, |
| 594 | + { |
| 595 | + "cell_type": "markdown", |
| 596 | + "metadata": {}, |
| 597 | + "source": [ |
| 598 | + "**[INSERT diagram for class vs object]**" |
| 599 | + ] |
| 600 | + }, |
| 601 | + { |
| 602 | + "cell_type": "markdown", |
| 603 | + "metadata": {}, |
| 604 | + "source": [ |
| 605 | + "TBD:\n", |
| 606 | + "- polymorphism/abstraction/encapsulation a little bit\n", |
| 607 | + "- then intermission on anotations\n", |
| 608 | + "- static and class methods" |
489 | 609 | ]
|
490 | 610 | },
|
491 | 611 | {
|
|
0 commit comments