|
241 | 241 | "### Decorator in Python"
|
242 | 242 | ]
|
243 | 243 | },
|
| 244 | + { |
| 245 | + "cell_type": "markdown", |
| 246 | + "id": "740ee443-484c-4ab5-8e51-ff97601b9dbf", |
| 247 | + "metadata": {}, |
| 248 | + "source": [ |
| 249 | + "Creating custom object behaviors or function modifications in Python often results in repetitive code and complex logic wrapped around the original functionality. This causes developers to write boilerplate code every time they need to add logging, timing, or validation to their functions." |
| 250 | + ] |
| 251 | + }, |
| 252 | + { |
| 253 | + "cell_type": "code", |
| 254 | + "execution_count": 24, |
| 255 | + "id": "06c450f1-e451-46fe-a202-86f76f6eef5b", |
| 256 | + "metadata": {}, |
| 257 | + "outputs": [ |
| 258 | + { |
| 259 | + "name": "stdout", |
| 260 | + "output_type": "stream", |
| 261 | + "text": [ |
| 262 | + "Add 1 and 2\n", |
| 263 | + "Elapsed time: 0.302ms\n", |
| 264 | + "Multiply 1 and 2\n", |
| 265 | + "Elapsed time: 0.005ms\n" |
| 266 | + ] |
| 267 | + }, |
| 268 | + { |
| 269 | + "data": { |
| 270 | + "text/plain": [ |
| 271 | + "2" |
| 272 | + ] |
| 273 | + }, |
| 274 | + "execution_count": 24, |
| 275 | + "metadata": {}, |
| 276 | + "output_type": "execute_result" |
| 277 | + } |
| 278 | + ], |
| 279 | + "source": [ |
| 280 | + "def add(num1: int, num2: int):\n", |
| 281 | + " \"\"\"Takes two integers and returns their sum.\"\"\"\n", |
| 282 | + " start = time.time()\n", |
| 283 | + " print(f\"Add {num1} and {num2}\")\n", |
| 284 | + " res = num1 + num2\n", |
| 285 | + " end = time.time()\n", |
| 286 | + " print(f'Elapsed time: {(end - start) * 1000:.3f}ms')\n", |
| 287 | + " return res\n", |
| 288 | + "\n", |
| 289 | + "def multiply(num1: int, num2: int):\n", |
| 290 | + " \"\"\"Takes two integers and returns their product.\"\"\"\n", |
| 291 | + " start = time.time()\n", |
| 292 | + " print(f\"Multiply {num1} and {num2}\")\n", |
| 293 | + " res = num1 * num2\n", |
| 294 | + " end = time.time()\n", |
| 295 | + " print(f'Elapsed time: {(end - start) * 1000:.3f}ms')\n", |
| 296 | + " return res\n", |
| 297 | + "\n", |
| 298 | + "add(1, 2)\n", |
| 299 | + "multiply(1, 2)" |
| 300 | + ] |
| 301 | + }, |
| 302 | + { |
| 303 | + "cell_type": "markdown", |
| 304 | + "id": "03b5507b-ee31-4b52-a371-f2d8c9fcec57", |
| 305 | + "metadata": {}, |
| 306 | + "source": [ |
| 307 | + "Changing functionality across multiple functions can be time-consuming." |
| 308 | + ] |
| 309 | + }, |
| 310 | + { |
| 311 | + "cell_type": "code", |
| 312 | + "execution_count": null, |
| 313 | + "id": "aad7eb90-c4fe-430b-84b2-fbb5bec18b3e", |
| 314 | + "metadata": {}, |
| 315 | + "outputs": [], |
| 316 | + "source": [ |
| 317 | + "def add(num1: int, num2: int):\n", |
| 318 | + " \"\"\"Takes two integers and returns their sum.\"\"\"\n", |
| 319 | + " start = time.time()\n", |
| 320 | + " print(f\"Add {num1} and {num2}\")\n", |
| 321 | + " res = num1 + num2\n", |
| 322 | + " end = time.time()\n", |
| 323 | + " print(f'Elapsed time: {(end - start):.3f}s') # Change to seconds\n", |
| 324 | + " return res\n", |
| 325 | + "\n", |
| 326 | + "def multiply(num1: int, num2: int):\n", |
| 327 | + " \"\"\"Takes two integers and returns their product.\"\"\"\n", |
| 328 | + " start = time.time()\n", |
| 329 | + " print(f\"Multiply {num1} and {num2}\")\n", |
| 330 | + " res = num1 * num2\n", |
| 331 | + " end = time.time()\n", |
| 332 | + " print(f'Elapsed time: {(end - start) * 1000:.3f}ms') # Fog\n", |
| 333 | + " return res\n", |
| 334 | + "\n", |
| 335 | + "add(1, 2)\n", |
| 336 | + "multiply(1, 2)" |
| 337 | + ] |
| 338 | + }, |
244 | 339 | {
|
245 | 340 | "attachments": {},
|
246 | 341 | "cell_type": "markdown",
|
247 | 342 | "id": "459bffb1",
|
248 | 343 | "metadata": {},
|
249 | 344 | "source": [
|
250 |
| - "If you want to apply a common piece of functionality to multiple functions while keeping the code clean, use decorator. Decorator modifies the behavior of your Python functions without altering the code directly.\n", |
| 345 | + "With decorators, you can create reusable wrappers that add functionality to your functions without modifying their code. You can easily add timing, logging, or validation to any function with a single line.\n", |
251 | 346 | "\n",
|
252 |
| - "In the code below, `time_func` is a decorator that can be used to track the execution time of any function." |
| 347 | + "In the code below, `time_func` is a decorator that can be used to track the execution time of any function. This decorator can be applied to any function, making the code more maintainable and reducing duplication. " |
253 | 348 | ]
|
254 | 349 | },
|
255 | 350 | {
|
256 | 351 | "cell_type": "code",
|
257 |
| - "execution_count": 27, |
| 352 | + "execution_count": 21, |
258 | 353 | "id": "712e1fcd",
|
259 | 354 | "metadata": {
|
260 | 355 | "ExecuteTime": {
|
261 | 356 | "end_time": "2021-08-30T00:49:30.920515Z",
|
262 | 357 | "start_time": "2021-08-30T00:49:30.913093Z"
|
263 | 358 | }
|
264 | 359 | },
|
265 |
| - "outputs": [], |
| 360 | + "outputs": [ |
| 361 | + { |
| 362 | + "name": "stdout", |
| 363 | + "output_type": "stream", |
| 364 | + "text": [ |
| 365 | + "Add 1 and 2\n", |
| 366 | + "Elapsed time: 0.425ms\n", |
| 367 | + "Multiply 1 and 2\n", |
| 368 | + "Elapsed time: 0.009ms\n" |
| 369 | + ] |
| 370 | + }, |
| 371 | + { |
| 372 | + "data": { |
| 373 | + "text/plain": [ |
| 374 | + "2" |
| 375 | + ] |
| 376 | + }, |
| 377 | + "execution_count": 21, |
| 378 | + "metadata": {}, |
| 379 | + "output_type": "execute_result" |
| 380 | + } |
| 381 | + ], |
266 | 382 | "source": [
|
267 | 383 | "import time \n",
|
268 | 384 | "\n",
|
269 | 385 | "def time_func(func):\n",
|
270 | 386 | " def wrapper(*args, **kwargs):\n",
|
271 | 387 | " start = time.time()\n",
|
272 |
| - " func(*args, **kwargs)\n", |
| 388 | + " res = func(*args, **kwargs)\n", |
273 | 389 | " end = time.time()\n",
|
274 | 390 | " print(f'Elapsed time: {(end - start) * 1000:.3f}ms')\n",
|
275 |
| - " return wrapper" |
| 391 | + " return res\n", |
| 392 | + " return wrapper\n", |
| 393 | + "\n", |
| 394 | + "@time_func\n", |
| 395 | + "def add(num1: int, num2: int):\n", |
| 396 | + " \"\"\"Takes two integers and returns their sum.\"\"\"\n", |
| 397 | + " print(f\"Add {num1} and {num2}\")\n", |
| 398 | + " return num1 + num2\n", |
| 399 | + "\n", |
| 400 | + "@time_func\n", |
| 401 | + "def multiply(num1: int, num2: int):\n", |
| 402 | + " \"\"\"Takes two integers and returns their product.\"\"\"\n", |
| 403 | + " print(f\"Multiply {num1} and {num2}\")\n", |
| 404 | + " return num1 * num2\n", |
| 405 | + "\n", |
| 406 | + "add(1, 2)\n", |
| 407 | + "multiply(1, 2)" |
| 408 | + ] |
| 409 | + }, |
| 410 | + { |
| 411 | + "cell_type": "markdown", |
| 412 | + "id": "6a5e056e-58b0-4ce7-9b56-29e4960451f0", |
| 413 | + "metadata": {}, |
| 414 | + "source": [ |
| 415 | + "If you need to modify the timing logic, you only need to update it in one place." |
276 | 416 | ]
|
277 | 417 | },
|
278 | 418 | {
|
279 | 419 | "cell_type": "code",
|
280 |
| - "execution_count": 30, |
281 |
| - "id": "1226ad8f", |
282 |
| - "metadata": { |
283 |
| - "ExecuteTime": { |
284 |
| - "end_time": "2021-08-30T00:49:39.814766Z", |
285 |
| - "start_time": "2021-08-30T00:49:39.804463Z" |
286 |
| - } |
287 |
| - }, |
| 420 | + "execution_count": 20, |
| 421 | + "id": "126c3f4e-2877-4c64-8c99-1b0bb2196e87", |
| 422 | + "metadata": {}, |
288 | 423 | "outputs": [
|
289 | 424 | {
|
290 | 425 | "name": "stdout",
|
291 | 426 | "output_type": "stream",
|
292 | 427 | "text": [
|
293 | 428 | "Add 1 and 2\n",
|
294 |
| - "Elapsed time: 1.006ms\n", |
| 429 | + "Elapsed time: 0.000s\n", |
295 | 430 | "Multiply 1 and 2\n",
|
296 |
| - "Elapsed time: 0.027ms\n" |
| 431 | + "Elapsed time: 0.000s\n" |
297 | 432 | ]
|
| 433 | + }, |
| 434 | + { |
| 435 | + "data": { |
| 436 | + "text/plain": [ |
| 437 | + "2" |
| 438 | + ] |
| 439 | + }, |
| 440 | + "execution_count": 20, |
| 441 | + "metadata": {}, |
| 442 | + "output_type": "execute_result" |
298 | 443 | }
|
299 | 444 | ],
|
300 | 445 | "source": [
|
| 446 | + "import time \n", |
| 447 | + "\n", |
| 448 | + "def time_func(func):\n", |
| 449 | + " def wrapper(*args, **kwargs):\n", |
| 450 | + " start = time.time()\n", |
| 451 | + " res = func(*args, **kwargs)\n", |
| 452 | + " end = time.time()\n", |
| 453 | + " print(f'Elapsed time: {(end - start):.3f}s')\n", |
| 454 | + " return res\n", |
| 455 | + " return wrapper\n", |
| 456 | + "\n", |
301 | 457 | "@time_func\n",
|
302 | 458 | "def add(num1: int, num2: int):\n",
|
| 459 | + " \"\"\"Takes two integers and returns their sum.\"\"\"\n", |
303 | 460 | " print(f\"Add {num1} and {num2}\")\n",
|
304 | 461 | " return num1 + num2\n",
|
305 | 462 | "\n",
|
306 | 463 | "@time_func\n",
|
307 | 464 | "def multiply(num1: int, num2: int):\n",
|
| 465 | + " \"\"\"Takes two integers and returns their product.\"\"\"\n", |
308 | 466 | " print(f\"Multiply {num1} and {num2}\")\n",
|
309 | 467 | " return num1 * num2\n",
|
310 | 468 | "\n",
|
311 | 469 | "add(1, 2)\n",
|
312 | 470 | "multiply(1, 2)"
|
313 | 471 | ]
|
314 | 472 | },
|
| 473 | + { |
| 474 | + "cell_type": "markdown", |
| 475 | + "id": "702d484b-b5b3-4ac1-b6d2-a0209d223277", |
| 476 | + "metadata": {}, |
| 477 | + "source": [ |
| 478 | + "However, when we use the `time_func` decorator, it changes the function name and docstring. " |
| 479 | + ] |
| 480 | + }, |
| 481 | + { |
| 482 | + "cell_type": "code", |
| 483 | + "execution_count": 14, |
| 484 | + "id": "d0056209-b0ec-4436-b933-6ff5a21679b0", |
| 485 | + "metadata": {}, |
| 486 | + "outputs": [ |
| 487 | + { |
| 488 | + "name": "stdout", |
| 489 | + "output_type": "stream", |
| 490 | + "text": [ |
| 491 | + "Function name: wrapper\n", |
| 492 | + "Docstring: None\n" |
| 493 | + ] |
| 494 | + } |
| 495 | + ], |
| 496 | + "source": [ |
| 497 | + "print(f\"Function name: {add.__name__}\")\n", |
| 498 | + "print(f\"Docstring: {add.__doc__}\")" |
| 499 | + ] |
| 500 | + }, |
| 501 | + { |
| 502 | + "cell_type": "markdown", |
| 503 | + "id": "feaddc81-8ada-4a99-ac50-5f7eefea031f", |
| 504 | + "metadata": {}, |
| 505 | + "source": [ |
| 506 | + "To preserve the original function metadata, we can use the `wraps` decorator from the `functools` module." |
| 507 | + ] |
| 508 | + }, |
| 509 | + { |
| 510 | + "cell_type": "code", |
| 511 | + "execution_count": 7, |
| 512 | + "id": "0b63ae07-1704-4b83-9ad3-48c6242237fa", |
| 513 | + "metadata": {}, |
| 514 | + "outputs": [], |
| 515 | + "source": [ |
| 516 | + "import time\n", |
| 517 | + "from functools import wraps\n", |
| 518 | + "\n", |
| 519 | + "def time_func_with_wraps(func):\n", |
| 520 | + " @wraps(func)\n", |
| 521 | + " def wrapper(*args, **kwargs):\n", |
| 522 | + " start = time.time()\n", |
| 523 | + " res = func(*args, **kwargs)\n", |
| 524 | + " end = time.time()\n", |
| 525 | + " print(f'Elapsed time: {(end - start) * 1000:.3f}ms')\n", |
| 526 | + " return res\n", |
| 527 | + " return wrapper" |
| 528 | + ] |
| 529 | + }, |
| 530 | + { |
| 531 | + "cell_type": "code", |
| 532 | + "execution_count": 15, |
| 533 | + "id": "47e11ca8-62e0-4b69-b6a2-398c3f71c2b7", |
| 534 | + "metadata": {}, |
| 535 | + "outputs": [ |
| 536 | + { |
| 537 | + "name": "stdout", |
| 538 | + "output_type": "stream", |
| 539 | + "text": [ |
| 540 | + "Add 1 and 2\n", |
| 541 | + "Elapsed time: 0.332ms\n", |
| 542 | + "Multiply 1 and 2\n", |
| 543 | + "Elapsed time: 0.008ms\n" |
| 544 | + ] |
| 545 | + }, |
| 546 | + { |
| 547 | + "data": { |
| 548 | + "text/plain": [ |
| 549 | + "2" |
| 550 | + ] |
| 551 | + }, |
| 552 | + "execution_count": 15, |
| 553 | + "metadata": {}, |
| 554 | + "output_type": "execute_result" |
| 555 | + } |
| 556 | + ], |
| 557 | + "source": [ |
| 558 | + "@time_func_with_wraps\n", |
| 559 | + "def add(num1: int, num2: int):\n", |
| 560 | + " \"\"\"Takes two integers and returns their sum.\"\"\"\n", |
| 561 | + " print(f\"Add {num1} and {num2}\")\n", |
| 562 | + " return num1 + num2\n", |
| 563 | + "\n", |
| 564 | + "@time_func_with_wraps\n", |
| 565 | + "def multiply(num1: int, num2: int):\n", |
| 566 | + " \"\"\"Takes two integers and returns their product.\"\"\"\n", |
| 567 | + " print(f\"Multiply {num1} and {num2}\")\n", |
| 568 | + " return num1 * num2\n", |
| 569 | + "\n", |
| 570 | + "add(1, 2)\n", |
| 571 | + "multiply(1, 2)" |
| 572 | + ] |
| 573 | + }, |
| 574 | + { |
| 575 | + "cell_type": "code", |
| 576 | + "execution_count": 16, |
| 577 | + "id": "db1f1170-f2ba-494c-a6c0-f0a4a18fd309", |
| 578 | + "metadata": {}, |
| 579 | + "outputs": [ |
| 580 | + { |
| 581 | + "name": "stdout", |
| 582 | + "output_type": "stream", |
| 583 | + "text": [ |
| 584 | + "Function name: add\n", |
| 585 | + "Docstring: Takes two integers and returns their sum.\n" |
| 586 | + ] |
| 587 | + } |
| 588 | + ], |
| 589 | + "source": [ |
| 590 | + "print(f\"Function name: {add.__name__}\")\n", |
| 591 | + "print(f\"Docstring: {add.__doc__}\")" |
| 592 | + ] |
| 593 | + }, |
315 | 594 | {
|
316 | 595 | "attachments": {},
|
317 | 596 | "cell_type": "markdown",
|
|
529 | 808 | ],
|
530 | 809 | "metadata": {
|
531 | 810 | "kernelspec": {
|
532 |
| - "display_name": "Python 3 (ipykernel)", |
| 811 | + "display_name": "venv", |
533 | 812 | "language": "python",
|
534 | 813 | "name": "python3"
|
535 | 814 | },
|
|
0 commit comments