[{"data":1,"prerenderedAt":1902},["ShallowReactive",2],{"page-\u002Fpython\u002F17-modules-and-packages":3},{"id":4,"title":5,"body":6,"description":36,"extension":1896,"meta":1897,"navigation":83,"path":1898,"seo":1899,"stem":1900,"__hash__":1901},"content\u002Fpython\u002F17-modules-and-packages.md","17 — Modules & Packages",{"type":7,"value":8,"toc":1871},"minimark",[9,13,18,27,98,253,259,346,385,422,426,437,481,518,579,587,591,672,678,682,731,800,824,860,865,913,917,960,964,973,983,1093,1132,1146,1156,1232,1242,1246,1274,1281,1284,1360,1386,1393,1400,1427,1431,1489,1493,1575,1579,1586,1677,1817,1821,1867],[10,11,5],"h1",{"id":12},"_17-modules-packages",[14,15,17],"h2",{"id":16},"modules-the-basic-unit-of-code-organization","Modules: The Basic Unit of Code Organization",[19,20,21,22,26],"p",{},"Any ",[23,24,25],"code",{},".py"," file is a module. Importing it runs the file's top-level code exactly once (subsequent imports reuse the cached result) and binds the module's name in the importer's namespace.",[28,29,31],"code-wrapper",{"language":30},"python",[32,33,37],"pre",{"className":34,"code":35,"language":30,"meta":36,"style":36},"language-python shiki shiki-themes github-light github-dark","# math_utils.py\ndef add(a, b):\n    return a + b\n\nPI = 3.14159\n","",[23,38,39,48,63,78,85],{"__ignoreMap":36},[40,41,44],"span",{"class":42,"line":43},"line",1,[40,45,47],{"class":46},"sdCPZ","# math_utils.py\n",[40,49,51,55,59],{"class":42,"line":50},2,[40,52,54],{"class":53},"svdQ7","def",[40,56,58],{"class":57},"sIsaT"," add",[40,60,62],{"class":61},"ssxIu","(a, b):\n",[40,64,66,69,72,75],{"class":42,"line":65},3,[40,67,68],{"class":53},"    return",[40,70,71],{"class":61}," a ",[40,73,74],{"class":53},"+",[40,76,77],{"class":61}," b\n",[40,79,81],{"class":42,"line":80},4,[40,82,84],{"emptyLinePlaceholder":83},true,"\n",[40,86,88,92,95],{"class":42,"line":87},5,[40,89,91],{"class":90},"snvgF","PI",[40,93,94],{"class":53}," =",[40,96,97],{"class":90}," 3.14159\n",[28,99,100],{"language":30},[32,101,103],{"className":34,"code":102,"language":30,"meta":36,"style":36},"# main.py\nimport math_utils\n\nprint(math_utils.add(2, 3))   # 5\nprint(math_utils.PI)            # 3.14159\n\nfrom math_utils import add, PI   # import specific names directly into the current namespace\nprint(add(1, 1))                   # 2\n\nfrom math_utils import add as sum_two   # rename on import to avoid clashes\nprint(sum_two(4, 5))                      # 9\n",[23,104,105,110,118,122,145,160,165,184,205,210,231],{"__ignoreMap":36},[40,106,107],{"class":42,"line":43},[40,108,109],{"class":46},"# main.py\n",[40,111,112,115],{"class":42,"line":50},[40,113,114],{"class":53},"import",[40,116,117],{"class":61}," math_utils\n",[40,119,120],{"class":42,"line":65},[40,121,84],{"emptyLinePlaceholder":83},[40,123,124,127,130,133,136,139,142],{"class":42,"line":80},[40,125,126],{"class":90},"print",[40,128,129],{"class":61},"(math_utils.add(",[40,131,132],{"class":90},"2",[40,134,135],{"class":61},", ",[40,137,138],{"class":90},"3",[40,140,141],{"class":61},"))   ",[40,143,144],{"class":46},"# 5\n",[40,146,147,149,152,154,157],{"class":42,"line":87},[40,148,126],{"class":90},[40,150,151],{"class":61},"(math_utils.",[40,153,91],{"class":90},[40,155,156],{"class":61},")            ",[40,158,159],{"class":46},"# 3.14159\n",[40,161,163],{"class":42,"line":162},6,[40,164,84],{"emptyLinePlaceholder":83},[40,166,168,171,174,176,179,181],{"class":42,"line":167},7,[40,169,170],{"class":53},"from",[40,172,173],{"class":61}," math_utils ",[40,175,114],{"class":53},[40,177,178],{"class":61}," add, ",[40,180,91],{"class":90},[40,182,183],{"class":46},"   # import specific names directly into the current namespace\n",[40,185,187,189,192,195,197,199,202],{"class":42,"line":186},8,[40,188,126],{"class":90},[40,190,191],{"class":61},"(add(",[40,193,194],{"class":90},"1",[40,196,135],{"class":61},[40,198,194],{"class":90},[40,200,201],{"class":61},"))                   ",[40,203,204],{"class":46},"# 2\n",[40,206,208],{"class":42,"line":207},9,[40,209,84],{"emptyLinePlaceholder":83},[40,211,213,215,217,219,222,225,228],{"class":42,"line":212},10,[40,214,170],{"class":53},[40,216,173],{"class":61},[40,218,114],{"class":53},[40,220,221],{"class":61}," add ",[40,223,224],{"class":53},"as",[40,226,227],{"class":61}," sum_two   ",[40,229,230],{"class":46},"# rename on import to avoid clashes\n",[40,232,234,236,239,242,244,247,250],{"class":42,"line":233},11,[40,235,126],{"class":90},[40,237,238],{"class":61},"(sum_two(",[40,240,241],{"class":90},"4",[40,243,135],{"class":61},[40,245,246],{"class":90},"5",[40,248,249],{"class":61},"))                      ",[40,251,252],{"class":46},"# 9\n",[14,254,256],{"id":255},"if-__name__-__main__",[23,257,258],{},"if __name__ == \"__main__\":",[28,260,261],{"language":30},[32,262,264],{"className":34,"code":263,"language":30,"meta":36,"style":36},"# calculator.py\ndef add(a, b):\n    return a + b\n\ndef main():\n    print(add(2, 3))\n\nif __name__ == \"__main__\":\n    main()\n",[23,265,266,271,279,289,293,303,319,323,341],{"__ignoreMap":36},[40,267,268],{"class":42,"line":43},[40,269,270],{"class":46},"# calculator.py\n",[40,272,273,275,277],{"class":42,"line":50},[40,274,54],{"class":53},[40,276,58],{"class":57},[40,278,62],{"class":61},[40,280,281,283,285,287],{"class":42,"line":65},[40,282,68],{"class":53},[40,284,71],{"class":61},[40,286,74],{"class":53},[40,288,77],{"class":61},[40,290,291],{"class":42,"line":80},[40,292,84],{"emptyLinePlaceholder":83},[40,294,295,297,300],{"class":42,"line":87},[40,296,54],{"class":53},[40,298,299],{"class":57}," main",[40,301,302],{"class":61},"():\n",[40,304,305,308,310,312,314,316],{"class":42,"line":162},[40,306,307],{"class":90},"    print",[40,309,191],{"class":61},[40,311,132],{"class":90},[40,313,135],{"class":61},[40,315,138],{"class":90},[40,317,318],{"class":61},"))\n",[40,320,321],{"class":42,"line":167},[40,322,84],{"emptyLinePlaceholder":83},[40,324,325,328,331,334,338],{"class":42,"line":186},[40,326,327],{"class":53},"if",[40,329,330],{"class":90}," __name__",[40,332,333],{"class":53}," ==",[40,335,337],{"class":336},"sJ6F3"," \"__main__\"",[40,339,340],{"class":61},":\n",[40,342,343],{"class":42,"line":207},[40,344,345],{"class":61},"    main()\n",[19,347,348,349,352,353,356,357,359,360,363,364,368,369,371,372,375,376,380,381,384],{},"Every module has a ",[23,350,351],{},"__name__"," attribute — when a file is run directly (",[23,354,355],{},"python calculator.py","), Python sets ",[23,358,351],{}," to ",[23,361,362],{},"\"__main__\"","; when the same file is ",[365,366,367],"em",{},"imported"," by another module, ",[23,370,351],{}," is set to the module's actual name (",[23,373,374],{},"\"calculator\"",") instead. This guard lets a file work both as a reusable, importable library ",[377,378,379],"strong",{},"and"," as a standalone script, without the \"script\" behavior (like ",[23,382,383],{},"main()",") accidentally running just because something imported it for its functions.",[28,386,387],{"language":30},[32,388,390],{"className":34,"code":389,"language":30,"meta":36,"style":36},"import calculator   # does NOT print anything — main() only runs when calculator.py is executed directly\nprint(calculator.add(10, 20))   # 30 — the function is still perfectly usable\n",[23,391,392,402],{"__ignoreMap":36},[40,393,394,396,399],{"class":42,"line":43},[40,395,114],{"class":53},[40,397,398],{"class":61}," calculator   ",[40,400,401],{"class":46},"# does NOT print anything — main() only runs when calculator.py is executed directly\n",[40,403,404,406,409,412,414,417,419],{"class":42,"line":50},[40,405,126],{"class":90},[40,407,408],{"class":61},"(calculator.add(",[40,410,411],{"class":90},"10",[40,413,135],{"class":61},[40,415,416],{"class":90},"20",[40,418,141],{"class":61},[40,420,421],{"class":46},"# 30 — the function is still perfectly usable\n",[14,423,425],{"id":424},"packages-directories-of-modules","Packages: Directories of Modules",[19,427,428,429,432,433,436],{},"A ",[377,430,431],{},"package"," is a directory containing an ",[23,434,435],{},"__init__.py"," file (making it importable as a single namespace) plus any number of module files or sub-packages.",[28,438,439],{"language":30},[32,440,444],{"className":441,"code":442,"language":443,"meta":36,"style":36},"language-bash shiki shiki-themes github-light github-dark","myapp\u002F\n    __init__.py\n    models.py\n    utils\u002F\n        __init__.py\n        validation.py\n        formatting.py\n","bash",[23,445,446,451,456,461,466,471,476],{"__ignoreMap":36},[40,447,448],{"class":42,"line":43},[40,449,450],{"class":57},"myapp\u002F\n",[40,452,453],{"class":42,"line":50},[40,454,455],{"class":57},"    __init__.py\n",[40,457,458],{"class":42,"line":65},[40,459,460],{"class":57},"    models.py\n",[40,462,463],{"class":42,"line":80},[40,464,465],{"class":57},"    utils\u002F\n",[40,467,468],{"class":42,"line":87},[40,469,470],{"class":57},"        __init__.py\n",[40,472,473],{"class":42,"line":162},[40,474,475],{"class":57},"        validation.py\n",[40,477,478],{"class":42,"line":167},[40,479,480],{"class":57},"        formatting.py\n",[28,482,483],{"language":30},[32,484,486],{"className":34,"code":485,"language":30,"meta":36,"style":36},"# myapp\u002F__init__.py\nfrom .models import User          # re-export for a cleaner public API\n__version__ = \"1.0.0\"\n",[23,487,488,493,508],{"__ignoreMap":36},[40,489,490],{"class":42,"line":43},[40,491,492],{"class":46},"# myapp\u002F__init__.py\n",[40,494,495,497,500,502,505],{"class":42,"line":50},[40,496,170],{"class":53},[40,498,499],{"class":61}," .models ",[40,501,114],{"class":53},[40,503,504],{"class":61}," User          ",[40,506,507],{"class":46},"# re-export for a cleaner public API\n",[40,509,510,513,515],{"class":42,"line":65},[40,511,512],{"class":90},"__version__",[40,514,94],{"class":53},[40,516,517],{"class":336}," \"1.0.0\"\n",[28,519,520],{"language":30},[32,521,523],{"className":34,"code":522,"language":30,"meta":36,"style":36},"# usage from outside the package\nfrom myapp import User             # works because __init__.py re-exported it\nfrom myapp.utils.validation import is_valid_email\nimport myapp\nprint(myapp.__version__)             # \"1.0.0\"\n",[23,524,525,530,545,557,564],{"__ignoreMap":36},[40,526,527],{"class":42,"line":43},[40,528,529],{"class":46},"# usage from outside the package\n",[40,531,532,534,537,539,542],{"class":42,"line":50},[40,533,170],{"class":53},[40,535,536],{"class":61}," myapp ",[40,538,114],{"class":53},[40,540,541],{"class":61}," User             ",[40,543,544],{"class":46},"# works because __init__.py re-exported it\n",[40,546,547,549,552,554],{"class":42,"line":65},[40,548,170],{"class":53},[40,550,551],{"class":61}," myapp.utils.validation ",[40,553,114],{"class":53},[40,555,556],{"class":61}," is_valid_email\n",[40,558,559,561],{"class":42,"line":80},[40,560,114],{"class":53},[40,562,563],{"class":61}," myapp\n",[40,565,566,568,571,573,576],{"class":42,"line":87},[40,567,126],{"class":90},[40,569,570],{"class":61},"(myapp.",[40,572,512],{"class":90},[40,574,575],{"class":61},")             ",[40,577,578],{"class":46},"# \"1.0.0\"\n",[19,580,581,583,584,586],{},[23,582,435],{}," runs once, the first time any part of the package is imported — it's the natural place to define a curated public API (via re-exports) and package-level metadata like ",[23,585,512],{},", hiding internal module structure from consumers who shouldn't need to know it.",[14,588,590],{"id":589},"absolute-vs-relative-imports","Absolute vs Relative Imports",[28,592,593],{"language":30},[32,594,596],{"className":34,"code":595,"language":30,"meta":36,"style":36},"# myapp\u002Futils\u002Fformatting.py\n\n# Absolute import — spells out the full path from the top-level package; unambiguous, preferred\nfrom myapp.utils.validation import is_valid_email\n\n# Relative import — relative to the CURRENT module's position in the package\nfrom . import validation          # \".\" = same directory (myapp\u002Futils\u002F)\nfrom .validation import is_valid_email\nfrom .. import models               # \"..\" = one level up (myapp\u002F)\n",[23,597,598,603,607,612,622,626,631,646,657],{"__ignoreMap":36},[40,599,600],{"class":42,"line":43},[40,601,602],{"class":46},"# myapp\u002Futils\u002Fformatting.py\n",[40,604,605],{"class":42,"line":50},[40,606,84],{"emptyLinePlaceholder":83},[40,608,609],{"class":42,"line":65},[40,610,611],{"class":46},"# Absolute import — spells out the full path from the top-level package; unambiguous, preferred\n",[40,613,614,616,618,620],{"class":42,"line":80},[40,615,170],{"class":53},[40,617,551],{"class":61},[40,619,114],{"class":53},[40,621,556],{"class":61},[40,623,624],{"class":42,"line":87},[40,625,84],{"emptyLinePlaceholder":83},[40,627,628],{"class":42,"line":162},[40,629,630],{"class":46},"# Relative import — relative to the CURRENT module's position in the package\n",[40,632,633,635,638,640,643],{"class":42,"line":167},[40,634,170],{"class":53},[40,636,637],{"class":61}," . ",[40,639,114],{"class":53},[40,641,642],{"class":61}," validation          ",[40,644,645],{"class":46},"# \".\" = same directory (myapp\u002Futils\u002F)\n",[40,647,648,650,653,655],{"class":42,"line":186},[40,649,170],{"class":53},[40,651,652],{"class":61}," .validation ",[40,654,114],{"class":53},[40,656,556],{"class":61},[40,658,659,661,664,666,669],{"class":42,"line":207},[40,660,170],{"class":53},[40,662,663],{"class":61}," .. ",[40,665,114],{"class":53},[40,667,668],{"class":61}," models               ",[40,670,671],{"class":46},"# \"..\" = one level up (myapp\u002F)\n",[19,673,674,677],{},[377,675,676],{},"Best practice"," (PEP 8): prefer absolute imports for clarity — they remain correct even if a module is moved elsewhere within the package, and they make the source of every imported name immediately obvious when reading the file in isolation. Relative imports are more common in tightly-coupled internal package code, where hardcoding the full package name in every file would be brittle if the package itself gets renamed.",[14,679,681],{"id":680},"circular-imports-why-they-happen-and-how-to-fix-them","Circular Imports — Why They Happen and How to Fix Them",[28,683,684],{"language":30},[32,685,687],{"className":34,"code":686,"language":30,"meta":36,"style":36},"# a.py\nfrom b import func_b\n\ndef func_a():\n    return func_b() + 1\n",[23,688,689,694,706,710,719],{"__ignoreMap":36},[40,690,691],{"class":42,"line":43},[40,692,693],{"class":46},"# a.py\n",[40,695,696,698,701,703],{"class":42,"line":50},[40,697,170],{"class":53},[40,699,700],{"class":61}," b ",[40,702,114],{"class":53},[40,704,705],{"class":61}," func_b\n",[40,707,708],{"class":42,"line":65},[40,709,84],{"emptyLinePlaceholder":83},[40,711,712,714,717],{"class":42,"line":80},[40,713,54],{"class":53},[40,715,716],{"class":57}," func_a",[40,718,302],{"class":61},[40,720,721,723,726,728],{"class":42,"line":87},[40,722,68],{"class":53},[40,724,725],{"class":61}," func_b() ",[40,727,74],{"class":53},[40,729,730],{"class":90}," 1\n",[28,732,733],{"language":30},[32,734,736],{"className":34,"code":735,"language":30,"meta":36,"style":36},"# b.py\nfrom a import func_a    # circular! a imports b, b imports a\n\ndef func_b():\n    return 1\n\ndef func_c():\n    return func_a() + 1\n",[23,737,738,743,757,761,770,776,780,789],{"__ignoreMap":36},[40,739,740],{"class":42,"line":43},[40,741,742],{"class":46},"# b.py\n",[40,744,745,747,749,751,754],{"class":42,"line":50},[40,746,170],{"class":53},[40,748,71],{"class":61},[40,750,114],{"class":53},[40,752,753],{"class":61}," func_a    ",[40,755,756],{"class":46},"# circular! a imports b, b imports a\n",[40,758,759],{"class":42,"line":65},[40,760,84],{"emptyLinePlaceholder":83},[40,762,763,765,768],{"class":42,"line":80},[40,764,54],{"class":53},[40,766,767],{"class":57}," func_b",[40,769,302],{"class":61},[40,771,772,774],{"class":42,"line":87},[40,773,68],{"class":53},[40,775,730],{"class":90},[40,777,778],{"class":42,"line":162},[40,779,84],{"emptyLinePlaceholder":83},[40,781,782,784,787],{"class":42,"line":167},[40,783,54],{"class":53},[40,785,786],{"class":57}," func_c",[40,788,302],{"class":61},[40,790,791,793,796,798],{"class":42,"line":186},[40,792,68],{"class":53},[40,794,795],{"class":61}," func_a() ",[40,797,74],{"class":53},[40,799,730],{"class":90},[28,801,802],{"language":30},[32,803,805],{"className":34,"code":804,"language":30,"meta":36,"style":36},"import a\n# ImportError: cannot import name 'func_a' from partially initialized module 'a'\n# (most likely due to a circular import)\n",[23,806,807,814,819],{"__ignoreMap":36},[40,808,809,811],{"class":42,"line":43},[40,810,114],{"class":53},[40,812,813],{"class":61}," a\n",[40,815,816],{"class":42,"line":50},[40,817,818],{"class":46},"# ImportError: cannot import name 'func_a' from partially initialized module 'a'\n",[40,820,821],{"class":42,"line":65},[40,822,823],{"class":46},"# (most likely due to a circular import)\n",[19,825,826,827,830,831,834,835,838,839,841,842,845,846,849,850,852,853,856,857,859],{},"When ",[23,828,829],{},"a.py"," is imported, Python starts executing it top-to-bottom; its first line tries to import ",[23,832,833],{},"b",", so Python starts executing ",[23,836,837],{},"b.py","; ",[23,840,837],{},"'s first line tries to import ",[23,843,844],{},"func_a"," from ",[23,847,848],{},"a"," — but ",[23,851,848],{}," is still mid-import (its module object exists in ",[23,854,855],{},"sys.modules",", but execution hasn't reached the point of defining ",[23,858,844],{}," yet), so the name isn't there yet, and the import fails.",[861,862,864],"h3",{"id":863},"fix-1-import-the-module-not-the-name-and-defer-attribute-access","Fix 1: import the module, not the name, and defer attribute access",[28,866,867],{"language":30},[32,868,870],{"className":34,"code":869,"language":30,"meta":36,"style":36},"# b.py\nimport a                # imports the MODULE object, doesn't need func_a to exist YET\n\ndef func_c():\n    return a.func_a() + 1   # func_a is looked up at CALL time, by which point a is fully loaded\n",[23,871,872,876,886,890,898],{"__ignoreMap":36},[40,873,874],{"class":42,"line":43},[40,875,742],{"class":46},[40,877,878,880,883],{"class":42,"line":50},[40,879,114],{"class":53},[40,881,882],{"class":61}," a                ",[40,884,885],{"class":46},"# imports the MODULE object, doesn't need func_a to exist YET\n",[40,887,888],{"class":42,"line":65},[40,889,84],{"emptyLinePlaceholder":83},[40,891,892,894,896],{"class":42,"line":80},[40,893,54],{"class":53},[40,895,786],{"class":57},[40,897,302],{"class":61},[40,899,900,902,905,907,910],{"class":42,"line":87},[40,901,68],{"class":53},[40,903,904],{"class":61}," a.func_a() ",[40,906,74],{"class":53},[40,908,909],{"class":90}," 1",[40,911,912],{"class":46},"   # func_a is looked up at CALL time, by which point a is fully loaded\n",[861,914,916],{"id":915},"fix-2-move-the-import-inside-the-function-local-import","Fix 2: move the import inside the function (local import)",[28,918,919],{"language":30},[32,920,922],{"className":34,"code":921,"language":30,"meta":36,"style":36},"# b.py\ndef func_c():\n    from a import func_a    # deferred until func_c is actually CALLED, long after both modules finished loading\n    return func_a() + 1\n",[23,923,924,928,936,950],{"__ignoreMap":36},[40,925,926],{"class":42,"line":43},[40,927,742],{"class":46},[40,929,930,932,934],{"class":42,"line":50},[40,931,54],{"class":53},[40,933,786],{"class":57},[40,935,302],{"class":61},[40,937,938,941,943,945,947],{"class":42,"line":65},[40,939,940],{"class":53},"    from",[40,942,71],{"class":61},[40,944,114],{"class":53},[40,946,753],{"class":61},[40,948,949],{"class":46},"# deferred until func_c is actually CALLED, long after both modules finished loading\n",[40,951,952,954,956,958],{"class":42,"line":80},[40,953,68],{"class":53},[40,955,795],{"class":61},[40,957,74],{"class":53},[40,959,730],{"class":90},[861,961,963],{"id":962},"fix-3-restructure-the-real-fix","Fix 3: restructure — the real fix",[19,965,966,967,969,970,972],{},"Circular imports are usually a signal of a genuine design problem: two modules that are too tightly coupled. The most durable fix is extracting the shared logic both modules need into a third module that neither ",[23,968,848],{}," nor ",[23,971,833],{}," needs to import the other for.",[14,974,976,979,980],{"id":975},"__all__-controlling-from-module-import",[23,977,978],{},"__all__"," — Controlling ",[23,981,982],{},"from module import *",[28,984,985],{"language":30},[32,986,988],{"className":34,"code":987,"language":30,"meta":36,"style":36},"# strings_utils.py\n__all__ = [\"slugify\", \"truncate\"]     # explicitly whitelists what * imports\n\ndef slugify(text):\n    return text.lower().replace(\" \", \"-\")\n\ndef truncate(text, length):\n    return text[:length]\n\ndef _internal_helper():               # not in __all__ — excluded from *, even without leading underscore protection\n    pass\n",[23,989,990,995,1018,1022,1032,1050,1054,1064,1071,1075,1088],{"__ignoreMap":36},[40,991,992],{"class":42,"line":43},[40,993,994],{"class":46},"# strings_utils.py\n",[40,996,997,999,1001,1004,1007,1009,1012,1015],{"class":42,"line":50},[40,998,978],{"class":90},[40,1000,94],{"class":53},[40,1002,1003],{"class":61}," [",[40,1005,1006],{"class":336},"\"slugify\"",[40,1008,135],{"class":61},[40,1010,1011],{"class":336},"\"truncate\"",[40,1013,1014],{"class":61},"]     ",[40,1016,1017],{"class":46},"# explicitly whitelists what * imports\n",[40,1019,1020],{"class":42,"line":65},[40,1021,84],{"emptyLinePlaceholder":83},[40,1023,1024,1026,1029],{"class":42,"line":80},[40,1025,54],{"class":53},[40,1027,1028],{"class":57}," slugify",[40,1030,1031],{"class":61},"(text):\n",[40,1033,1034,1036,1039,1042,1044,1047],{"class":42,"line":87},[40,1035,68],{"class":53},[40,1037,1038],{"class":61}," text.lower().replace(",[40,1040,1041],{"class":336},"\" \"",[40,1043,135],{"class":61},[40,1045,1046],{"class":336},"\"-\"",[40,1048,1049],{"class":61},")\n",[40,1051,1052],{"class":42,"line":162},[40,1053,84],{"emptyLinePlaceholder":83},[40,1055,1056,1058,1061],{"class":42,"line":167},[40,1057,54],{"class":53},[40,1059,1060],{"class":57}," truncate",[40,1062,1063],{"class":61},"(text, length):\n",[40,1065,1066,1068],{"class":42,"line":186},[40,1067,68],{"class":53},[40,1069,1070],{"class":61}," text[:length]\n",[40,1072,1073],{"class":42,"line":207},[40,1074,84],{"emptyLinePlaceholder":83},[40,1076,1077,1079,1082,1085],{"class":42,"line":212},[40,1078,54],{"class":53},[40,1080,1081],{"class":57}," _internal_helper",[40,1083,1084],{"class":61},"():               ",[40,1086,1087],{"class":46},"# not in __all__ — excluded from *, even without leading underscore protection\n",[40,1089,1090],{"class":42,"line":233},[40,1091,1092],{"class":53},"    pass\n",[28,1094,1095],{"language":30},[32,1096,1098],{"className":34,"code":1097,"language":30,"meta":36,"style":36},"from strings_utils import *\nprint(slugify(\"Hello World\"))   # \"hello-world\" — works\n# _internal_helper()             # NameError — not exported by *, though still directly importable by name\n",[23,1099,1100,1112,1127],{"__ignoreMap":36},[40,1101,1102,1104,1107,1109],{"class":42,"line":43},[40,1103,170],{"class":53},[40,1105,1106],{"class":61}," strings_utils ",[40,1108,114],{"class":53},[40,1110,1111],{"class":53}," *\n",[40,1113,1114,1116,1119,1122,1124],{"class":42,"line":50},[40,1115,126],{"class":90},[40,1117,1118],{"class":61},"(slugify(",[40,1120,1121],{"class":336},"\"Hello World\"",[40,1123,141],{"class":61},[40,1125,1126],{"class":46},"# \"hello-world\" — works\n",[40,1128,1129],{"class":42,"line":65},[40,1130,1131],{"class":46},"# _internal_helper()             # NameError — not exported by *, though still directly importable by name\n",[19,1133,1134,1136,1137,1139,1140,1142,1143,1145],{},[377,1135,676],{},": avoid ",[23,1138,982],{}," in production code regardless of ",[23,1141,978],{}," — it makes it impossible to tell, just by reading a file, where a given name came from, which defeats a large part of what makes Python code easy to trace and refactor. ",[23,1144,978],{}," is still worth setting on public library modules, since it also affects what tools like Sphinx\u002FIDEs consider \"public API.\"",[14,1147,1149,1150,1153,1154],{"id":1148},"the-import-system-syspath-and-sysmodules","The Import System: ",[23,1151,1152],{},"sys.path"," and ",[23,1155,855],{},[28,1157,1158],{"language":30},[32,1159,1161],{"className":34,"code":1160,"language":30,"meta":36,"style":36},"import sys\nprint(sys.path)         # list of directories Python searches, in order, for modules to import\nprint(sys.modules.keys())   # every module already imported this process — a CACHE\n\nimport math_utils\nimport math_utils          # second import does NOT re-run the file — returns the cached module object\nprint(sys.modules[\"math_utils\"] is math_utils)   # True\n",[23,1162,1163,1170,1180,1190,1194,1200,1210],{"__ignoreMap":36},[40,1164,1165,1167],{"class":42,"line":43},[40,1166,114],{"class":53},[40,1168,1169],{"class":61}," sys\n",[40,1171,1172,1174,1177],{"class":42,"line":50},[40,1173,126],{"class":90},[40,1175,1176],{"class":61},"(sys.path)         ",[40,1178,1179],{"class":46},"# list of directories Python searches, in order, for modules to import\n",[40,1181,1182,1184,1187],{"class":42,"line":65},[40,1183,126],{"class":90},[40,1185,1186],{"class":61},"(sys.modules.keys())   ",[40,1188,1189],{"class":46},"# every module already imported this process — a CACHE\n",[40,1191,1192],{"class":42,"line":80},[40,1193,84],{"emptyLinePlaceholder":83},[40,1195,1196,1198],{"class":42,"line":87},[40,1197,114],{"class":53},[40,1199,117],{"class":61},[40,1201,1202,1204,1207],{"class":42,"line":162},[40,1203,114],{"class":53},[40,1205,1206],{"class":61}," math_utils          ",[40,1208,1209],{"class":46},"# second import does NOT re-run the file — returns the cached module object\n",[40,1211,1212,1214,1217,1220,1223,1226,1229],{"class":42,"line":167},[40,1213,126],{"class":90},[40,1215,1216],{"class":61},"(sys.modules[",[40,1218,1219],{"class":336},"\"math_utils\"",[40,1221,1222],{"class":61},"] ",[40,1224,1225],{"class":53},"is",[40,1227,1228],{"class":61}," math_utils)   ",[40,1230,1231],{"class":46},"# True\n",[19,1233,1234,1235,1237,1238,1241],{},"Because ",[23,1236,855],{}," caches by name, importing the same module twice (even from different places in a codebase) always yields the ",[365,1239,1240],{},"same"," module object — any mutable state a module defines at the top level is genuinely shared and can be mutated by one importer and observed by another, a pattern sometimes used deliberately for singletons, and sometimes a source of surprising coupling when done accidentally.",[861,1243,1245],{"id":1244},"reloading-a-module-rare-mostly-for-interactive-use","Reloading a module (rare, mostly for interactive use)",[28,1247,1248],{"language":30},[32,1249,1251],{"className":34,"code":1250,"language":30,"meta":36,"style":36},"import importlib\nimport math_utils\nimportlib.reload(math_utils)   # re-executes the module's top-level code, useful in long-running REPLs\u002Fnotebooks\n",[23,1252,1253,1260,1266],{"__ignoreMap":36},[40,1254,1255,1257],{"class":42,"line":43},[40,1256,114],{"class":53},[40,1258,1259],{"class":61}," importlib\n",[40,1261,1262,1264],{"class":42,"line":50},[40,1263,114],{"class":53},[40,1265,117],{"class":61},[40,1267,1268,1271],{"class":42,"line":65},[40,1269,1270],{"class":61},"importlib.reload(math_utils)   ",[40,1272,1273],{"class":46},"# re-executes the module's top-level code, useful in long-running REPLs\u002Fnotebooks\n",[14,1275,1277,1280],{"id":1276},"pyprojecttoml-and-package-discovery-brief-preview",[23,1278,1279],{},"pyproject.toml"," and Package Discovery (Brief Preview)",[19,1282,1283],{},"Modern Python packaging (fully covered in chapter 25) declares a package's structure declaratively:",[28,1285,1287],{"language":1286},"ini",[32,1288,1292],{"className":1289,"code":1290,"language":1291,"meta":36,"style":36},"language-toml shiki shiki-themes github-light github-dark","[project]\nname = \"myapp\"\nversion = \"1.0.0\"\n\n[tool.setuptools.packages.find]\nwhere = [\"src\"]\n","toml",[23,1293,1294,1305,1313,1321,1325,1350],{"__ignoreMap":36},[40,1295,1296,1299,1302],{"class":42,"line":43},[40,1297,1298],{"class":61},"[",[40,1300,1301],{"class":57},"project",[40,1303,1304],{"class":61},"]\n",[40,1306,1307,1310],{"class":42,"line":50},[40,1308,1309],{"class":61},"name = ",[40,1311,1312],{"class":336},"\"myapp\"\n",[40,1314,1315,1318],{"class":42,"line":65},[40,1316,1317],{"class":61},"version = ",[40,1319,1320],{"class":336},"\"1.0.0\"\n",[40,1322,1323],{"class":42,"line":80},[40,1324,84],{"emptyLinePlaceholder":83},[40,1326,1327,1329,1332,1335,1338,1340,1343,1345,1348],{"class":42,"line":87},[40,1328,1298],{"class":61},[40,1330,1331],{"class":57},"tool",[40,1333,1334],{"class":61},".",[40,1336,1337],{"class":57},"setuptools",[40,1339,1334],{"class":61},[40,1341,1342],{"class":57},"packages",[40,1344,1334],{"class":61},[40,1346,1347],{"class":57},"find",[40,1349,1304],{"class":61},[40,1351,1352,1355,1358],{"class":42,"line":162},[40,1353,1354],{"class":61},"where = [",[40,1356,1357],{"class":336},"\"src\"",[40,1359,1304],{"class":61},[28,1361,1362],{"language":443},[32,1363,1365],{"className":441,"code":1364,"language":443,"meta":36,"style":36},"src\u002F\n    myapp\u002F\n        __init__.py\n        models.py\n",[23,1366,1367,1372,1377,1381],{"__ignoreMap":36},[40,1368,1369],{"class":42,"line":43},[40,1370,1371],{"class":57},"src\u002F\n",[40,1373,1374],{"class":42,"line":50},[40,1375,1376],{"class":57},"    myapp\u002F\n",[40,1378,1379],{"class":42,"line":65},[40,1380,470],{"class":57},[40,1382,1383],{"class":42,"line":80},[40,1384,1385],{"class":57},"        models.py\n",[19,1387,1388,1389,1392],{},"The ",[23,1390,1391],{},"src\u002F"," layout (package code nested one level deeper than the project root) is increasingly the recommended convention — it prevents accidentally importing the package from the working directory instead of the properly-installed version, a subtle bug that a flat layout (package directory directly at the project root) is prone to.",[14,1394,1396,1397,1399],{"id":1395},"namespace-packages-no-__init__py-required","Namespace Packages (No ",[23,1398,435],{}," Required)",[28,1401,1402],{"language":30},[32,1403,1405],{"className":34,"code":1404,"language":30,"meta":36,"style":36},"# Since Python 3.3, a directory WITHOUT __init__.py can still be a \"namespace package\" —\n# used for splitting a single logical package's code across multiple distributions.\n# For almost all ordinary projects, still include __init__.py explicitly —\n# it's clearer, and required for re-exports and package-level code to run at all.\n",[23,1406,1407,1412,1417,1422],{"__ignoreMap":36},[40,1408,1409],{"class":42,"line":43},[40,1410,1411],{"class":46},"# Since Python 3.3, a directory WITHOUT __init__.py can still be a \"namespace package\" —\n",[40,1413,1414],{"class":42,"line":50},[40,1415,1416],{"class":46},"# used for splitting a single logical package's code across multiple distributions.\n",[40,1418,1419],{"class":42,"line":65},[40,1420,1421],{"class":46},"# For almost all ordinary projects, still include __init__.py explicitly —\n",[40,1423,1424],{"class":42,"line":80},[40,1425,1426],{"class":46},"# it's clearer, and required for re-exports and package-level code to run at all.\n",[14,1428,1430],{"id":1429},"tips-tricks","💡 Tips & Tricks",[1432,1433,1434,1447,1461,1466,1478],"ul",{},[1435,1436,1437,1440,1441,1443,1444,1446],"li",{},[377,1438,1439],{},"Idiom",": keep ",[23,1442,435],{}," files thin — a handful of re-exports and ",[23,1445,512],{},", not business logic — so that importing the top-level package doesn't accidentally trigger expensive work (database connections, network calls) as a side effect of merely importing something from it.",[1435,1448,1449,1452,1453,1456,1457,1460],{},[377,1450,1451],{},"Debug",": ",[23,1454,1455],{},"python -c \"import module_name; print(module_name.__file__)\""," instantly tells you ",[365,1458,1459],{},"which"," file on disk a given import actually resolved to — invaluable when multiple installed versions or a stray local file might be shadowing what you expect.",[1435,1462,1463,1465],{},[377,1464,1439],{},": local (function-level) imports are a legitimate, common fix for circular imports — but overusing them for imports that don't need to be deferred (as a habit rather than a fix) hides a module's real dependencies from readers scanning the top of the file.",[1435,1467,1468,1452,1470,1473,1474,1477],{},[377,1469,1451],{},[23,1471,1472],{},"sys.path.insert(0, \"...\")"," at the top of a script is a common quick hack to make an ad-hoc script find a package — but for real projects, an editable install (",[23,1475,1476],{},"pip install -e .",", chapter 25) is the durable fix, since path hacks are fragile and don't travel with the code.",[1435,1479,1480,1452,1482,1484,1485,1488],{},[377,1481,1439],{},[23,1483,978],{}," doubles as living documentation of a module's public surface — even projects that never use ",[23,1486,1487],{},"from x import *"," benefit from setting it, since IDEs and autocomplete tools respect it too.",[14,1490,1492],{"id":1491},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[1432,1494,1495,1504,1514,1532,1552],{},[1435,1496,1497,1503],{},[377,1498,1499,1500,1502],{},"A module's top-level code runs exactly once per process, the first time it's imported anywhere — later imports return the cached object from ",[23,1501,855],{}," without re-running anything",", including any print statements, network calls, or global mutable state initialization at the top level.",[1435,1505,1506,1513],{},[377,1507,1508,1509,1512],{},"Circular imports fail with a confusing ",[23,1510,1511],{},"ImportError"," about a \"partially initialized module,\" not an obviously-named \"circular import\" error"," — recognizing this specific message is the fast path to diagnosing the real cause.",[1435,1515,1516,1527,1528,1531],{},[377,1517,1518,1519,1522,1523,1526],{},"A local file that happens to share a name with a standard-library or installed package (e.g., a project's own ",[23,1520,1521],{},"random.py"," or ",[23,1524,1525],{},"json.py",") silently shadows the real one for any import inside that directory"," — this produces baffling ",[23,1529,1530],{},"AttributeError","s on functions that definitely exist in the \"real\" module, because Python is actually importing your file instead.",[1435,1533,1534,1541,1542,1544,1545,1548,1549,1551],{},[377,1535,1536,1538,1539],{},[23,1537,982],{}," silently skips any name starting with an underscore UNLESS it's explicitly listed in ",[23,1540,978],{}," — and if ",[23,1543,978],{}," is defined, ",[23,1546,1547],{},"*"," imports ONLY the names in it, even ones without a leading underscore, meaning ",[23,1550,978],{},"'s presence fully overrides the \"no leading underscore\" default rule rather than adding to it.",[1435,1553,1554,1568,1569,1571,1572,1574],{},[377,1555,1556,1557,1560,1561,1564,1565],{},"Relative imports (",[23,1558,1559],{},"from . import x",") only work inside a package being imported as a package — running a file directly with ",[23,1562,1563],{},"python somefile.py"," when it contains relative imports raises ",[23,1566,1567],{},"ImportError: attempted relative import with no known parent package",", since the file's ",[23,1570,351],{}," is ",[23,1573,362],{}," with no package context at all in that mode.",[14,1576,1578],{"id":1577},"spot-the-bug","🧠 Spot the Bug",[19,1580,1581,1582,1585],{},"A small project has a ",[23,1583,1584],{},"utils.py"," inside its package that shadows a name the developer didn't expect. Find the issue.",[28,1587,1588],{"language":30},[32,1589,1591],{"className":34,"code":1590,"language":30,"meta":36,"style":36},"# project structure:\n# myapp\u002F\n#     __init__.py\n#     queue.py\n#     worker.py\n\n# myapp\u002Fqueue.py\nimport queue    # intends to import the STANDARD LIBRARY queue module\n\nclass TaskQueue:\n    def __init__(self):\n        self.q = queue.Queue()\n",[23,1592,1593,1598,1603,1608,1613,1618,1622,1627,1637,1641,1651,1662],{"__ignoreMap":36},[40,1594,1595],{"class":42,"line":43},[40,1596,1597],{"class":46},"# project structure:\n",[40,1599,1600],{"class":42,"line":50},[40,1601,1602],{"class":46},"# myapp\u002F\n",[40,1604,1605],{"class":42,"line":65},[40,1606,1607],{"class":46},"#     __init__.py\n",[40,1609,1610],{"class":42,"line":80},[40,1611,1612],{"class":46},"#     queue.py\n",[40,1614,1615],{"class":42,"line":87},[40,1616,1617],{"class":46},"#     worker.py\n",[40,1619,1620],{"class":42,"line":162},[40,1621,84],{"emptyLinePlaceholder":83},[40,1623,1624],{"class":42,"line":167},[40,1625,1626],{"class":46},"# myapp\u002Fqueue.py\n",[40,1628,1629,1631,1634],{"class":42,"line":186},[40,1630,114],{"class":53},[40,1632,1633],{"class":61}," queue    ",[40,1635,1636],{"class":46},"# intends to import the STANDARD LIBRARY queue module\n",[40,1638,1639],{"class":42,"line":207},[40,1640,84],{"emptyLinePlaceholder":83},[40,1642,1643,1646,1649],{"class":42,"line":212},[40,1644,1645],{"class":53},"class",[40,1647,1648],{"class":57}," TaskQueue",[40,1650,340],{"class":61},[40,1652,1653,1656,1659],{"class":42,"line":233},[40,1654,1655],{"class":53},"    def",[40,1657,1658],{"class":90}," __init__",[40,1660,1661],{"class":61},"(self):\n",[40,1663,1665,1668,1671,1674],{"class":42,"line":1664},12,[40,1666,1667],{"class":90},"        self",[40,1669,1670],{"class":61},".q ",[40,1672,1673],{"class":53},"=",[40,1675,1676],{"class":61}," queue.Queue()\n",[1678,1679,1680,1684,1726,1729,1781,1790],"details",{},[1681,1682,1683],"summary",{},"Answer",[19,1685,1686,1689,1690,1693,1694,1697,1698,1701,1702,1704,1705,1707,1708,1710,1711,1714,1715,1717,1718,1721,1722,1725],{},[23,1687,1688],{},"import queue"," inside ",[23,1691,1692],{},"myapp\u002Fqueue.py"," imports ",[377,1695,1696],{},"itself",", not the standard library ",[23,1699,1700],{},"queue"," module — because the current package's directory is searched (as part of how Python resolves absolute imports inside a package in some configurations, and definitively so for any implicit relative-import-like resolution) and ",[23,1703,1692],{}," matches the name ",[23,1706,1700],{}," before the interpreter reaches the standard library entry on ",[23,1709,1152],{},". This typically manifests as ",[23,1712,1713],{},"AttributeError: module 'queue' has no attribute 'Queue'"," — because ",[23,1716,1700],{}," resolved to the local file (which has no ",[23,1719,1720],{},"Queue"," class), not ",[23,1723,1724],{},"queue.Queue"," from the standard library, even though the error message doesn't say anything about \"wrong module\" directly.",[19,1727,1728],{},"The fix is to never name a module the same as a standard-library or widely-used third-party module — rename the local file:",[28,1730,1731],{"language":30},[32,1732,1734],{"className":34,"code":1733,"language":30,"meta":36,"style":36},"# myapp\u002Ftask_queue.py\nimport queue   # now unambiguously the standard library\n\nclass TaskQueue:\n    def __init__(self):\n        self.q = queue.Queue()\n",[23,1735,1736,1741,1751,1755,1763,1771],{"__ignoreMap":36},[40,1737,1738],{"class":42,"line":43},[40,1739,1740],{"class":46},"# myapp\u002Ftask_queue.py\n",[40,1742,1743,1745,1748],{"class":42,"line":50},[40,1744,114],{"class":53},[40,1746,1747],{"class":61}," queue   ",[40,1749,1750],{"class":46},"# now unambiguously the standard library\n",[40,1752,1753],{"class":42,"line":65},[40,1754,84],{"emptyLinePlaceholder":83},[40,1756,1757,1759,1761],{"class":42,"line":80},[40,1758,1645],{"class":53},[40,1760,1648],{"class":57},[40,1762,340],{"class":61},[40,1764,1765,1767,1769],{"class":42,"line":87},[40,1766,1655],{"class":53},[40,1768,1658],{"class":90},[40,1770,1661],{"class":61},[40,1772,1773,1775,1777,1779],{"class":42,"line":162},[40,1774,1667],{"class":90},[40,1776,1670],{"class":61},[40,1778,1673],{"class":53},[40,1780,1676],{"class":61},[19,1782,1783,1784,1786,1787,1789],{},"If renaming isn't immediately possible, Python 3's absolute-import-by-default behavior (PEP 328) makes this specific collision less common than it was in Python 2, but it still occurs, particularly with ",[23,1785,435],{},"-relative resolution quirks and tooling that manipulates ",[23,1788,1152],{}," — the safest fix is always avoiding the name collision outright.",[19,1791,1792,1795,1796,135,1798,135,1801,135,1804,135,1807,135,1810,1813,1814,1816],{},[377,1793,1794],{},"The lesson",": never name a project module identically to a standard-library module (",[23,1797,1700],{},[23,1799,1800],{},"json",[23,1802,1803],{},"types",[23,1805,1806],{},"email",[23,1808,1809],{},"string",[23,1811,1812],{},"random"," are common real-world collisions) — the failure mode is a confusing ",[23,1815,1530],{}," deep inside code that looks completely correct, not an obvious import error pointing at the real cause.",[14,1818,1820],{"id":1819},"key-takeaways","Key Takeaways",[1432,1822,1823,1831,1837,1843,1849,1861],{},[1435,1824,1825,1826,838,1828,1830],{},"A module's top-level code executes exactly once per process, cached in ",[23,1827,855],{},[23,1829,258],{}," lets a file work both as an importable library and a standalone script.",[1435,1832,1833,1834,1836],{},"Packages are directories with ",[23,1835,435],{},"; keep that file thin (re-exports and metadata) to avoid surprising side effects on import.",[1435,1838,1839,1840,1842],{},"Prefer absolute imports for clarity; relative imports (",[23,1841,1559],{},") are common inside tightly-coupled package-internal code but fail when the file is run directly rather than imported as part of a package.",[1435,1844,1845,1846,1848],{},"Circular imports produce a distinctive \"partially initialized module\" ",[23,1847,1511],{}," — fix by importing the module (not specific names) and deferring attribute access, moving the import inside a function, or restructuring shared logic into a third module.",[1435,1850,1851,1853,1854,1856,1857,1860],{},[23,1852,978],{}," controls what ",[23,1855,982],{}," exports and doubles as documentation of a module's public surface — but avoid ",[23,1858,1859],{},"import *"," in real code regardless, since it obscures where names came from.",[1435,1862,1863,1864,1866],{},"Never name a local module the same as a standard-library module — it silently shadows the real one for any import inside that directory, producing confusing ",[23,1865,1530],{},"s far from the actual cause.",[1868,1869,1870],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}",{"title":36,"searchDepth":50,"depth":50,"links":1872},[1873,1874,1875,1876,1877,1882,1884,1888,1890,1892,1893,1894,1895],{"id":16,"depth":50,"text":17},{"id":255,"depth":50,"text":258},{"id":424,"depth":50,"text":425},{"id":589,"depth":50,"text":590},{"id":680,"depth":50,"text":681,"children":1878},[1879,1880,1881],{"id":863,"depth":65,"text":864},{"id":915,"depth":65,"text":916},{"id":962,"depth":65,"text":963},{"id":975,"depth":50,"text":1883},"__all__ — Controlling from module import *",{"id":1148,"depth":50,"text":1885,"children":1886},"The Import System: sys.path and sys.modules",[1887],{"id":1244,"depth":65,"text":1245},{"id":1276,"depth":50,"text":1889},"pyproject.toml and Package Discovery (Brief Preview)",{"id":1395,"depth":50,"text":1891},"Namespace Packages (No __init__.py Required)",{"id":1429,"depth":50,"text":1430},{"id":1491,"depth":50,"text":1492},{"id":1577,"depth":50,"text":1578},{"id":1819,"depth":50,"text":1820},"md",{},"\u002Fpython\u002F17-modules-and-packages",{"title":5,"description":36},"python\u002F17-modules-and-packages","Cvn13yoBFdz6gc0s-16MDpUKu0JSayROPmuHovDuu9c",1789924651636]