Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Open In Colab Open In Kaggle

This notebook builds the smallest complete toolkit for handling environmental data in Python: variables, the core scalar types, arithmetic, casting, string formatting, and reading and writing text files.

We work throughout with one running example, a week of daily maximum air temperatures from the Jungfraujoch research station in the Swiss Alps, and finish by showing how a single type confusion can make generated code return the wrong answer without raising an error.

1.1.1 Variables and the Core Scalar Types

A variable binds a name to a value, and Python infers the value’s type, which determines what operations are allowed. Five scalar types cover almost everything a single measurement needs: int (whole counts) , float (real-valued measurements), str (text), bool (true/false flags), and None (a deliberate “no value”, useful for missing or not-yet-assigned information).

Our running example is the Jungfraujoch research station in the Swiss Alps (3571 m), one of the highest year-round weather stations in Europe. Let’s assume we have one week of daily maximum air temperatures from it. The number of readings is a whole count; each temperature is a decimal-point number.

7 <class 'int'>
-8.4 <class 'float'>

The station also has a name, each reading can carry a flag that is either true or false, and a quality field may have no value assigned to it yet.

Jungfraujoch <class 'str'>
True <class 'bool'>
None <class 'NoneType'>
Data TypePython IdentifierOperational Scope
IntegerintWhole numerical counts
Floating-PointfloatReal-valued measurements
StringstrTextual data
BooleanboolTrue/False logical flags
NoneTypeNoneDeliberate absence of value

1.1.2 Arithmetic, Comparison, and Casting

Arithmetic (+ - * / // % **) and comparison (< <= > >= == !=) operators behave as in mathematics, with two things to watch:

  1. / always returns a float even if the operands divide evenly;

  2. Operators are type-dependent: + adds numbers but concatenates strings.

Temperature in Kelvin: 264.75 K
Temperature in Fahrenheit: 16.88 F

Two of the seven days in our week fell strictly below -9.0 °C. / gives the fraction of the week that was that cold, and always returns a float:

Fraction of days below -9 C: 0.2857142857142857

// and % split a count into whole groups and a remainder. Over a longer record — the station’s full January, 31 days — they answer “how many complete weeks, and how many days left over?”:

Complete weeks: 4
Days left over: 3
False

Four operator families appear throughout this book, including the comparison operators you have just met.

FamilyOperatorsWhat they do
Comparison< <= > >= == !=Compare two values, return a bool
Assignment= += -= *= /=Assign, or update a variable in place
Logicaland or notCombine or negate bool values
Identityis is notTest whether two names refer to the same object

count += 1 is shorthand for count = count + 1. Use is only to compare with None; for values, use ==.

4
True
True
False
True
True

Use the Exercises section to explore all the different comparison operators.

Casting converts between types with int(), float(), and str(). The station also logs air pressure, and at 3571 m it is far below sea level pressure — around 651 hPa, or 65120 Pa. Here it arrives as text:

65120.0 <class 'str'>
65120.0 <class 'float'>
65220.0
7 readings
3

1.1.3 Rounding Numbers

Use round() for nearest-integer behaviour. A second argument says how many decimal places to keep.

1.67

1.1.4 Formatting Numbers with f-strings

f-strings (f"...") interpolate variables and apply a format specifier after a colon: :.2f fixes two decimals, :.3e uses scientific notation, :.1% formats a fraction as a percentage. This keeps reported precision honest and units explicit.

Jungfraujoch: -8.4 °C (264.75 K)
pressure = 6.512e+04 Pa
days below -9 °C = 28.6%

1.1.5 Working with Text

Measurements often arrive embedded in text — station records, log lines, CSV fields.

A string is a sequence of characters, so you can pick out single characters by index and ranges of them by slice. Indexing starts at 0; negative indices count from the end.

J h

A slice [start:stop] includes start and excludes stop. Either end can be left out, and it defaults to the beginning or the end of the string.

Jungf
Jungf
raujoch
joch

Station records are often fixed width: every field always occupies the same positions, so slicing alone can take them apart. Here the first three characters are the station code and the rest is the date.

JFJ
2022-01-03

The same slicing syntax will return on lists in the next subchapter and on arrays in 1.3.

Methods

Not every record is that tidy. String methods clean them up: .strip() removes surrounding whitespace, .split(sep) breaks a string into parts, and .lower()/.upper()/.title() normalise case. The parts are still text and must be cast before arithmetic.

All of these are methods: functions that belong to a type and are called on a value of that type with a dot. The functions used so far, such as print(), type(), float(), and round(), take the value to work on inside their parentheses. A method takes it from in front of the dot instead, and the parentheses hold only any further arguments: record.split(",") below splits the string record, and "," says where to cut. The parentheses are required even when there is nothing to put in them, as in .strip(). Each type has its own methods: every str has .split(), but a float does not, so temp_celsius.split(",") raises an AttributeError. A string method never changes the string it is called on. It returns a new value, which you keep by assigning it to a name, and which you can call a further method on straight away: in fields[0].strip().title(), .strip() returns a trimmed string and .title() is then called on that.

['        JUNGFRAUJOCH ', ' -9.2 ', ' degC  ']
Jungfraujoch
jungfraujoch
-9.2
degC

Not everything after a dot is a method. An attribute is a value stored on an object, and it is read with the dot but without parentheses, since there is nothing to run. Paths in 1.1.7 have both: data_path.parent is an attribute holding the folder the file sits in, and data_path.exists() is a method that checks the disk. Python looks up a method the same way, as an attribute whose value is a function, which is why temp_celsius.split(",") fails with an AttributeError: a float has no attribute called split. Adding parentheses to a plain attribute, as in data_path.parent(), raises a TypeError. Leaving them off a method raises nothing: record.strip gives back the method itself instead of a trimmed string, and any error appears only later, where that result is used as text.

1.1.6 Importing Libraries

Python keeps extra tools in libraries (also called modules), and you bring them into your environment with import. The standard library ships with many tools; math is a good example, and the exercises for this subchapter use it.

4.0
3.141592653589793

1.1.7 Files and Paths with pathlib

Standard .txt and .csv files are universally readable plain text. pathlib.Path builds filesystem paths that work on any operating system: join the parts with the / operator, Path("_files") / "station_daily.csv", and Python uses the right separator for your system. Never type backslashes (e.g., \t inside a string is a tab), and do not start a path with / unless you mean the root of the disk. We open paths with .open(), specifying a mode:

ModeMeaning
"r"Read an existing file (the default); fails if it does not exist
"w"Write, creating the file or overwriting everything in it
"a"Append, adding to the end and keeping the existing contents

An open file must be closed again, or the last writes may never reach disk. Doing that by hand is easy to forget, so the standard form is a with block, which closes the file for you as soon as the block ends — even if an error occurs inside it.

Does the file exist? False

Open the path in mode "w" to create the file and write the header row plus the first day of the week. The with block closes it again as soon as the indented lines are done.

Does the file exist now? True

In Python, indentation is part of the syntax. A line that opens a block ends in a colon, like with ... as fhandler: above, and every line indented beneath it belongs to that block, up to the first line back at the previous level. The two write calls are indented, so they run while the file is open; the print is not, so it runs after the with block has closed the file. Many languages mark blocks with braces and ignore indentation, but in Python the indentation is the only marker, so moving a line in or out of a block changes when it runs, and Python raises no error as long as the result is still valid code. Use four spaces per level, the convention in Python code; notebook editors indent the line after a colon for you. A colon with no indented line after it, or an indented line where no block was opened, stops the cell with an IndentationError. The bodies of the if statements, loops, and functions in the next subchapter follow the same rule.

Mode "a" reopens the same file and adds to the end instead of overwriting it. That gets the remaining six days of the week in.

station,day,max_temp_celsius
JFJ,2022-01-01,-8.4
JFJ,2022-01-02,-8.9
JFJ,2022-01-03,-9.2
JFJ,2022-01-04,-9.0
JFJ,2022-01-05,-9.5
JFJ,2022-01-06,-7.8
JFJ,2022-01-07,-6.1

number of lines: 8
['JFJ', '2022-01-01', '-8.4']
-8.4 <class 'str'>
-8.4 <class 'float'>
264.75

When generated code lies: a hidden type bug

AI assistants write code that runs and looks right, but is sometimes silently wrong. A classic trap: values read from a text file are strings, and comparing strings does not behave like comparing numbers.

is -8.4 warmer than -9.2 ? False
is -8.4 warmer than -9.2 ? True

Summary

ConceptRule to remember
TypesEvery value has a type; type() shows it (int, float, str, bool, None).
CastingText from a file is str; use float() or int() before doing maths.
Operators+ adds numbers but joins strings; / always gives a float.
ComparisonStrings compare character by character, not by numeric value.
NamingEncode the quantity and unit: temp_celsius, pressure_pa.
Formattingf"{value:.2f}" fixes the number of decimals shown.
FilesUse pathlib.Path with a with path.open(mode) block; "w" overwrites, "a" appends.

Resources

  • Project Pythia Foundations — geoscience-flavoured tutorials on the core scientific-Python stack; the natural next step after this chapter.

  • The Python tutorial — the authoritative reference for the built-in types and syntax used above.