<!--order=1-->


<h1>Beginner's Guide to Python</h1>
<p>Python is one of the most readable programming languages ever designed — the syntax is close to plain English in many places, which makes it a good first language. It's also genuinely useful: web development, data science, automation, system administration, scripting — Python works for all of these. This guide covers the core building blocks with runnable examples.</p>

<h2>Running Python</h2>
<pre>
# Check what version you have
$ python3 --version

# Run a script
$ python3 myscript.py

# Interactive interpreter (great for experimenting)
$ python3
>>> print("hello")
hello
>>> 2 + 2
4
>>> exit()
</pre>

<h2>Variables and Data Types</h2>
<p>Python is dynamically typed — you don't declare types, they're inferred from the value:</p>
<pre>
name      = "Alice"       # str (string)
age       = 25            # int (integer)
height    = 5.6           # float (decimal)
is_admin  = True          # bool (True or False)
nothing   = None          # NoneType (absence of value)

# f-strings: embed expressions in strings (Python 3.6+)
print(f"Name: {name}, Age: {age}, Height: {height}")
# Output: Name: Alice, Age: 25, Height: 5.6

# Check a type
print(type(age))   # &lt;class 'int'&gt;
</pre>

<h2>Input and Output</h2>
<pre>
# Output
print("Hello, world!")
print("Multiple", "values", "on", "one", "line")   # space-separated by default
print("No newline at end", end="")                  # custom end character

# Input — always returns a string
user_name = input("What is your name? ")
print(f"Hello, {user_name}!")

# Convert input to a number
age = int(input("Enter your age: "))
print(f"Next year you'll be {age + 1}")
</pre>

<h2>Conditionals</h2>
<pre>
number = int(input("Enter a number: "))

if number > 0:
    print("Positive")
elif number < 0:
    print("Negative")
else:
    print("Zero")

# Comparison operators: ==, !=, &lt;, &gt;, &lt;=, &gt;=
# Logical operators: and, or, not

if age >= 18 and is_admin:
    print("Adult admin")

if name == "Alice" or name == "Bob":
    print("Known user")
</pre>

<h2>Loops</h2>
<pre>
# for loop — iterate over a range or collection
for i in range(5):         # 0, 1, 2, 3, 4
    print(i)

for i in range(1, 6):      # 1, 2, 3, 4, 5
    print(i)

for i in range(0, 10, 2):  # 0, 2, 4, 6, 8 (step of 2)
    print(i)

# while loop — repeat while condition is true
count = 0
while count < 5:
    print(f"Count: {count}")
    count += 1

# break and continue
for i in range(10):
    if i == 3:
        continue    # skip 3
    if i == 7:
        break       # stop at 7
    print(i)
# Output: 0 1 2 4 5 6
</pre>

<h2>Functions</h2>
<pre>
# Define a function
def greet(name):
    return f"Hello, {name}!"

print(greet("Alice"))    # Hello, Alice!

# Default parameter values
def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

print(greet("Bob"))              # Hello, Bob!
print(greet("Bob", "Hi"))        # Hi, Bob!

# Multiple return values
def min_max(numbers):
    return min(numbers), max(numbers)

lo, hi = min_max([3, 1, 4, 1, 5, 9, 2, 6])
print(f"Min: {lo}, Max: {hi}")   # Min: 1, Max: 9
</pre>

<h2>Lists</h2>
<p>Lists are ordered, mutable sequences — the most common data structure in Python:</p>
<pre>
fruits = ["apple", "banana", "cherry"]
print(fruits[0])           # apple (zero-indexed)
print(fruits[-1])          # cherry (negative index from end)
print(fruits[1:3])         # ['banana', 'cherry'] (slice)

fruits.append("orange")    # add to end
fruits.insert(1, "mango")  # insert at position
fruits.remove("banana")    # remove by value
popped = fruits.pop()      # remove and return last item

print(len(fruits))         # length

# Iterate
for fruit in fruits:
    print(fruit)

# List comprehension — concise way to build a list
squares = [x**2 for x in range(10)]       # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
evens   = [x for x in range(20) if x % 2 == 0]
</pre>

<h2>Dictionaries</h2>
<p>Dictionaries store key-value pairs — like a lookup table:</p>
<pre>
person = {
    "name":  "Alice",
    "age":   25,
    "city":  "Toronto"
}

print(person["name"])          # Alice
print(person.get("email", ""))  # "" — safe get with default

person["email"] = "alice@example.com"   # add or update a key
del person["city"]                       # remove a key

# Iterate over keys and values
for key, value in person.items():
    print(f"{key}: {value}")

# Check if key exists
if "email" in person:
    print(person["email"])
</pre>

<h2>File Handling</h2>
<pre>
# Write to a file
with open("example.txt", "w") as f:
    f.write("Line one\n")
    f.write("Line two\n")

# Read entire file
with open("example.txt", "r") as f:
    content = f.read()
    print(content)

# Read line by line (memory-efficient for large files)
with open("example.txt", "r") as f:
    for line in f:
        print(line.strip())    # strip removes the trailing newline

# Append to existing file
with open("example.txt", "a") as f:
    f.write("Line three\n")
</pre>
<p>The <code>with</code> statement (context manager) automatically closes the file when the block ends — even if an exception occurs. Always use it.</p>

<h2>Error Handling</h2>
<pre>
try:
    number = int(input("Enter a number: "))
    result = 10 / number
    print(f"Result: {result}")
except ValueError:
    print("That's not a valid number")
except ZeroDivisionError:
    print("Can't divide by zero")
except Exception as e:
    print(f"Unexpected error: {e}")
finally:
    print("This always runs")    # cleanup code goes here
</pre>

<h2>Useful Built-in Functions</h2>

<table>
  <thead><tr><th>Function</th><th>Purpose</th><th>Example</th></tr></thead>
  <tbody>
    <tr><td><code>len(x)</code></td><td>Length of list, string, dict</td><td><code>len("hello") → 5</code></td></tr>
    <tr><td><code>range(n)</code></td><td>Sequence of integers</td><td><code>range(5) → 0,1,2,3,4</code></td></tr>
    <tr><td><code>sorted(x)</code></td><td>Return sorted copy</td><td><code>sorted([3,1,2]) → [1,2,3]</code></td></tr>
    <tr><td><code>enumerate(x)</code></td><td>Index + value pairs</td><td><code>for i, v in enumerate(lst)</code></td></tr>
    <tr><td><code>zip(a, b)</code></td><td>Pair elements from two sequences</td><td><code>for x, y in zip(xs, ys)</code></td></tr>
    <tr><td><code>str(x)</code></td><td>Convert to string</td><td><code>str(42) → "42"</code></td></tr>
    <tr><td><code>int(x)</code></td><td>Convert to integer</td><td><code>int("42") → 42</code></td></tr>
    <tr><td><code>type(x)</code></td><td>Type of an object</td><td><code>type(3.14) → float</code></td></tr>
  </tbody>
</table>

<h2>A Complete Example: Word Counter</h2>
<pre>
#!/usr/bin/env python3
"""Count word frequencies in a text file."""

import sys

def count_words(filename):
    counts = {}
    try:
        with open(filename, "r") as f:
            for line in f:
                for word in line.lower().split():
                    # Remove punctuation from word ends
                    word = word.strip(".,!?\"';:-")
                    if word:
                        counts[word] = counts.get(word, 0) + 1
    except FileNotFoundError:
        print(f"Error: file '{filename}' not found", file=sys.stderr)
        return {}
    return counts

def main():
    if len(sys.argv) != 2:
        print(f"Usage: {sys.argv[0]} &lt;filename&gt;", file=sys.stderr)
        sys.exit(1)

    counts = count_words(sys.argv[1])
    if not counts:
        return

    # Sort by count descending, then alphabetically
    for word, count in sorted(counts.items(), key=lambda x: (-x[1], x[0])):
        print(f"{count:5d}  {word}")

if __name__ == "__main__":
    main()
</pre>
<pre>
# Run it:
$ python3 wordcount.py myfile.txt
   42  the
   31  and
   28  of
   ...
</pre>

<h2>A Practical Learning Workflow</h2>
<p>When learning, change one small thing at a time and run the program after each change. The interpreter and a few standard tools are enough to build good habits:</p>
<pre>
# Check a file for syntax errors without running it
$ python3 -m py_compile myscript.py

# Run with warnings enabled
$ python3 -Wall myscript.py

# Show the installed Python and its location
$ python3 --version
$ command -v python3
</pre>
<p>Keep experiments in their own directory and write down the command that runs them. When a script becomes useful, give it a clear name, a short description, and a small example of expected output.</p>

<h2>Turning a Script into a Reliable Tool</h2>
<p>A useful script should handle the ordinary ways it can be called incorrectly. Check command-line arguments, catch only errors you can explain, and send diagnostic messages to standard error when appropriate.</p>
<pre>
import sys

if len(sys.argv) != 2:
    print(f"Usage: {sys.argv[0]} filename", file=sys.stderr)
    sys.exit(2)

filename = sys.argv[1]
print(f"Reading {filename}")
</pre>
<p>Exit status <code>0</code> means success. A non-zero status lets shell scripts, cron, and systemd know that something needs attention.</p>

<h2>Small Exercises</h2>
<ul>
  <li>Change the word counter to ignore words shorter than four characters.</li>
  <li>Add a <code>--limit</code> option so it prints only the most common words.</li>
  <li>Write a program that reports how many lines each file in a directory contains.</li>
  <li>Run one of the programs on a Raspberry Pi and compare its output with your main computer.</li>
</ul>

<h2>References</h2>
<ul>
  <li><a href="https://docs.python.org/3/tutorial/" target="_blank" rel="noopener">Python Official Tutorial ↗</a></li>
  <li><a href="https://docs.python.org/3/library/" target="_blank" rel="noopener">Python Standard Library Reference ↗</a></li>
  <li><a href="https://realpython.com" target="_blank" rel="noopener">Real Python — tutorials and articles ↗</a></li>
</ul>
