#set document(title: "7.3 Top-level code", author: "OpenStax / XYZ Homework") #set page(width: 8.5in, height: auto, margin: 1in) #import "@preview/cetz:0.5.2" #set text(font: ("STIX Two Text", "Libertinus Serif", "New Computer Modern"), size: 10.5pt, lang: "en") #show math.equation: set text(font: ("STIX Two Math", "New Computer Modern Math")) #set par(justify: true, leading: 0.62em, spacing: 0.9em) #set enum(spacing: 1.1em) // room between list items so tall inline fractions don't collide #set list(spacing: 1.1em) #set table(stroke: 0.5pt + rgb("#c7ccd3")) #let BLUE = rgb("#183B6F") // brand navy — section bars + example/solution labels (white on navy 11.09:1) #let ORANGE = rgb("#A94509") // brand primary-700 — AA-safe deep orange for TEXT (5.93:1 on white; raw brand #F37021 is 2.94:1 and must never carry text) #let RED = rgb("#DC2626") // brand error-600 #let GREEN = rgb("#059669") // brand success-600 (decoration only; small green text uses green-text #007942) #show heading.where(level: 1): it => block(width: 100%, above: 0pt, below: 16pt, fill: gradient.linear(BLUE, rgb("#2C5AA0")), inset: (x: 14pt, y: 12pt), radius: 3pt, text(fill: white, weight: "bold", size: 19pt, it.body)) #show heading.where(level: 2): it => block(width: 100%, above: 18pt, below: 10pt, fill: BLUE, inset: (x: 10pt, y: 6pt), radius: 2pt, text(fill: white, weight: "bold", size: 12pt, it.body)) #show heading.where(level: 3): it => text(fill: ORANGE, weight: "bold", size: 12.5pt, it.body) #show heading.where(level: 4): it => text(fill: BLUE, weight: "bold", size: 10.5pt, it.body) #let examplebox(label, title, body) = block(width: 100%, breakable: true, fill: rgb("#EFF1F5"), stroke: 0.5pt + rgb("#CFDDF0"), radius: 4pt, inset: 10pt, above: 12pt, below: 12pt)[ #block(below: 6pt)[#box(fill: BLUE, inset: (x: 6pt, y: 2pt), radius: 2pt, text(fill: white, weight: "bold", size: 8.5pt, label)) #h(0.4em) #strong[#title]] #body] // rail = decorative left rule (raw brand token); labelcolor = AA-safe label text shade #let notebox(label, rail, labelcolor, tint, body) = block(width: 100%, breakable: true, fill: tint, stroke: (left: 3pt + rail), inset: (left: 10pt, rest: 8pt), radius: (right: 4pt), above: 11pt, below: 11pt)[ #text(fill: labelcolor, weight: "bold", size: 7.5pt, tracking: 0.5pt)[#upper(label)] #linebreak() #body] #let solutionbox(body) = block(above: 4pt, below: 8pt)[ #text(fill: BLUE, weight: "bold", size: 8.5pt)[Solution] #linebreak() #body] #let figph(msg) = block(width: 100%, height: 60pt, fill: rgb("#f6f7f9"), stroke: (paint: rgb("#c7ccd3"), dash: "dashed"), radius: 4pt, inset: 10pt)[ #align(center + horizon, text(fill: rgb("#889"), style: "italic", size: 9pt, msg))] // Standardize inlined figure sizes: measure the natural CeTZ canvas, then scale to a // consistent envelope (aspect-aware; see build_typst.py FIG_* constants). Unlike the // print preamble, dimensions are FLOORED: in an editor a user can trim a figure to a // degenerate 1-D shape (a bare line), and w/h or tw/w would then divide by zero. #let _STD_W = 3.5 #let _WIDE_W = 5.6 #let _MAX_H = 3.4 #let _ASPECT_WIDE = 2.2 #let _UPSCALE_MAX = 1.15 #let stdfig(body) = context { let m = measure(body) let w = calc.max(m.width / 1in, 0.01) let h = calc.max(m.height / 1in, 0.01) let tw = if w / h > _ASPECT_WIDE { _WIDE_W } else { _STD_W } let s = calc.min(tw / w, _MAX_H / h, _UPSCALE_MAX) align(center, box(scale(x: s * 100%, y: s * 100%, reflow: true, body))) } #show figure: set block(breakable: false) #set figure(gap: 8pt) #show figure.caption: set text(size: 8.5pt, fill: rgb("#555")) == 7.3#h(0.6em)Top-level code === Learning objectives By the end of this section you should be able to - Identify code that will run as a side effect of importing. - Explain the purpose of if \_\_name\_\_ == "\_\_main\_\_". === Side effects Modules define functions and constants to be used in other programs. When importing a module, #emph[all] code in the module is run from top to bottom. If a module is not designed carefully, unintended code might run as a side effect. The unintended code is generally at the top level, outside of function definitions. #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Sphere test code] #link("https://www.openstax.org/r/sphere-test")[Sphere test code; ch 7, video 4] ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Side effects] ] === Using \_\_name\_\_ Python modules often include the statement if \_\_name\_\_ == "\_\_main\_\_" to prevent side effects. This statement is true when the module is run as a program and false when the module is imported. #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[The main module] #link("https://www.openstax.org/r/main-module")[The main module; ch 7, video 5] ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Using \_\_name\_\_] ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Exploring further] Variables that begin and end with double underscores have special meaning in Python. Double underscores are informally called "dunder" or "magic" variables. Other examples include \_\_doc\_\_ (the module's docstring) and \_\_file\_\_ (the module's filename). ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Side effects] This exercise is a continuation of the "Missing imports" exercise. Previously, you added missing import statements to the top of the program. Now, modify the program to prevent side effects when importing the program as a module: + Add if \_\_name\_\_ == "\_\_main\_\_" at the end. + Move all test code under that if statement. The program should run without errors and produce the same output as before. from math import sqrt from area import circle def is\_prime(n): """Returns True if n is prime.""" if n \< 2: return False for i in range(2, int(sqrt(n)) + 1): if n % i == 0: return False return True \# Test the is\_prime function for n in range(10): if is\_prime(n): print(n, "is prime") else: print(n, "is NOT prime") def pizza\_rate(size, price): """Calculates the value of a pizza coupon. Args: size (int): Diameter of the pizza in inches. price (float): Advertised price of the pizza. Returns: float: The pizza's price per square inch. """ return price / circle(size / 2) \# Test the pizza\_rate function print() print(" Small for \$4.99:", pizza\_rate(10, 4.99)) print(" Medium for \$5.99:", pizza\_rate(12, 5.99)) print(" Large for \$7.99:", pizza\_rate(14, 7.99)) print("X-Large for \$9.99:", pizza\_rate(16, 9.99)) ] #notebox("Note", rgb("#8a94a6"), rgb("#556666"), rgb("#f7f8fa"))[ #emph[Conversion test] This exercise is a continuation of the "Conversion module" exercise. Previously, you wrote the functions cel2fah, fah2cel, km2mi, and mi2km. Write test code at the end of #emph[conversion.py] (the original file) for each of these functions. The test code must not run as a side effect when conversion is imported by other programs. When running #emph[conversion.py] as the main program, the test output should be: 0 C is 32 F 5 C is 41 F 10 C is 50 F 15 C is 59 F 20 C is 68 F 20 F is -7 C 25 F is -4 C 30 F is -1 C 35 F is 2 C 40 F is 4 C 1 km is 0.6 mi 2 km is 1.2 mi 3 km is 1.9 mi 4 km is 2.5 mi 5 km is 3.1 mi 5 mi is 8.0 km 6 mi is 9.7 km 7 mi is 11.3 km 8 mi is 12.9 km 9 mi is 14.5 km """Functions that convert metric and imperial units.""" def cel2fah(c): """Converts from Celsius to Fahrenheit.""" return 9/5 \* c + 32 def fah2cel(f): """Converts from Fahrenheit to Celsius.""" return 5/9 \* (f - 32) def km2mi(km): """Converts from kilometers to miles.""" return km / 1.60934 def mi2km(mi): """Converts from miles to kilometers.""" return mi \* 1.60934 ]