|
3404 | 3404 | "print(even_numbers_as_strs)"
|
3405 | 3405 | ]
|
3406 | 3406 | },
|
| 3407 | + { |
| 3408 | + "cell_type": "markdown", |
| 3409 | + "metadata": {}, |
| 3410 | + "source": [ |
| 3411 | + "## Walrus operator" |
| 3412 | + ] |
| 3413 | + }, |
| 3414 | + { |
| 3415 | + "cell_type": "markdown", |
| 3416 | + "metadata": {}, |
| 3417 | + "source": [ |
| 3418 | + "В Python 3.8 се появява нов оператор, който ни позволява да имаме т.нар. \"assignment expression\" - израз, в който можем да присвояваме променливи.\n", |
| 3419 | + "\n", |
| 3420 | + "Чрез него можем да спестим изчисляването на дадени изрази, като ги присвоим към име на места, в който това не бе позволено." |
| 3421 | + ] |
| 3422 | + }, |
| 3423 | + { |
| 3424 | + "cell_type": "code", |
| 3425 | + "execution_count": 1, |
| 3426 | + "metadata": {}, |
| 3427 | + "outputs": [ |
| 3428 | + { |
| 3429 | + "data": { |
| 3430 | + "text/plain": [ |
| 3431 | + "{'count': 6, 'sum': 29, 'average': 4.833333333333333}" |
| 3432 | + ] |
| 3433 | + }, |
| 3434 | + "execution_count": 1, |
| 3435 | + "metadata": {}, |
| 3436 | + "output_type": "execute_result" |
| 3437 | + } |
| 3438 | + ], |
| 3439 | + "source": [ |
| 3440 | + "numbers = [4, 7, 6, 3, 1, 8]\n", |
| 3441 | + "\n", |
| 3442 | + "data = {\n", |
| 3443 | + " 'count': len(numbers),\n", |
| 3444 | + " 'sum': sum(numbers),\n", |
| 3445 | + " 'average': sum(numbers) / len(numbers)\n", |
| 3446 | + "}\n", |
| 3447 | + "\n", |
| 3448 | + "data" |
| 3449 | + ] |
| 3450 | + }, |
| 3451 | + { |
| 3452 | + "cell_type": "markdown", |
| 3453 | + "metadata": {}, |
| 3454 | + "source": [ |
| 3455 | + "Тук, изчисляваме дължината и сумата на елементите два пъти. Можем да отделим тези сметки в променливи, и да ги преизползваме." |
| 3456 | + ] |
| 3457 | + }, |
| 3458 | + { |
| 3459 | + "cell_type": "code", |
| 3460 | + "execution_count": 2, |
| 3461 | + "metadata": {}, |
| 3462 | + "outputs": [ |
| 3463 | + { |
| 3464 | + "data": { |
| 3465 | + "text/plain": [ |
| 3466 | + "{'count': 6, 'sum': 29, 'average': 4.833333333333333}" |
| 3467 | + ] |
| 3468 | + }, |
| 3469 | + "execution_count": 2, |
| 3470 | + "metadata": {}, |
| 3471 | + "output_type": "execute_result" |
| 3472 | + } |
| 3473 | + ], |
| 3474 | + "source": [ |
| 3475 | + "numbers = [4, 7, 6, 3, 1, 8]\n", |
| 3476 | + "\n", |
| 3477 | + "count = len(numbers)\n", |
| 3478 | + "total_sum = sum(numbers)\n", |
| 3479 | + "\n", |
| 3480 | + "data = {\n", |
| 3481 | + " 'count': count,\n", |
| 3482 | + " 'sum': total_sum,\n", |
| 3483 | + " 'average': total_sum / count\n", |
| 3484 | + "}\n", |
| 3485 | + "\n", |
| 3486 | + "data" |
| 3487 | + ] |
| 3488 | + }, |
| 3489 | + { |
| 3490 | + "cell_type": "markdown", |
| 3491 | + "metadata": {}, |
| 3492 | + "source": [ |
| 3493 | + "Проблемът тук е, че използваме тези променливи само за речника. Можем да \"преместим\" това дефиниране на стойностите вътре в речника, чрез използването на walrus оператора. \n", |
| 3494 | + "\n", |
| 3495 | + "Той изглежда по следният начин: `(name := expression)`. Важно е да се отбележи, че скобите са задължителни." |
| 3496 | + ] |
| 3497 | + }, |
| 3498 | + { |
| 3499 | + "cell_type": "code", |
| 3500 | + "execution_count": 4, |
| 3501 | + "metadata": {}, |
| 3502 | + "outputs": [ |
| 3503 | + { |
| 3504 | + "data": { |
| 3505 | + "text/plain": [ |
| 3506 | + "{'count': 6, 'sum': 29, 'average': 4.833333333333333}" |
| 3507 | + ] |
| 3508 | + }, |
| 3509 | + "execution_count": 4, |
| 3510 | + "metadata": {}, |
| 3511 | + "output_type": "execute_result" |
| 3512 | + } |
| 3513 | + ], |
| 3514 | + "source": [ |
| 3515 | + "numbers = [4, 7, 6, 3, 1, 8]\n", |
| 3516 | + "\n", |
| 3517 | + "data = {\n", |
| 3518 | + " 'count': (count := len(numbers)),\n", |
| 3519 | + " 'sum': (total_sum := sum(numbers)),\n", |
| 3520 | + " 'average': total_sum / count\n", |
| 3521 | + "}\n", |
| 3522 | + "\n", |
| 3523 | + "data" |
| 3524 | + ] |
| 3525 | + }, |
| 3526 | + { |
| 3527 | + "cell_type": "markdown", |
| 3528 | + "metadata": {}, |
| 3529 | + "source": [ |
| 3530 | + "Най-честото използване на walrus оператора е в list comprehension-и." |
| 3531 | + ] |
| 3532 | + }, |
| 3533 | + { |
| 3534 | + "cell_type": "markdown", |
| 3535 | + "metadata": {}, |
| 3536 | + "source": [ |
| 3537 | + "В долният пример имаме клас `Point`, както и функция `calculate_length`, която изчислява разстоянието между две точки.\n", |
| 3538 | + "\n", |
| 3539 | + "Дадени са ни 4 точки, като искаме да върнем точките и разстоянието между тях, ако то е по-малко от 3." |
| 3540 | + ] |
| 3541 | + }, |
| 3542 | + { |
| 3543 | + "cell_type": "code", |
| 3544 | + "execution_count": 25, |
| 3545 | + "metadata": {}, |
| 3546 | + "outputs": [], |
| 3547 | + "source": [ |
| 3548 | + "import math\n", |
| 3549 | + "\n", |
| 3550 | + "class Point:\n", |
| 3551 | + " def __init__(self, x, y):\n", |
| 3552 | + " self.x = x\n", |
| 3553 | + " self.y = y\n", |
| 3554 | + "\n", |
| 3555 | + " def __str__(self):\n", |
| 3556 | + " return f'({self.x}, {self.y})'\n", |
| 3557 | + " \n", |
| 3558 | + " def __repr__(self):\n", |
| 3559 | + " return str(self)\n", |
| 3560 | + "\n", |
| 3561 | + "def calculate_length(a, b):\n", |
| 3562 | + " return math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2)\n", |
| 3563 | + "\n", |
| 3564 | + "point_1 = Point(2, 3)\n", |
| 3565 | + "point_2 = Point(3, 4)\n", |
| 3566 | + "point_3 = Point(4, 5)\n", |
| 3567 | + "point_4 = Point(1, 0)\n", |
| 3568 | + "\n", |
| 3569 | + "first_points = [point_1, point_2]\n", |
| 3570 | + "second_points = [point_3, point_4]" |
| 3571 | + ] |
| 3572 | + }, |
| 3573 | + { |
| 3574 | + "cell_type": "code", |
| 3575 | + "execution_count": 26, |
| 3576 | + "metadata": {}, |
| 3577 | + "outputs": [ |
| 3578 | + { |
| 3579 | + "data": { |
| 3580 | + "text/plain": [ |
| 3581 | + "[((3, 4), (1, 0), 4.47213595499958)]" |
| 3582 | + ] |
| 3583 | + }, |
| 3584 | + "execution_count": 26, |
| 3585 | + "metadata": {}, |
| 3586 | + "output_type": "execute_result" |
| 3587 | + } |
| 3588 | + ], |
| 3589 | + "source": [ |
| 3590 | + "distances = [(first, second, calculate_length(first, second)) for first, second in zip(first_points, second_points) if calculate_length(first, second) > 3]\n", |
| 3591 | + "distances" |
| 3592 | + ] |
| 3593 | + }, |
| 3594 | + { |
| 3595 | + "cell_type": "markdown", |
| 3596 | + "metadata": {}, |
| 3597 | + "source": [ |
| 3598 | + "Прилагайки walrus оператора тук, кодът ни изглежда по следния начин:" |
| 3599 | + ] |
| 3600 | + }, |
| 3601 | + { |
| 3602 | + "cell_type": "code", |
| 3603 | + "execution_count": 27, |
| 3604 | + "metadata": {}, |
| 3605 | + "outputs": [ |
| 3606 | + { |
| 3607 | + "data": { |
| 3608 | + "text/plain": [ |
| 3609 | + "[((3, 4), (1, 0), 4.47213595499958)]" |
| 3610 | + ] |
| 3611 | + }, |
| 3612 | + "execution_count": 27, |
| 3613 | + "metadata": {}, |
| 3614 | + "output_type": "execute_result" |
| 3615 | + } |
| 3616 | + ], |
| 3617 | + "source": [ |
| 3618 | + "distances = [(first, second, length) for first, second in zip(first_points, second_points) if (length := calculate_length(first, second)) > 3]\n", |
| 3619 | + "distances" |
| 3620 | + ] |
| 3621 | + }, |
| 3622 | + { |
| 3623 | + "cell_type": "markdown", |
| 3624 | + "metadata": {}, |
| 3625 | + "source": [ |
| 3626 | + "## namedtuple" |
| 3627 | + ] |
| 3628 | + }, |
| 3629 | + { |
| 3630 | + "cell_type": "markdown", |
| 3631 | + "metadata": {}, |
| 3632 | + "source": [ |
| 3633 | + "В горният пример, дефинирахме клас `Point`, който единствено държи две стойности - `x` и `y`. Към него липсват методи (освен `__str__` и `__repr__`). \n", |
| 3634 | + "\n", |
| 3635 | + "Алтернативен вариант би бил да представим нашата точка като `tuple`. " |
| 3636 | + ] |
| 3637 | + }, |
| 3638 | + { |
| 3639 | + "cell_type": "code", |
| 3640 | + "execution_count": 30, |
| 3641 | + "metadata": {}, |
| 3642 | + "outputs": [ |
| 3643 | + { |
| 3644 | + "name": "stdout", |
| 3645 | + "output_type": "stream", |
| 3646 | + "text": [ |
| 3647 | + "(2, 3)\n" |
| 3648 | + ] |
| 3649 | + } |
| 3650 | + ], |
| 3651 | + "source": [ |
| 3652 | + "point_1 = (2, 3)\n", |
| 3653 | + "\n", |
| 3654 | + "print(f'({point_1[0]}, {point_1[1]})')" |
| 3655 | + ] |
| 3656 | + }, |
| 3657 | + { |
| 3658 | + "cell_type": "markdown", |
| 3659 | + "metadata": {}, |
| 3660 | + "source": [ |
| 3661 | + "Проблемът с този подход, е че трябва да гадаем на какво отговоря всеки от елементите на tuple-а. \n", |
| 3662 | + "\n", |
| 3663 | + "Python ни позволява да създадем т.нар. именувана n-торка (`namedtuple`). Този тип е подтип на `tuple`, но с избрано име от нас, и именувани член-данни.\n", |
| 3664 | + "\n", |
| 3665 | + "Можем да създадем `namedtuple` по следния начин:" |
| 3666 | + ] |
| 3667 | + }, |
| 3668 | + { |
| 3669 | + "cell_type": "code", |
| 3670 | + "execution_count": 32, |
| 3671 | + "metadata": {}, |
| 3672 | + "outputs": [ |
| 3673 | + { |
| 3674 | + "name": "stdout", |
| 3675 | + "output_type": "stream", |
| 3676 | + "text": [ |
| 3677 | + "(2, 3)\n", |
| 3678 | + "(2, 3)\n" |
| 3679 | + ] |
| 3680 | + } |
| 3681 | + ], |
| 3682 | + "source": [ |
| 3683 | + "from collections import namedtuple\n", |
| 3684 | + "point = namedtuple('Point', ['x', 'y'])\n", |
| 3685 | + "\n", |
| 3686 | + "point_1 = Point(2, 3)\n", |
| 3687 | + "\n", |
| 3688 | + "print(f'({point_1.x}, {point_1.y})')\n", |
| 3689 | + "print(point_1)" |
| 3690 | + ] |
| 3691 | + }, |
| 3692 | + { |
| 3693 | + "cell_type": "markdown", |
| 3694 | + "metadata": {}, |
| 3695 | + "source": [ |
| 3696 | + "Забелязваме, че `namedtuple` има предефиниран `__str__` и `__repr__` методи." |
| 3697 | + ] |
| 3698 | + }, |
3407 | 3699 | {
|
3408 | 3700 | "cell_type": "markdown",
|
3409 | 3701 | "metadata": {},
|
|
0 commit comments