{"id":"own-modules-files","slug":"several-files","title":"A program of several files","text":"Any Python file is a module. Put some functions in a file of their own, and other files can import them exactly as they import `math`. As programs grow, splitting them into files by topic keeps each file short, and a module of useful functions can be reused in the next program too.\n\nOn this site, a program can have several files. The editor shows a tab for each one, and Python starts the program from `main.py`. Here the file `units.py` holds two conversion functions, and `main.py` imports it:\n\n```python\nimport units\n\nprint(f\"{units.km_to_miles(42.195):.1f} miles\")\nprint(f\"{units.celsius_to_fahrenheit(21):.1f} F\")\n# ==== units.py ====\ndef km_to_miles(km):\n    return km * 0.621371\n\n\ndef celsius_to_fahrenheit(celsius):\n    return celsius * 9 / 5 + 32\n```\n\n```output\n26.2 miles\n69.8 F\n```\n\nThe module's name is the file's name without `.py`: the file `units.py` is the module `units`. Python looks for it in the same folder as the program (on this site, all the files of a program are in the same folder), and then among the modules of the standard library.\n\nEverything you learned about importing works for your own modules too. The `from` form brings in chosen names:\n\n```python\nfrom units import km_to_miles\n\ndistance = float(input(\"Distance in km: \"))\nprint(f\"That is {km_to_miles(distance):.1f} miles\")\n# ==== units.py ====\ndef km_to_miles(km):\n    return km * 0.621371\n\n\ndef celsius_to_fahrenheit(celsius):\n    return celsius * 9 / 5 + 32\n```\n\n```input\n10\n```\n\n```output\nDistance in km: 10\nThat is 6.2 miles\n```\n\n### No .py in the import\n\nThe import names the module, not the file. With `.py`, Python reads the dot as a module inside a module, and can't find one:\n\n```python\nimport units.py\n\nprint(units.km_to_miles(5))\n# ==== units.py ====\ndef km_to_miles(km):\n    return km * 0.621371\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 1, in <module>\n    import units.py\nModuleNotFoundError: No module named 'units.py'; 'units' is not a package\n```\n\nOne more rule for naming your files: don't give a file the name of a standard module. A file called `random.py` next to your program would be imported instead of the real `random` module, and nothing random would work. This site doesn't allow such names, but on your own computer it's an easy mistake to make.\n","task":"`main.py` uses the functions in `shapes.py`, but it doesn't import the module, so it stops with a `NameError`. Add the import to `main.py` so the program prints:\n\n```\n20\n10.0\n```\n","kind":"code","seed":"# ==== main.py ====\nprint(shapes.rectangle_area(4, 5))\nprint(shapes.triangle_area(4, 5))\n\n# ==== shapes.py ====\ndef rectangle_area(width, height):\n    return width * height\n\n\ndef triangle_area(base, height):\n    return base * height / 2\n","solution":"# ==== main.py ====\nimport shapes\n\nprint(shapes.rectangle_area(4, 5))\nprint(shapes.triangle_area(4, 5))\n\n# ==== shapes.py ====\ndef rectangle_area(width, height):\n    return width * height\n\n\ndef triangle_area(base, height):\n    return base * height / 2\n","hints":["`main.py` refers to `shapes.rectangle_area`. Which name doesn't Python know, according to the error?","Add `import shapes` as the first line of `main.py`, without `.py`."],"tests":[{"name":"Output","stdin":"","expect":"20\n10.0","hidden":false}],"require":[{"pattern":"\\bimport\\s+shapes\\b|\\bfrom\\s+shapes\\s+import\\b","message":"Import the module `shapes` in `main.py`."}],"forbid":[],"more":[{"task":"`main.py` is ready, but the two functions in `money.py` are still empty. Write them:\n\n- `with_tax(price, percent)` returns the price with the tax added: a tax of 24 percent makes 10.0 into 12.4.\n- `round_up(amount)` returns the amount rounded up to a whole number, with `math.ceil`. A module can import other modules: put `import math` at the top of `money.py`.\n\nFor example:\n\n```\nPrice without tax: 10\nWith 24% tax: 12.40\nRounded up to whole euros: 13\n```\n","kind":"code","seed":"# ==== main.py ====\nimport money\n\nprice = float(input(\"Price without tax: \"))\ntotal = money.with_tax(price, 24)\nprint(f\"With 24% tax: {total:.2f}\")\nprint(f\"Rounded up to whole euros: {money.round_up(total)}\")\n\n# ==== money.py ====\ndef with_tax(price, percent):\n    pass\n\n\ndef round_up(amount):\n    pass\n","solution":"# ==== main.py ====\nimport money\n\nprice = float(input(\"Price without tax: \"))\ntotal = money.with_tax(price, 24)\nprint(f\"With 24% tax: {total:.2f}\")\nprint(f\"Rounded up to whole euros: {money.round_up(total)}\")\n\n# ==== money.py ====\nimport math\n\n\ndef with_tax(price, percent):\n    return price * (1 + percent / 100)\n\n\ndef round_up(amount):\n    return math.ceil(amount)\n","hints":["Adding 24 percent is multiplying by 1.24, which is `1 + percent / 100`.","`round_up` needs `math.ceil`, so `money.py` needs `import math` at its top. Imports in `main.py` don't reach into other files."],"tests":[{"name":"Test 1","stdin":"10\n","expect":"Price without tax: 10\nWith 24% tax: 12.40\nRounded up to whole euros: 13","hidden":false},{"name":"Test 2","stdin":"99.99\n","expect":"Price without tax: 99.99\nWith 24% tax: 123.99\nRounded up to whole euros: 124","hidden":true},{"name":"Test 3","stdin":"0.5\n","expect":"Price without tax: 0.5\nWith 24% tax: 0.62\nRounded up to whole euros: 1","hidden":true},{"name":"Test 4","stdin":"100\n","expect":"Price without tax: 100\nWith 24% tax: 124.00\nRounded up to whole euros: 124","hidden":true}],"require":[{"pattern":"math\\.ceil\\s*\\(|\\bceil\\s*\\(","message":"Round up with `math.ceil` in `money.py`."}],"forbid":[]},{"task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"# ==== main.py ====\nimport settings\nfrom settings import greeting\n\nprint(settings.language)\nprint(greeting + \", \" + settings.user)\n\n# ==== settings.py ====\nlanguage = \"Python\"\nuser = \"Ada\"\ngreeting = \"Hi\"\n","solution":"# ==== main.py ====\nimport settings\nfrom settings import greeting\n\nprint(settings.language)\nprint(greeting + \", \" + settings.user)\n\n# ==== settings.py ====\nlanguage = \"Python\"\nuser = \"Ada\"\ngreeting = \"Hi\"\n","hints":["A module can hold variables as well as functions, and they're imported the same way.","`settings.language` is the variable `language` of the module `settings`. `greeting` was brought in with `from`, so it needs no prefix."],"tests":[{"name":"Output","stdin":"","expect":"Python\nHi, Ada","hidden":false}],"require":[],"forbid":[],"lines":["Python","Hi, Ada"]}]}