Skip to content

Commit eedd985

Browse files
committed
Added sections about walrus and namedtuples
1 parent 5a8d9b2 commit eedd985

File tree

1 file changed

+292
-0
lines changed

1 file changed

+292
-0
lines changed

04 - Functional Programming/04 - Functional Programming.ipynb

+292
Original file line numberDiff line numberDiff line change
@@ -3404,6 +3404,298 @@
34043404
"print(even_numbers_as_strs)"
34053405
]
34063406
},
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+
},
34073699
{
34083700
"cell_type": "markdown",
34093701
"metadata": {},

0 commit comments

Comments
 (0)