Глава 1
Unlocking the Digital World: Python for Everybody
When Mark Zuckerberg wanted to build the first version of Facebook, he turned to Python. When NASA needed to process vast amounts of space imagery, they chose Python. When Netflix wanted to personalize your recommendations, they relied on Python. Charles Severance's "Python for Everybody" has become the gateway through which millions have entered the world of programming, with over 14 million learners enrolled in related courses on platforms like Coursera and edX. What makes this book special isn't just its technical content-it's Severance's unique ability to make programming feel accessible to anyone, regardless of their background. Unlike traditional programming texts that overwhelm beginners with jargon, this book starts with the fundamental question: why should you learn to program at all? The answer is simple yet profound-computers are tools that work for us, and programming gives us the power to instruct these tools to solve real problems that matter in our lives.
Глава 2
The Foundation: Why Programming Matters
Programming is fundamentally about creativity-building something that serves your needs. The most effective way to learn programming isn't through abstract exercises but through personal motivation. When you're driven by genuine interest in solving a problem, you'll naturally push through the inevitable frustrations of learning.
At its core, a computer consists of basic components: the central processing unit (CPU) that performs calculations, main memory that stores information during computation, secondary memory for long-term storage, input devices like keyboards, and output devices like screens. Understanding this hardware foundation helps conceptualize how your programs interact with the physical machine.
Programming involves writing instructions that tell the computer precisely what to do. These instructions, called programs, are executed by the CPU, which follows them exactly. The challenge lies in writing instructions that are both correct and comprehensible to the machine. Unlike human communication, computers cannot infer meaning or handle ambiguity-they need explicit, detailed instructions.
Python's vocabulary and grammar are deliberately simpler than human languages, but also more rigid-even minor errors will cause the program to fail. The Python interpreter serves as a conversation partner, allowing you to type statements and receive immediate feedback. This interactive mode enables experimentation and immediate learning.
While Python uses an interpreter that executes code line-by-line, other languages use compilers that translate entire programs before execution. Python's interpreter reads your code, translates it to machine language, and executes it before moving to the next line, making it ideal for beginners due to its interactive nature.
Beyond the interactive mode, complete Python programs are written in files with a .py extension. These programs typically take input, process it through a sequence of steps, and produce output. Even complex programs are built from simple building blocks: input (getting data), output (displaying results), sequential execution (performing operations in order), conditional execution (making decisions), and repeated execution (loops).
Programming inevitably involves errors, which fall into three categories: syntax errors (violations of language rules), logic errors (code that runs but produces incorrect results), and semantic errors (code that doesn't do what you intended). Learning to identify and fix these errors-debugging-is an essential part of programming, requiring patience and systematic problem-solving.
Глава 3
Building Blocks: Variables, Expressions, and Statements
Just as buildings are constructed from bricks, programs are built from fundamental elements: variables, expressions, and statements. Variables are named memory locations that store values, allowing programmers to save results for later use and make programs more readable by using meaningful names instead of raw values.
Values in Python belong to specific types, including integers, floating-point numbers (decimals), and strings (text). The type determines what operations can be performed-you can multiply numbers but not text (though "Test" * 3 creates "TestTestTest" through repetition).
Operators like + (addition), - (subtraction), * (multiplication), / (division), and ** (exponentiation) combine with values to form expressions. Python follows mathematical convention for operator precedence: Parentheses, Exponentiation, Multiplication/Division, Addition/Subtraction (PEMDAS). When in doubt, use parentheses to ensure operations occur in your intended order.
The modulus operator (%) yields the remainder when the first operand is divided by the second. For example, 7 % 3 equals 1 because 7 divided by 3 is 2 with 1 remaining. This operator is useful for checking divisibility (x % y equals zero when x is divisible by y) and extracting rightmost digits from numbers.
To interact with users, the input() function gets keyboard input, pausing the program until the user types something and presses Enter. It returns the entered text as a string, which can be converted to numbers using int() or float() functions-though this causes errors if users enter non-numeric text.
Comments explain code in natural language, making programs easier to understand. In Python, comments start with # and continue to the end of the line. They're most valuable when explaining why code works a certain way rather than what it does, especially for non-obvious features.
While variable names can be almost anything, "mnemonic" names that reflect their purpose make code more understandable. For example, using hours, rate, and pay is much clearer than generic names like a, b, c or meaningless ones like x1q3z9ahd.
Глава 4
Making Decisions: Conditional Execution
Real-world problems rarely follow a single path. When driving, we make decisions based on traffic lights: stop at red, proceed with caution at yellow, go at green. Programming mirrors this decision-making through conditional statements.
Boolean expressions evaluate to either True or False and serve as the foundation for decisions. Comparison operators like == (equality), != (inequality), > (greater than), < (less than), >= (greater than or equal to), and <= (less than or equal to) create these expressions. A common mistake is using = (assignment) instead of == (comparison).
Python offers three logical operators to combine conditions: and (true only if both conditions are true), or (true if either condition is true), and not (negates a boolean expression). While these should work with boolean expressions, Python treats any non-zero value as "true," providing flexibility but potentially causing confusion.
The simplest conditional is the if statement, which executes indented code only when its condition is true. For situations with two possibilities, if-else statements choose between alternative actions. When facing more than two possibilities, chained conditionals using elif (short for "else if") check conditions in order, executing only the first matching branch.
Conditionals can be nested inside other conditionals, creating complex decision structures. However, deeply nested conditionals quickly become difficult to read. Logical operators often provide cleaner alternatives, such as using "and" to combine conditions (e.g., "if 0 < x and x < 10" instead of nesting two separate if statements).
The try/except structure handles errors gracefully. When Python encounters an error in a try block, it jumps to the except block rather than crashing. This works like an "insurance policy" for code that might fail, such as converting user input to numbers.
Python evaluates logical expressions from left to right and stops as soon as the result is determined-known as short-circuit evaluation. This enables the "guardian pattern" where a safety check prevents errors in later parts of an expression. For example, in "x >= 2 and y != 0 and (x/y) > 2", the y != 0 check guards against division by zero errors.
Глава 5
Reusable Code: Functions
Functions are named sequences of statements that perform computations. They take arguments as input and return results as output, allowing programmers to organize code into reusable pieces that solve specific problems.
Python provides many built-in functions like max(), min(), and len(), which return the largest value, smallest value, and number of items in a sequence, respectively. Type conversion functions like int(), float(), and str() convert values between types, while the math module offers mathematical functions like log10(), sin(), and sqrt().
Beyond using built-in functions, you can create your own with function definitions using the def keyword. A definition specifies the function name and statement sequence, with the header ending in a colon followed by an indented body. Once defined, a function creates a function object that can be called using the same syntax as built-in functions.
Function definitions create function objects but don't execute the function's body until called. Functions must be defined before they can be called, meaning the definition must appear before the first call in the program flow.
Program execution begins at the first statement and proceeds top to bottom. Function calls create a "detour" where execution jumps to the function body, completes those statements, then returns to where it left off. Functions can call other functions, creating nested detours, but Python tracks the execution path and always returns to the correct point after each function completes.
Functions can accept arguments that get assigned to parameters inside the function. Arguments can be expressions (evaluated before the function call), variables, or literals. The parameter name inside the function is independent of any variable names used when calling the function.
Functions that return values (like math.sqrt()) are "fruitful functions" whose results can be assigned to variables or used in expressions. Functions that perform actions without returning values (like print()) are "void functions" that return None. The return statement sends a computed value back to the calling code.
Functions make programs more readable by naming groups of statements, and they reduce repetition by allowing code reuse. This makes programs smaller and easier to maintain since changes only need to be made in one place. Functions also allow you to debug parts separately before assembling them into a working whole.
Глава 6
Repetition: Iteration
Imagine having to write out instructions for brushing your teeth: "Pick up toothbrush. Apply toothpaste. Brush upper left molars 10 times. Brush upper right molars 10 times..." This would be tedious. Instead, we might say "Brush each tooth for 10 seconds." Programming faces similar challenges, and iteration provides the solution.
A common pattern in programming is updating a variable where the new value depends on the old one, such as x = x + 1. Before updating a variable, it must be initialized. Incrementing means adding 1 to a variable; decrementing means subtracting 1.
The while statement creates a loop that executes as long as a condition remains true. The flow involves evaluating the condition, executing the body if true, then returning to check the condition again. The loop body should change variables so the condition eventually becomes false, avoiding infinite loops.
Infinite loops occur when there's no iteration variable or when the loop condition never becomes false. You can intentionally create infinite loops using "while True" and then use break statements to exit when needed, like when taking user input until they type "done". The continue statement allows you to skip to the next iteration without completing the current one.
For loops are used when iterating through a known set of items like a list. Unlike while loops (indefinite loops), for loops run a specific number of times based on the collection size. The iteration variable changes with each iteration, stepping through each item in the collection.
Common loop patterns involve counting items, calculating sums, or finding maximum and minimum values. Counting loops use a counter variable initialized to zero that increments with each iteration. Summing loops use an accumulator that adds each value encountered. To find the largest or smallest value in a collection, loops track the "largest/smallest so far" using a variable initialized to None and updated when new extremes are found.
As programs grow larger, debugging becomes more time-consuming. "Debugging by bisection" can help by checking intermediate values near the middle of the program rather than examining each line sequentially, effectively cutting the search space in half with each step.
Глава 7
Working with Text: Strings
Text processing is one of computing's most common tasks, from search engines analyzing web pages to messaging apps handling conversations. In Python, text is represented as strings-sequences of characters that can be manipulated through various operations.
A string is a sequence of characters that can be accessed individually using the bracket operator with an index. In Python, indexing starts at 0, so the first character is at position 0, the second at position 1, and so on. The len() function returns the number of characters in a string, with indices ranging from 0 to len(string)-1.
Processing a string one character at a time is called traversal. This can be done with a while loop by tracking an index variable, or more elegantly with a for loop that automatically assigns each character to a variable: for char in fruit:.
A slice extracts a segment of a string using the syntax [n:m], which returns characters from position n up to but not including position m. Omitting the first index starts from the beginning, while omitting the second goes to the end.
Strings in Python are immutable, meaning you cannot change individual characters after creation. Instead, you must create a new string with the desired changes, often by concatenating slices with new characters.
A common string pattern uses a counter variable to track occurrences. For example, to count a specific letter in a string, initialize a counter to zero, loop through each character, and increment the counter when the target letter is found.
The in operator returns True if the first string appears as a substring in the second string, and False otherwise. Strings can be compared using standard comparison operators, with Python treating uppercase and lowercase letters differently in sorting.
Strings in Python are objects with built-in methods like upper(), lower(), find(), and strip(). These methods are called using dot notation (string.method()) and may take arguments. Multiple methods can be chained together in a single expression.
String methods like find() can help extract substrings by locating positions of specific characters. For example, to extract a domain from an email address, you can find the position of the @ symbol and the following space, then use slicing to extract the text between them.
Глава 8
Persistence: Files
Until now, our programs have been transient exercises using CPU and main memory where all "thinking" happens. Secondary memory (files) provides persistence-data isn't erased when power is off. This persistence is crucial for any real-world application, from saving user preferences to storing large datasets.
Opening a file communicates with the operating system to locate the file and ensure it exists. If successful, the system returns a file handle-not the actual data, but a "handle" for accessing it. Think of this like getting a ticket to a library book rather than the book itself. The open() function fails with a traceback if the file doesn't exist or you lack proper permissions. Common permission issues include trying to read from write-protected files or writing to system directories.
Text files can be viewed as sequences of lines, similar to how strings are sequences of characters. Lines are separated by a special newline character, represented in Python as '\n'. Different operating systems historically used different line endings (Windows uses '\r\n', Mac used '\r'), but Python handles these differences automatically. File handles can be used as sequences in for loops to efficiently process files line by line without loading everything into memory. This is particularly important when dealing with large files that might exceed available RAM.
A common pattern is reading through files while only processing lines meeting specific conditions. For example, you might want to process only lines containing email addresses or starting with specific dates. String methods like startswith() can select lines with desired prefixes, while other methods like contains() or regular expressions offer more sophisticated filtering. The rstrip() method helps remove trailing whitespace including newlines to prevent double spacing when printing. Similarly, lstrip() removes leading whitespace, and strip() removes both.
Rather than editing code to process different files, programs can use input() to let users specify filenames. This makes programs more flexible but introduces potential errors if users enter nonexistent filenames. Good practice includes validating file extensions and checking path accessibility before attempting operations.
The try/except structure elegantly handles potential failures when opening files, allowing recovery code to execute when operations fail rather than crashing with a traceback. For example:
This approach is considered "Pythonic"-an elegant solution that Python programmers appreciate.
To write files in Python, open them with mode "w" as a second parameter. Additional modes include "a" for append and "r+" for both reading and writing. Opening an existing file in write mode clears all previous data, while non-existent files are created. The write() method puts data into files and returns the number of characters written. Unlike print(), write() doesn't automatically add newlines, so you must explicitly include "\n" characters. Always close files after writing to ensure data is physically saved to disk, or better yet, use the 'with' statement which automatically handles file closing:
Глава 9
Beyond Strings: Lists, Dictionaries, and Tuples
Python offers several data structures beyond strings, each with specific strengths for different situations. Lists are versatile sequences created using square brackets that can contain elements of any type-numbers, strings, or even other lists. Unlike strings, lists are mutable, meaning they can be changed after creation.
For loops provide the simplest way to process list elements. Lists support concatenation with the + operator to join lists together, and repetition with the * operator to repeat a list a specified number of times. The slice operator works on lists just like strings, extracting portions using start:end notation.
Python provides built-in list methods: append() adds a single element to the end, extend() adds all elements from another list, and sort() arranges elements from low to high. Elements can be removed using pop() (by index), del (without returning them), or remove() (by value).
Dictionaries are more general than lists, allowing any type as indices (called keys) rather than just integers. They create mappings between keys and values, with each key-value pair forming an item. Dictionaries excel as counters for tracking frequencies, such as counting word occurrences in text.
When looping through dictionaries with a for statement, Python iterates through the keys. This allows accessing both keys and their values using the index operator. You can filter entries by checking values or sort keys alphabetically by creating a list of keys, sorting it, and then looking up corresponding values.
Tuples are sequence values similar to lists but with the critical difference of being immutable. They can contain any type of values, are indexed by integers, and are comparable and hashable-making them usable as dictionary keys. Tuples are created using parentheses: (1, 2, 3).
Python allows tuples on the left side of assignment statements, enabling multiple variable assignment in a single statement: x, y = y, x swaps two variables. The items() method of dictionaries returns a list of tuples containing key-value pairs, providing a way to sort dictionary contents.
Глава 10
The Power of Python: From Regular Expressions to Web Services
As your programming skills grow, Python offers powerful tools for more complex tasks. Regular expressions provide a concise way to search and extract patterns from strings. Special characters like the period (.) match any character, while ^ matches the beginning of a line. When combined with repetition characters like * (zero or more) or + (one or more), you can create patterns that match varying amounts of text. For example, the pattern "^[A-Z].*\d$" matches lines that start with a capital letter and end with a digit. The \w character class matches word characters, while \s matches whitespace, making it easy to parse structured text like log files or CSV data.
Python's networking capabilities allow you to retrieve information from the Internet using the Hypertext Transfer Protocol (HTTP). The socket library makes network connections straightforward, enabling direct TCP/IP communication. The urllib library simplifies HTTP interactions by treating web pages like files, handling details like URL encoding and HTTP headers automatically. For more sophisticated web interactions, the requests library offers an elegant API for sending GET, POST, and other HTTP requests, complete with session management and automatic JSON handling.
Web services enable programs to communicate with each other over the internet using standardized formats like XML (eXtensible Markup Language) and JSON (JavaScript Object Notation). Python's ElementTree library makes parsing XML straightforward, supporting XPath queries and document traversal. The built-in json library converts JSON strings into native Python structures, making it simple to work with REST APIs and modern web services. For example, you can easily interact with services like Twitter's API or OpenWeatherMap to fetch and process real-time data.
Object-oriented programming provides a way to manage complexity by breaking programs into smaller, understandable pieces. Classes serve as templates for creating objects that combine code and data. Each object maintains its own independent copy of attributes, allowing them to evolve separately as methods are called on them. Inheritance enables code reuse by creating specialized versions of existing classes, while encapsulation helps maintain data integrity by controlling access to object internals. For instance, a banking application might use classes to represent accounts, transactions, and customers, with methods enforcing business rules.
Databases offer persistent storage for data that needs to survive between program runs or is too large to fit in memory. SQLite, built into Python, provides a lightweight database system that stores data in a single file. The SQL language allows creating tables, inserting data, querying with filters, and establishing relationships between multiple tables. More advanced features include transactions for data integrity, indexes for performance optimization, and joins for combining data from multiple tables. For larger applications, Python also integrates well with enterprise databases like PostgreSQL and MySQL through libraries such as SQLAlchemy.
Python's visualization capabilities enable turning raw data into meaningful graphics. Libraries like matplotlib create charts and graphs, supporting everything from simple line plots to complex 3D visualizations. Seaborn builds on matplotlib to provide statistical visualizations with minimal code. Integration with JavaScript libraries like D3 enables interactive web-based visualizations, while Plotly offers both static and dynamic plotting capabilities. These tools transform complex datasets into intuitive visual representations that reveal patterns and insights, making them invaluable for data analysis and presentation. For example, you can create interactive dashboards showing real-time data updates or generate publication-quality figures for scientific papers.