Udemy-The-Python-Mega-Course-Learn-Python-in-60-Days-with-20-Apps

module 1

print

print('Enter a todo:')

def print(*values: object,
sep: str | None = “ “,
end: str | None = “\n”,
file: SupportsWrite[str] | None = None,
flush: Literal[False] = False) -> None

*parameter是用来接受任意多个参数并将其放在一个元组中

1
2
3
4
5
6
7
>>> def demo(*p):
print(p)


>>> demo(1,2,3)
(1, 2, 3)

**parameter用于接收类似于关键参数一样赋值的形式的多个实参放入字典中(即把该函数的参数转换为字典)。

1
2
3
4
5
6
7
>>> def demo(**p):
for i in p.items():
print(i)

>>> demo(x=1,y=2)
('x', 1)
('y', 2)

input()

def input(__prompt: object = “”) -> str
Read a string from standard input. The trailing newline is stripped.
The prompt string, if given, is printed to standard output without a trailing newline before reading input.

1
2
prompt = 'Enter a todo: '
todo1 = input(prompt)

type()

type(object) -> the object’s type

1
2
print(type('prompt'))  # <class 'str'>
print(type(['todos1', 'todos2','todos3','todos4'])) # <class 'list'>

len()

def len(__obj: Sized) -> int
Return the number of items in a container.

1
2
length_1 = len('Enter a title: ')
print(length_1) # 15

using leading or trailing underscores

invoke引用
If you invoke something such as a principle, a saying, or a famous person, you refer to them in order to support your argument.

mangling 扭曲
f you say that someone mangles words or information, you are criticizing them for not speaking or writing clearly or correctly.

To avoid name clashes with subclasses, use two leading underscores to invoke Python’s name mangling rules.

  • _single_leading_underscore: weak “internal use” indicator. E.g. from M import * does not import objects whose names start with an underscore.
  • single_trailing_underscore_: used by convention to avoid conflicts with Python keyword, e.g. :
    tkinter.Toplevel(master, class_=’ClassName’)
  • __double_leading_underscore: when naming a class attribute, invokes name mangling (inside class FooBar, __boo becomes _FooBar__boo; see below).
    Python mangles these names with the class name: if class Foo has an attribute named __a, it cannot be accessed by Foo.__a. (An insistent user could still gain access by calling Foo._Foo__a.) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.
  • __double_leading_and_trailing_underscore__: “magic” objects or attributes that live in user-controlled namespaces. E.g. __init__, __import__ or __file__. Never invent such names; only use them as documented.

Python mangles these names with the class name: if class Foo has an attribute named __a, it cannot be accessed by Foo.__a. (An insistent user could still gain access by calling Foo._Foo__a.) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.

boolean type

is_male = True

list.append()

def append(self, __object: _T) -> None
Append object to the end of the list

1
2
3
4
todos = []
todo = 'Hello'
todos.append(todo)
print(todos) # ['Hello']

str.capitalize() str.title()

print('hello world'.title()) # Hello world

def capitalize(self: LiteralString) -> LiteralString
Return a capitalized version of the string.
More specifically, make the first character have upper case and the rest lower case.

print('hello world'.title()) # Hello World

def title(self: LiteralString) -> LiteralString
Return a version of the string where each word is titlecased.
More specifically, words start with uppercased characters and all remaining cased characters have lower case.

pycharm shortcut

cut a line
ctrl + x

paste a line before this line
ctrl + v

ctrl + b

while loop

1
2
3
4
5
password = input("Enter password: ")

while password != 'pass123':
password = input("Enter password: ")
print("Password was correct!")
1
2
3
4
x = 1
while x <= 6:
print(x)
x = x + 1

break statement

break may only occur syntactically nested in a for or while loop, but not nested in a function or class definition within that loop.
It terminates the nearest enclosing loop, skipping the optional else clause if the loop has one.
If a for loop is terminated by break, the loop control target keeps its current value.
When break passes control out of a try statement with a finally clause, that finally clause is executed before really leaving the loop

1
2
3
4
5
6
7
8
9
10
11
12
todos = []
while True:
# prompt = 'Enter a todo: '
user_action = input("Type add, show, or exit: ")
match user_action:
case 'add':
todo = input("Enter a todo: ")
todos.append(todo)
case 'show':
print(todos)
case 'exit':
break

dir(str)

print(dir(str))
print(dir('Hello'))

def dir(__o: object = …) -> list[str]
Show attributes of an object.
If called without an argument, return the names in the current scope. Else, return an alphabetized list of names comprising (some of) the attributes of the given object, and of attributes reachable from it. If the object supplies a method named __dir__, it will be used; otherwise the default dir() logic is used and returns:

for a module object: the module’s attributes. for a class object: its attributes, and recursively the attributes
of its bases.
for any other object: its attributes, its class’s attributes, and
recursively the attributes of its class’s base classes.

1
2
import builtins
print(dir(builtins))

help()

help("Hello".capitalize)

Help on built-in function capitalize:

capitalize() method of builtins.str instance
Return a capitalized version of the string.
More specifically, make the first character have upper case and the rest lower
case.

match

1
2
3
4
5
6
7
user_action = input("Type add or show: ")
match user_action:
case 'add':
todo = input("Enter a todo: ")
todos.append(todo)
case 'show':
print(todos)
1
2
3
4
5
6
7
8
9
10
11
12
13
user_action = input("Type add, show, or exit: ").strip()
match user_action:
case 'add':
todo = input("Enter a todo: ")
todos.append(todo)
case 'show' | 'display':
print(todos)
for item in todos:
print(item)
case 'exit':
break
case _:
print("please enter a correct command!")

for loop

1
2
3
4
todo_list = ['todo 1', 'todo 2', 'todo 3']
for todo in todo_list:
item = item.title()
print(todo)
1
2
for c in 'meals':
print(c)

str.strip()

1
2
3
str1 = 'add '
str2 = str1.strip()
print(str1, str2) # 'add ' 'add'

def strip(self: LiteralString, __chars: LiteralString | None = None) -> LiteralString
Return a copy of the string with leading and trailing whitespace removed.
If chars is given and not None, remove characters in chars instead

list index

list indices must be integers or slices, not str

int() float() str()

1
2
3
4
5
6
7
8
x = 10.2
print(type(x)) # <class 'float'>

y = 10
print(type(y)) # <class 'int'>

z = 'a'
print(type(z)) # <class 'str'>

number = int(input("Number of the todo to edit: "))
int([x]) -> integer int(x, base=10) -> integer
Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-‘ and be surrounded by whitespace. The base defaults to 10.

number = float('1.23')

str1 = str(12.3)

str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.

list.index()

1
2
todo_list = ['todo 1', 'todo 2', 'todo 3']
print(todo_list.index('todo 1')) # 0

def index(self,
__value: _T,
__start: SupportsIndex = 0,
__stop: SupportsIndex = sys.maxsize) -> int
Return first index of value.
Raises ValueError if the value is not present

list.getitem()

def __getitem__(self, __i: SupportsIndex) -> _T
Return self[index].

'Hello'[2] = 'a'
‘str’ object does not support item assignment

str.replace()

1
2
3
filename = 1.raw data.txt'
filename = filename.replace('.', '-', 1)
print(filename) # 1-raw data.txt

def replace(self: LiteralString,
__old: LiteralString,
__new: LiteralString,
__count: SupportsIndex = -1) -> LiteralString
Return a copy with all occurrences of substring old replaced by new.

count
Maximum number of occurrences to replace. -1 (the default value) means replace all occurrences.
If the optional argument count is given, only the first count occurrences are replaced.

tuple

1
2
3
4
5
filenames1 = ('1.raw data.txt', '2.reports.txt', '3.presentations.txt')

print(type(filenames1)) # <class 'tuple'>
# 'tuple' object does not support item assignment
filenames1[0] = 'new file.txt'

python local variable only in function

1
2
3
4
5
6
7
8
filenames = ['1.raw data.txt', '2.reports.txt', '3.presentations.txt']

for filename in filenames:
filename = filename.replace('.', '-', 1)
print(filename)

print(filename) # 3-presentations.txt
print(filenames)

enumerate function

enumerate
to name things on a list one by one

class enumerate(Iterator[tuple[int, _T]], Generic[_T])
Return an enumerate object.

The enumerate object yields pairs containing a count (from start, which defaults to zero) and a value yielded by the iterable argument.
enumerate is useful for obtaining an indexed list:
(0, seq[0]), (1, seq[1]), (2, seq[2]), …

iterable
an object supporting iteration

1
2
3
4
5
6
# 0  -  todo 1
# 1 - todo 2
# 2 - todo 3
todo_list = ['todo 1', 'todo 2', 'todo 3']
for index, item in enumerate(todo_list):
print(index, " - ", item)
1
2
3
4
5
todo_list = ['todo 1', 'todo 2', 'todo 3']
a = enumerate(todo_list)
print(type(a)) # <class 'enumerate'>
b = list(a)
print(b) # [(0, 'todo 1'), (1, 'todo 2'), (2, 'todo 3')]

format string

1
2
3
index = 1
item = 'hello'
print(f"{index + 1}-{item}") # '2-hello'

list.pop()

1
2
3
4
5
todo_list = ['todo 1', 'todo 2', 'todo 3']
popped = todo_list.pop(1)
print(todo_list, popped) # ['todo 1', 'todo 3'] 'todo 2'
popped = todo_list.pop()
print(todo_list, popped) # ['todo 1'] 'todo 3'

def pop(self, __index: SupportsIndex = -1) -> _T
Remove and return item at index (default last).

list.sort()

def sort(self: list[SupportsRichComparisonT],
*,
key: None = None,
reverse: bool = False) -> None

Sort the list in ascending order and return None.
The sort is in-place (i.e. the list itself is modified) and stable (i.e. the order of two equal elements is maintained).
If a key function is given, apply it once to each list item and sort them, ascending or descending, according to their function values.
The reverse flag can be set to sort in descending order.

1
2
3
waiting_list = ['sen', 'ben', 'john']
waiting_list.sort()
print(waiting_list) # ['ben', 'john', 'sen']

qiangfeng python

网络请求库 –> 浏览器客户端

网站服务器
WSGI: The Web Server Gateway Interface is a simple calling convention for web servers to forward requests to web applications or frameworks written in the Python programming language.

浏览器客户端
WebKit is a browser engine developed by Apple and primarily used in its Safari web browser, as well as all web browsers on iOS and iPadOS.


HTTP Requests
Start line
HTTP requests are messages sent by the client to initiate an action on the server. Their start-line contain three elements:

  1. An HTTP method, a verb (like GET, PUT or POST) or a noun (like HEAD or OPTIONS), that describes the action to be performed. For example, GET indicates that a resource should be fetched or POST means that data is pushed to the server (creating or modifying a resource, or generating a temporary document to send back).

  2. The request target, usually a URL, or the absolute path of the protocol, port, and domain are usually characterized by the request context. The format of this request target varies between different HTTP methods.

  3. The HTTP version, which defines the structure of the remaining message, acting as an indicator of the expected version to use for the response.

HTTP request header
The start-line and HTTP headers of the HTTP message are collectively known as the head of the requests, whereas its payload is known as the body.

Alt text

Alt text

1
2
3
4
5
6
7
8
9
10
11
12
13

GET /home.html HTTP/1.1
Host: developer.mozilla.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/testpage.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
If-Modified-Since: Mon, 18 Jul 2016 02:36:04 GMT
If-None-Match: "c561c68d0ba92bbeb8b0fff2a9199f722e3a621a"
Cache-Control: max-age=0

Body
The final part of the request is its body. Not all requests have one: requests fetching resources, like GET, HEAD, DELETE, or OPTIONS, usually don’t need one. Some requests send data to the server in order to update it: as often the case with POST requests (containing HTML form data).

Bodies can be broadly divided into two categories:

  • Single-resource bodies, consisting of one single file, defined by the two headers: Content-Type and Content-Length.
  • Multiple-resource bodies, consisting of a multipart body, each containing a different bit of information. This is typically associated with HTML Forms.

HTTP Responses

Status line
The start line of an HTTP response, called the status line, contains the following information:

The protocol version, usually HTTP/1.1.

  • A status code, indicating success or failure of the request. Common status codes are 200, 404, or 302
  • A status text. A brief, purely informational, textual description of the status code to help a human understand the HTTP message.
  • A typical status line looks like: HTTP/1.1 404 Not Found.

Alt text


网络请求:

  • urllib
    urllib is a package that collects several modules for working with URLs:
  • requests
    Requests is an HTTP client library for the Python programming language. Requests is one of the most, if not the most, popular Python libraries that is not included with Python due to its elegant mapping of the HTTP protocol onto Python’s object-oriented semantics
    It is implemented as a wrapper for urllib3, another 3rd party Python HTTP library.
  • selenium
  • appium 手机app

数据解析

  • re
    This module provides regular expression matching operations similar to those found in Perl.
  • xpath
    XPath (XML Path Language) is an expression language designed to support the query or transformation of XML documents.
    The XPath language is based on a tree representation of the XML document, and provides the ability to navigate around the tree, selecting nodes by a variety of criteria.
  • bs4
  • json

数据存储

  • pymysql
  • mongodb
  • elasticsearch

多任务

  • 多线程 threading/queue
    抢占式多任务处理(Preemptive multitasking)是计算机操作系统中,一种实现多任务处理(multi task)的方式。相对于协作式多任务处理而言。协作式环境下,下一个进程被调度的前提是当前进程主动放弃时间片;抢占式环境下,操作系统完全决定进程调度方案,操作系统可以剥夺耗时长的进程的时间片,提供给其它进程。
  • 协程 asynio | gevent/eventlet
    协程非常类似于线程。但是协程是协作式多任务的,而典型的线程是内核级抢占式多任务的。
    协作式多任务(Cooperative Multitasking),是一种多任务处理方式,多任务是使电脑能同时处理多个程序的技术,相对于抢占式多任务(Preemptive multitasking)由操作系统决定任务切换时机。协作式多任务要求每一个运行中的程序,定时放弃(yield)自己的执行权利,告知操作系统可让下一个程序执行,因为需要程序之间合作达到调度,故称作协作式多任务。

反爬虫

  • UA(user-agent)
  • 登录cookie
  • 请求频次 -> IP代理
  • 验证码
  • 动态js(splash/api)

python crash course

Getting Started

Setting up your Programming Environment

installing Python

https://www.python.org/downloads/

run the installer. Make sure you select the option Add Python to PATH, which will make it easier to configure your system correctly. Figure 1-1 shows this option selected.

Alt text

Running Python in a Terminal Session

Open a new command window and enter python in lowercase. You should
see a Python prompt (>>>), which means Windows has found the version of
Python you just installed.

Installing the Python Extension for VS Code

To install the Python extension, click the Manage icon, which looks
like a gear in the lower-left corner of the VS Code app. In the menu that
appears, click Extensions. Enter python in the search box and click the
Python extension. (If you see more than one extension named Python,
choose the one supplied by Microsoft.)

running hello_world.py

folder: python_work

file: hello_world.py

print("Hello Python world!")

vscode -> run -> Run Without Debugging or press CTRL-F5

Hello Python world!

Running Python Programs from a Terminal

terminal to run hello_world.py:

1
2
3
4
5
C:\> cd Desktop\python_work
C:\Desktop\python_work> dir
hello_world.py
C:\Desktop\python_work> python hello_world.py
Hello Python world!

First, use the cd command to navigate to the python_work folder, which is in the Desktop folder.

Next, use the dir command to make sure hello_world.py is in this folder.

Then run the file using the command python hello_world.py.

Variables and Simple Data Types

variable

1
2
message = "Hello Python world!"
print(message)

output

Hello Python world!

We’ve added a variable named message.

Every variable is connected to a
value, which is the information associated with that variable.


1
2
3
4
message = "Hello Python world!"
print(message)
message = "Hello Python Crash Course world!"
print(message)

output:

1
2
Hello Python world!
Hello Python Crash Course world!

You can change the value of a variable in your program at any time,
and Python will always keep track of its current value.

Naming and Using Variables

rules:

  • Variable names can contain only letters, numbers, and underscores.
    They can start with a letter or an underscore, but not with a number.
    For instance, you can call a variable message_1 but not 1_message.
  • Spaces are not allowed in variable names, but underscores can be used
    to separate words in variable names. For example, greeting_message works
    but greeting message will cause errors.
  • Avoid using Python keywords and function names as variable names.
    For example, do not use the word print as a variable name; Python
    has reserved it for a particular programmatic purpose. (See “Python
    Keywords and Built-in Functions” on page 466.)
  • Variable names should be short but descriptive. For example, name is
    better than n, student_name is better than s_n, and name_length is better
    than length_of_persons_name.
  • Be careful when using the lowercase letter l and the uppercase letter O
    because they could be confused with the numbers 1 and 0.

The Python variables you’re using at this point should be lowercase. You won’t get errors if you use uppercase letters, but uppercase letters in variable names have special meanings that we’ll discuss in later chapters.

Avoiding Name Errors When Using Variables

1
2
message = "Hello Python Crash Course reader!"
print(mesage)

When an error occurs in your program, The interpreter provides
a traceback when a program cannot run successfully.

A traceback is a record of where the interpreter ran into trouble when trying to execute your code.

example:

1
2
3
4
5
Traceback (most recent call last):
File "hello_world.py", line 2, in <module> # 1
print(mesage) # 2
^^^^^^
NameError: name 'mesage' is not defined. Did you mean: 'message'? # 3

The output reports that an error occurs in line 2 of the file hello_world.py and tells us what kind of error it found 3.
In this case it found a name error
and reports that the variable being printed, mesage, has not been defined.

A name error usually means we either forgot to set a variable’s value before using it, or we made a spelling mistake when entering the variable’s name.

If Python finds a variable name that’s similar to the one it doesn’t recognize, it will ask if that’s the name you meant to use.

Variables Are Labels

It’s much better to think of variables as labels that you can assign to values. You can
also say that a variable references a certain value.

Strings

A string is a series of characters.
Anything inside quotes is considered a string in Python, and you can use single or double quotes around your

strings like this:

“This is a string.”
‘This is also a string.’

use quotes and apostrophes within your strings:

‘I told my friend, “Python is my favorite language!”‘
“The language ‘Python’ is named after Monty Python, not the snake.”
“One of Python’s strengths is its diverse and supportive community.”

Changing Case in a String with Methods

string.title()

Return a version of the string where each word is titlecased.
More specifically, words start with uppercased characters and all remaining cased characters have lower case.

1
2
name = "ada lovelace"
print(name.title())

output:
Ada Lovelace

A method is an action that Python can perform on a piece of data. The dot (.) after name in name.title() tells Python to make the title() method act on the variable name.

Every method is followed by a set of parentheses, because
methods often need additional information to do their work. That information is provided inside the parentheses.

The title() function doesn’t need
any additional information, so its parentheses are empty.


change a string to all uppercase or all lowercase letters like this:

1
2
3
name = "Ada Lovelace"
print(name.upper())
print(name.lower())

This will display the following:

ADA LOVELACE
ada lovelace

The lower() method is particularly useful for storing data. You typically won’t want to trust the capitalization that your users provide, so you’ll convert strings to lowercase before storing them. Then when you want to display the information, you’ll use the case that makes the most sense foreach string.

Using Variables in Strings

use a variable’s value inside a string:

1
2
3
4
first_name = "ada"
last_name = "lovelace"
full_name = f"{first_name} {last_name}" # 1
print(full_name)

place the letter f immediately
before the opening quotation mark 1. Put braces around the name or
names of any variable you want to use inside the string.

These strings are called f-strings. The f is for format, because Python
formats the string by replacing the name of any variable in braces with its
value. The output from the previous code is:
ada lovelace


another example:

1
2
3
4
first_name = "ada"
last_name = "lovelace"
full_name = f"{first_name} {last_name}"
print(f"Hello, {full_name.title()}!") # 1

output:

Hello, Ada Lovelace!

Adding Whitespace to Strings with Tabs or Newlines

whitespace refers to any nonprinting characters, such as
spaces, tabs, and end-of-line symbols.
use whitespace to organize your output so it’s easier for users to read.

a tab \t:

1
2
3
4
>>> print("Python")
Python
>>> print("\tPython")
Python

newline \n:

1
2
3
4
5
>>> print("Languages:\nPython\nC\nJavaScript")
Languages:
Python
C
JavaScript

combine tabs and newlines:

1
2
3
4
5
>>> print("Languages:\n\tPython\n\tC\n\tJavaScript")
Languages:
Python
C
JavaScript

Stripping Whitespace

‘python’ and ‘python ‘ to a program, they are two different strings.

often you’ll want to compare two strings to determine whether they are the same. Extra whitespace can be confusing in much simpler situations as well.

eliminate extra whitespace from data that people enter.


To ensure that no whitespace exists at the right side of a string, use
the rstrip() method:

1
2
3
4
5
6
7
>>> favorite_language = 'python ' # 1
>>> favorite_language # 2
'python '
>>> favorite_language.rstrip() # 3
'python'
>>> favorite_language # 4
'python '

However, it is only removed temporarily. If you ask for the value
of favorite_language again, the string looks the same as when it was entered,
including the extra whitespace 4.
To remove the whitespace from the string permanently, you have to
associate the stripped value with the variable name:

1
2
3
4
>>> favorite_language = 'python '
>>> favorite_language = favorite_language.rstrip() # 1
>>> favorite_language
'python'

strip whitespace from the left side of a string using the lstrip() method
from both sides at once using strip():

1
2
3
4
5
6
7
>>> favorite_language = ' python '  # 1 
>>> favorite_language.rstrip() # 2
' python'
>>> favorite_language.lstrip() # 3
'python '
>>> favorite_language.strip() # 4
'python'

In the real world, these stripping functions are used most often to clean up
user input before it’s stored in a program.

Removing Prefixes

remove a prefix.

1
2
3
>>> nostarch_url = 'https://nostarch.com'
>>> nostarch_url.removeprefix('https://')
'nostarch.com'

Enter the name of the variable followed by a dot, and then the method
removeprefix(). Inside the parentheses, enter the prefix you want to remove
from the original string.

Like the methods for removing whitespace, removeprefix() leaves the
original string unchanged. If you want to keep the new value with the prefix removed, either reassign it to the original variable or assign it to a new
variable:

>>> simple_url = nostarch_url.removeprefix('https://')

Avoiding Syntax Errors with Strings

A syntax error occurs when Python doesn’t recognize a section of your program as valid Python code.

example

1
2
message = 'One of Python's strengths is its diverse community.'
print(message)

You’ll see the following output:

1
2
3
4
File "apostrophe.py", line 1
message = 'One of Python's strengths is its diverse community.'
1 ^
SyntaxError: unterminated string literal (detected at line 1)

Your editor’s syntax highlighting feature should help you spot some syntax errors quickly as you write your programs. If you see Python code highlighted as if it’s English or English highlighted as if it’s Python code, you probably have a mismatched quotation mark somewhere in your file.

Numbers

Integers

You can add (+), subtract (-), multiply (*), and divide (/) integers in Python.

1
2
3
4
5
6
7
8
>>> 2 + 3
5
>>> 3 - 2
1
>>> 2 * 3
6
>>> 3 / 2
1.5

uses two multiplication symbols to represent exponents:

1
2
3
4
5
6
>>> 3 ** 2
9
>>> 3 ** 3
27
>>> 10 ** 6
1000000

Python supports the order of operations too, so you can use multiple
operations in one expression. You can also use parentheses to modify the
order of operations. For example:

1
2
3
4
>>> 2 + 3*4
14
>>> (2 + 3) * 4
20

The spacing in these examples has no effect on how Python evaluates the expressions; it simply helps you more quickly spot the operations that have priority when you’re reading through the code.

Floats

Python calls any number with a decimal point a float. it refers to the fact that a decimal point Variables and can appear at any position in a number.

For the most part, you can use floats without worrying about how they
behave. Simply enter the numbers you want to use, and Python will most
likely do what you expect:

1
2
3
4
5
6
7
8
>>> 0.1 + 0.1
0.2
>>> 0.2 + 0.2
0.4
>>> 2 *0.1
0.2
>>> 2* 0.2
0.4

However, be aware that you can sometimes get an arbitrary number of
decimal places in your answer:

1
2
3
4
>>> 0.2 + 0.1
0.30000000000000004
>>> 3 * 0.1
0.30000000000000004

This happens in all languages and is of little concern. Python tries to
find a way to represent the result as precisely as possible, which is sometimes
difficult given how computers have to represent numbers internally.

Integers and Floats

When you divide any two numbers, even if they are integers that result in a
whole number, you’ll always get a float:

1
2
>>> 4/2
2.0

If you mix an integer and a float in any other operation, you’ll get a
float as well:

1
2
3
4
5
6
>>> 1 + 2.0
3.0
>>> 2 * 3.0
6.0
>>> 3.0 ** 2
9.0

Python defaults to a float in any operation that uses a float, even if the
output is a whole number.

Underscores in Numbers

When you’re writing long numbers, you can group digits using underscores
to make large numbers more readable:

1
2
3
>>> universe_age = 14_000_000_000
>>> print(universe_age)
14000000000

Python ignores the underscores when storing these kinds of values.

Even if you don’t group the digits in threes, the value will still be unaffected. To Python, 1000 is the same as 1_000, which is the same as 10_00. This
feature works for both integers and floats.

Multiple Assignment

You can assign values to more than one variable using just a single line of
code. This can help shorten your programs and make them easier to read;

you’ll use this technique most often when initializing a set of numbers.
For example, here’s how you can initialize the variables x, y, and z to zero:

>>> x, y, z = 0, 0, 0

You need to separate the variable names with commas, and do the same
with the values, and Python will assign each value to its respective variable.
As long as the number of values matches the number of variables, Python
will match them up correctly

Constants

A constant is a variable whose value stays the same throughout the life of a
program.

Python doesn’t have built-in constant types, but Python programmers use all capital letters to indicate a variable should be treated as a constant and never be changed:

MAX_CONNECTIONS = 5000

Comments

u should add notes within your programs that describe your overall approach to the
problem you’re solving.

A comment allows you to write notes in your spoken
language, within your programs.

How Do You Write Comments?

In Python, the hash mark (#) indicates a comment. Anything following a
hash mark in your code is ignored by the Python interpreter. For example:

1
2
# Say hello to everyone.
print("Hello Python people!")

Python ignores the first line and executes the second line.
Hello Python people!

Introducing Lists

what is a list

A list is a collection of items in a particular order

Because a list usually contains more than one element, it’s a good idea to make the name of your list plural, such as letters, digits, or names

In Python, square brackets ([]) indicate a list, and individual elements in the list are separated by commas.example

1
2
bicycles = ['trek', 'cannondale', 'redline', 'specialized']
print(bicycles)

output:
['trek', 'cannondale', 'redline', 'specialized']

Accessing Elements in a List

Lists are ordered collections, so you can access any element in a list by
telling Python the position, or index, of the item desired. To access an element in a list, write the name of the list followed by the index of the item
enclosed in square brackets.

1
2
bicycles = ['trek', 'cannondale', 'redline', 'specialized']
print(bicycles[0])

output
trek

Index Positions Start at 0, Not 1

Python has a special syntax for accessing the last element in a list. If you
ask for the item at index -1, Python always returns the last item in the list:

1
2
3
bicy
cles = ['trek', 'cannondale', 'redline', 'specialized']
print(bicycles[-1])

The index -2 returns the second item from the end of the list, the index -3 returns the third item from the end, and so forth.

Using Individual Values from a List

You can use individual values from a list just as you would any other variable.

1
2
3
bicycles = ['trek', 'cannondale', 'redline', 'specialized']
message = f"My first bicycle was a {bicycles[0].title()}."
print(message)

Modifying, Adding, and Removing Elements

Most lists you create will be dynamic, meaning you’ll build a list and then
add and remove elements from it as your program runs its course.

Modifying Elements in a List

To change an element, use the name of the list followed
by the index of the element you want to change, and then provide the new
value you want that item to have.

1
2
3
4
motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)
motorcycles[0] = 'ducati'
print(motorcycles)

output
[‘honda’, ‘yamaha’, ‘suzuki’]
[‘ducati’, ‘yamaha’, ‘suzuki’]

Adding Elements to a List

Appending Elements to the End of a List

append the item to the
list. When you append an item to a list, the new element is added to the end
of the list

1
2
3
4
motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)
motorcycles.append('ducati')
print(motorcycles)

To put your users in control, start by defining an empty list that
will hold the users’ values. Then append each new value provided to the list
you just created.

For example,

1
2
3
4
5
motorcycles = []
motorcycles.append('honda')
motorcycles.append('yamaha')
motorcycles.append('suzuki')
print(motorcycles)

output
[‘honda’, ‘yamaha’, ‘suzuki’]

Inserting Elements into a List

You can add a new element at any position in your list by using the insert()
method. You do this by specifying the index of the new element and the
value of the new item:
This operation shifts every other value in the list one position to the
right.

1
2
3
motorcycles = ['honda', 'yamaha', 'suzuki']
motorcycles.insert(0, 'ducati')
print(motorcycles)

output
[ducati’, ‘honda’, ‘yamaha’, ‘suzuki’]

Removing Elements from a List

Removing an Item Using the del Statement

know the position of the item you want to remove from a list, you can
use the del statement:

motorcycles = [‘honda’, ‘yamaha’, ‘suzuki’]
print(motorcycles)
del motorcycles[0]
print(motorcycles)

Removing an Item Using the pop() Method

The pop() method removes the last item in a list, but it lets you work
with that item after removing it. The term pop comes from thinking of a
list as a stack of items and popping one item off the top of the stack. In this
analogy, the top of a stack corresponds to the end of a list.

1
2
3
4
5
motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles)
popped_motorcycle = motorcycles.pop()
print(motorcycles)
print(popped_motorcycle)

[‘honda’, ‘yamaha’, ‘suzuki’]
[‘honda’, ‘yamaha’]
suzuki

Popping Items from Any Position in a List
1
2
3
motorcycles = ['honda', 'yamaha', 'suzuki']
first_owned = motorcycles.pop(0)
print(f"The first motorcycle I owned was a {first_owned.title()}.")

The first motorcycle I owned was a Honda.

Remember that each time you use pop(), the item you work with is no
longer stored in the list.

when you want to delete an item from a list and not use that item in any way, use the del statement; if you want to use an item as you remove it, use the pop() method.

Removing an Item by Value

If you only know the value of the item you want to remove, you
can use the remove() method

1
2
3
4
motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati']
print(motorcycles)
motorcycles.remove('ducati')
print(motorcycles)

[‘honda’, ‘yamaha’, ‘suzuki’, ‘ducati’]
[‘honda’, ‘yamaha’, ‘suzuki’]

The remove() method deletes only the first occurrence of the value you specify. If there’s a possibility the value appears more than once in the list, you’ll need to use a loop to make sure all occurrences of the value are removed.

Organizing a List

Sometimes you’ll want
to preserve the original order of your list, and other times you’ll want to
change the original order.

Sorting a List Permanently with the sort() Method

The sort() method changes the order of the list permanently. The cars
are now in alphabetical order, and we can never revert to the original order:

1
2
3
cars = ['bmw', 'audi', 'toyota', 'subaru']
cars.sort()
print(cars)

[‘audi’, ‘bmw’, ‘subaru’, ‘toyota’]

o sort this list in reverse-alphabetical order

1
2
3
cars = ['bmw', 'audi', 'toyota', 'subaru']
cars.sort(reverse=True)
print(cars)

[‘toyota’, ‘subaru’, ‘bmw’, ‘audi’]

Sorting a List Temporarily with the sorted() Function

The sorted() function lets you display your list
in a particular order, but doesn’t affect the actual order of the list.

1
2
3
4
5
6
7
cars = ['bmw', 'audi', 'toyota', 'subaru']
print("Here is the original list:")
print(cars)
print("\nHere is the sorted list:")
print(sorted(cars))
print("\nHere is the original list again:")
print(cars)

output:

Here is the original list:
[‘bmw’, ‘audi’, ‘toyota’, ‘subaru’]
Here is the sorted list:
[‘audi’, ‘bmw’, ‘subaru’, ‘toyota’]
1 Here is the original list again:
[‘bmw’, ‘audi’, ‘toyota’, ‘subaru’]

The sorted() function can also accept a reverse=True
argument if you want to display a list in reverse-alphabetical order.

Sorting a list alphabetically is a bit more complicated when all the values are not in lowercase

Printing a List in Reverse Order

If we originally stored the list of cars in chronological order according to when
we owned them, we could easily rearrange the list into reverse-chronological
order:

1
2
3
4
cars = ['bmw', 'audi', 'toyota', 'subaru']
print(cars)
cars.reverse()
print(cars)

[‘bmw’, ‘audi’, ‘toyota’, ‘subaru’]
[‘subaru’, ‘toyota’, ‘audi’, ‘bmw’]

Finding the Length of a List

cars = [‘bmw’, ‘audi’, ‘toyota’, ‘subaru’]
len(cars)

Avoiding Index Errors When Working with Lists

1
2
motorcycles = ['honda', 'yamaha', 'suzuki']
print(motorcycles[3])

This example results in an index error:

1
2
3
4
5
Traceback (most recent call last):
File "motorcycles.py", line 2, in <module>
print(motorcycles[3])
~~~~~~~~~~~^^^
IndexError: list index out of range

Keep in mind that whenever you want to access the last item in a list,
you should use the index -1. This will always work, even if your list has
changed size since the last time you accessed it:

motorcycles = [‘honda’, ‘yamaha’, ‘suzuki’]
print(motorcycles[-1])

output:

suzuki


The only time this approach will cause an error is when you request the
last item from an empty list:

1
2
motorcycles = []
print(motorcycles[-1])

No items are in motorcycles, so Python returns another index error:

1
2
3
4
5
6
Traceback (most recent call last):
File "motorcyles.py", line 3, in <module>
print(motorcycles[-1])
~~~~~~~~~~~^^^^
IndexError: list index out of range

If an index error occurs and you can’t figure out how to resolve it, try
printing your list or just printing the length of your list. Your list might look
much different than you thought it did, especially if it has been managed
dynamically by your program. Seeing the actual list, or the exact number of
items in your list, can help you sort out such logical errors.

Working with Lists

Looping allows you to take the same action, or set
of actions, with every item in a list

Looping Through an Entire List

Say we have a list of magicians’ names, and we want to print out each name in the list.

We could do this by retrieving each name from the list individually, but this approach could cause several problems. For one, it would
be repetitive to do this with a long list of names. Also, we’d have to change
our code each time the list’s length changed. Using a for loop avoids both of
these issues by letting Python manage these issues internally.

1
2
3
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician)

alice
david
carolina

A Closer Look at Looping

for magician in magicians:

This line tells Python to retrieve the first value from the list magicians and associate it with the variable magician.

the set of steps is repeated once for each item in the list, no matter how many items
are in the list.

you can choose
any name you want for the temporary variable that will be associated with
each value in the list. However, it’s helpful to choose a meaningful name
that represents a single item from the list.

Using singular and plural names can help
you identify whether a section of code is working with a single element from
the list or the entire list.

Doing More Work Within a for Loop

1
2
3
4
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(f"{magician.title()}, that was a great trick!")
print(f"I can't wait to see your next trick, {magician.title()}.\n")

Alice, that was a great trick!
I can’t wait to see your next trick, Alice.

David, that was a great trick!
I can’t wait to see your next trick, David.

Carolina, that was a great trick!
I can’t wait to see your next trick, Carolina.

Doing Something After a for Loop

Any lines of code after the for loop that are not indented are executed
once without repetition.

1
2
3
4
5
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(f"{magician.title()}, that was a great trick!")
print(f"I can't wait to see your next trick, {magician.title()}.\n")
print("Thank you, everyone. That was a great magic show!")

Alice, that was a great trick!
I can’t wait to see your next trick, Alice.

David, that was a great trick!
Working with Lists 53
I can’t wait to see your next trick, David.

Carolina, that was a great trick!
I can’t wait to see your next trick, Carolina.

Thank you, everyone. That was a great magic show!

Avoiding Indentation Errors

Python uses indentation to determine how a line, or group of lines, is related
to the rest of the program.

common indentation errors. For example, people
sometimes indent lines of code that don’t need to be indented or forget
to indent lines that need to be indented.

Forgetting to Indent

1
2
3
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician)
1
2
3
4
File "magicians.py", line 3
print(magician)
^
IndentationError: expected an indented block after 'for' statement on line 2

Forgetting to Indent Additional Lines

This is a logical error. The syntax is valid Python code, but the code does
not produce the desired result because a problem occurs in its logic. If you
expect to see a certain action repeated once for each item in a list and it’s
executed only once, determine whether you need to simply indent a line or
a group of lines.

1
2
3
4
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(f"{magician.title()}, that was a great trick!")
print(f"I can't wait to see your next trick, {magician.title()}.\n")

output:

Alice, that was a great trick!
David, that was a great trick!
Carolina, that was a great trick!
I can’t wait to see your next trick, Carolina.

Indenting Unnecessarily

1
2
message = "Hello Python world!"
print(message)

File “hello_world.py”, line 2
print(message)
^
IndentationError: unexpected indent

You can avoid unexpected indentation errors by indenting only when you have a specific reason to do so.

Indenting Unnecessarily After the Loop

1
2
3
4
5
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(f"{magician.title()}, that was a great trick!")
print(f"I can't wait to see your next trick, {magician.title()}.\n")
print("Thank you everyone, that was a great magic show!")
1
2
3
4
5
6
7
8
9
10
11
12
Alice, that was a great trick!
I can't wait to see your next trick, Alice.

Thank you everyone, that was a great magic show!
David, that was a great trick!
I can't wait to see your next trick, David.

Thank you everyone, that was a great magic show!
Carolina, that was a great trick!
I can't wait to see your next trick, Carolina.

Thank you everyone, that was a great magic show!

This is another logical error, similar to the one in “Forgetting to Indent
Additional Lines” on page 54. Because Python doesn’t know what you’re
trying to accomplish with your code, it will run all code that is written in
valid syntax. If an action is repeated many times when it should be executed
only once, you probably need to unindent the code for that action.

Forgetting the Colon

1
2
3
magicians = ['alice', 'david', 'carolina']
for magician in magicians
print(magician)
1
2
3
4
 File "magicians.py", line 2
for magician in magicians
^
SyntaxError: expected ':'

Making Numerical Lists

Using the range() Function

range(stop) -> range object range(start, stop[, step]) -> range object

Return an object that produces a sequence of integers from start (inclusive) to stop (exclusive) by step. range(i, j) produces i, i+1, i+2, …, j-1. start defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3. These are exactly the valid indices for a list of 4 elements. When step is given, it specifies the increment (or decrement).

generate a series of numbers.

1
2
for value in range(1, 5):
print(value)

output:
1
2
3
4

You can also pass range() only one argument, and it will start the
sequence of numbers at 0.

Using range() to Make a List of Numbers

convert the results of range()
directly into a list using the list() function.

1
2
numbers = list(range(1, 6))
print(numbers)

This is the result:
[1, 2, 3, 4, 5]


1
2
3
4
5
squares = []
for value in range(1, 11):
square = value ** 2
squares.append(square)
print(squares)

[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Simple Statistics with a List of Numbers

1
2
3
4
5
6
7
>>> digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> min(digits)
0
>>> max(digits)
9
>>> sum(digits)
45

List Comprehensions

A list comprehension allows you to generate
this same list in just one line of code. A list comprehension combines the
for loop and the creation of new elements into one line, and automatically
appends each new element.

1
2
squares = [value**2 for value in range(1, 11)]
print(squares)

output:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Working with Part of a List

Slicing a List

To make a slice, you specify the index of the first and last elements you want
to work with.
n, Python stops one item before the
second index you specify.

1
2
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[0:3])

output:
[‘charles’, ‘martina’, ‘michael’]

1
2
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[:4])

[‘charles’, ‘martina’, ‘michael’, ‘florence’]

1
2
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[2:])

[‘michael’, ‘florence’, ‘eli’]

1
2
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[-3:])

Looping Through a Slice

1
2
3
4
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print("Here are the first three players on my team:")
1 for player in players[:3]:
print(player.title())

Here are the first three players on my team:
Charles
Martina
Michael

Copying a List

1
2
3
4
5
6
7
8
my_foods = ['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods[:]
my_foods.append('cannoli')
friend_foods.append('ice cream')
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods are:")
print(friend_foods)

My favorite foods are:
[‘pizza’, ‘falafel’, ‘carrot cake’, ‘cannoli’]
My friend’s favorite foods are:
[‘pizza’, ‘falafel’, ‘carrot cake’, ‘ice cream’]

1
2
3
4
5
6
7
8
9
my_foods = ['pizza', 'falafel', 'carrot cake']
# This doesn't work:
friend_foods = my_foods
my_foods.append('cannoli')
friend_foods.append('ice cream')
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods are:")
print(friend_foods)

My favorite foods are:
[‘pizza’, ‘falafel’, ‘carrot cake’, ‘cannoli’, ‘ice cream’]
My friend’s favorite foods are:
[‘pizza’, ‘falafel’, ‘carrot cake’, ‘cannoli’, ‘ice cream’]

Tuples

Lists work well for storing collections of items that can change throughout the
life of a program.

Python refers to values that cannot change as
immutable, and an immutable list is called a tuple.

Defining a Tuple

A tuple looks just like a list, except you use parentheses instead of square
brackets.

1
2
3
dimensions = (200, 50)
print(dimensions[0])
print(dimensions[1])

output
200
50


1
2
dimensions = (200, 50)
dimensions[0] = 250
1
2
3
4
Traceback (most recent call last):
File "dimensions.py", line 2, in <module>
dimensions[0] = 250
TypeError: 'tuple' object does not support item assignment

Tuples are technically defined by the presence of a comma; the parentheses make them
look neater and more readable. If you want to define a tuple with one element, you
need to include a trailing comma:
my_t = (3,)

Looping Through All Values in a Tuple

1
2
3
dimensions = (200, 50)
for dimension in dimensions:
print(dimension)

200
50

Writing Over a Tuple

Although you can’t modify a tuple, you can assign a new value to a variable
that represents a tuple

1
2
3
4
5
6
7
8
dimensions = (200, 50)
print("Original dimensions:")
for dimension in dimensions:
print(dimension)
dimensions = (400, 100)
print("\nModified dimensions:")
for dimension in dimensions:
print(dimension)

if Statements 0

Programming often involves examining
a set of conditions and deciding which
action to take based on those conditions.
Python’s if statement allows you to examine
the current state of a program and respond appropriately to that state.

a example

1
2
3
4
5
6
cars = ['audi', 'bmw', 'subaru', 'toyota']
for car in cars:
if car == 'bmw':
print(car.upper())
else:
print(car.title())

output

Audi
BMW
Subaru
Toyota

Conditional Tests

an expression that can be evaluated as
True or False and is called a conditional test. Python uses the values True and
False to decide whether the code in an if statement should be executed.

Checking for Equality

equality operator returns
True if the values on the left and right side of the operator match, and False if
they don’t match.

1
2
3
>>> car = 'audi'
>>> car == 'bmw'
False

Ignoring Case When Checking for Equality

1
2
3
4
5
6
7
>>> car = 'Audi'
>>> car == 'audi'
False
>>> car.lower() == 'audi'
True
>>> car
'Audi'

Checking for Inequality

1
2
3
requested_topping = 'mushrooms'
if requested_topping != 'anchovies':
print("Hold the anchovies!")

Hold the anchovies!

Numerical Comparisons

mathematical comparisons

1
2
3
4
5
6
7
8
9
>>> age = 19
>>> age < 21
True
>>> age <= 21
True
>>> age > 21
False
>>> age >= 21
False

Checking Multiple Conditions

Using and to Check Multiple Conditions

To check whether two conditions are both True simultaneously, use the keyword and to combine the two conditional tests; if each test passes, the overall
expression evaluates to True. If either test fails or if both tests fail, the expression evaluates to False.

1
2
3
4
5
6
7
>>> age_0 = 22
>>> age_1 = 18
>>> age_0 >= 21 and age_1 >= 21
False
>>> age_1 = 22
>>> age_0 >= 21 and age_1 >= 21
True

To improve readability, you can use parentheses around the individual
tests
(age_0 >= 21) and (age_1 >= 21)

Checking Whether a Value Is in a List

To find out whether a particular value is already in a list, use the keyword in.

1
2
3
4
5
>>> requested_toppings = ['mushrooms', 'onions', 'pineapple']
>>> 'mushrooms' in requested_toppings
True
>>> 'pepperoni' in requested_toppings
False

Checking Whether a Value Is Not in a List

1
2
3
4
banned_users = ['andrew', 'carolina', 'david']
user = 'marie'
if user not in banned_users:
print(f"{user.title()}, you can post a response if you wish.")

Marie, you can post a response if you wish.

Boolean Expressions

A Boolean expression is just another name for a conditional
test. A Boolean value is either True or False, just like the value of a conditional
expression after it has been evaluated.

if Statements

Simple if Statements

if conditional_test:
do something

if-else Statements

take one action when a conditional test passes and a different action in all other cases.
An if-else block is similar to a simple if statement, but the else statement allows
you to define an action or set of actions that are executed when the conditional test fails.

1
2
3
4
5
6
7
age = 17
if age >= 18:
print("You are old enough to vote!")
print("Have you registered to vote yet?")
else:
print("Sorry, you are too young to vote.")
print("Please register to vote as soon as you turn 18!")

Sorry, you are too young to vote.
Please register to vote as soon as you turn 18!

The if-elif-else Chain

Python’s if-elif-else syntax. Python executes only one
block in an if-elif-else chain. It runs each conditional test in order, until
one passes. When a test passes, the code following that test is executed and
Python skips the rest of the tests.

1
2
3
4
5
6
7
age = 12
if age < 4:
print("Your admission cost is $0.")
elif age < 18:
print("Your admission cost is $25.")
else:
print("Your admission cost is $40.")

Your admission cost is $25.

Using Multiple elif Blocks

1
2
3
4
5
6
7
8
9
10
age = 12
if age < 4:
price = 0
elif age < 18:
price = 25
elif age < 65:
price = 40
else:
price = 20
print(f"Your admission cost is ${price}.")

Omitting the else Block

Other times, it’s clearer to use an additional elif statement that catches the specific condition of interest

1
2
3
4
5
6
7
8
9
10
age = 12
if age < 4:
price = 0
elif age < 18:
price = 25
elif age < 65:
price = 40
elif age >= 65:
price = 20
print(f"Your admission cost is ${price}.")

The else block is a catchall statement. It matches any condition that
wasn’t matched by a specific if or elif test, and that can sometimes include
invalid or even malicious data.
If you have a specific final condition you’re
testing for, consider using a final elif block and omit the else block. As a
result, you’ll be more confident that your code will run only under the correct conditions.

Testing Multiple Conditions

The if-elif-else chain is powerful, but it’s only appropriate to use when you
just need one test to pass. As soon as Python finds one test that passes, it
skips the rest of the tests.

sometimes it’s important to check all conditions of interest. In
this case, you should use a series of simple if statements with no elif or else
blocks. This technique makes sense when more than one condition could
be True, and you want to act on every condition that is True.

1
2
3
4
5
6
7
8
requested_toppings = ['mushrooms', 'extra cheese']
if 'mushrooms' in requested_toppings:
print("Adding mushrooms.")
if 'pepperoni' in requested_toppings:
print("Adding pepperoni.")
if 'extra cheese' in requested_toppings:
print("Adding extra cheese.")
print("\nFinished making your pizza!")

Adding mushrooms.
Adding extra cheese.

Finished making your pizza!

wrong:

1
2
3
4
5
6
7
8
requested_toppings = ['mushrooms', 'extra cheese']
if 'mushrooms' in requested_toppings:
print("Adding mushrooms.")
elif 'pepperoni' in requested_toppings:
print("Adding pepperoni.")
elif 'extra cheese' in requested_toppings:
print("Adding extra cheese.")
print("\nFinished making your pizza!")

Adding mushrooms.

Finished making your pizza!

Using if Statements with Lists

Checking for Special Items

1
2
3
4
5
6
7
requested_toppings = ['mushrooms', 'green peppers', 'extra cheese']
for requested_topping in requested_toppings:
if requested_topping == 'green peppers':
print("Sorry, we are out of green peppers right now.")
else:
print(f"Adding {requested_topping}.")
print("\nFinished making your pizza!")

Adding mushrooms.
Sorry, we are out of green peppers right now.
Adding extra cheese.

Finished making your pizza!

Checking That a List Is Not Empty

we won’t be able to assume
that a list has any items in it each time a loop is run. In this situation, it’s
useful to check whether a list is empty before running a for loop.

1
2
3
4
5
6
7
requested_toppings = []
if requested_toppings:
for requested_topping in requested_toppings:
print(f"Adding {requested_topping}.")
print("\nFinished making your pizza!")
else:
print("Are you sure you want a plain pizza?")

Are you sure you want a plain pizza?

Using Multiple Lists

1
2
3
4
5
6
7
8
available_toppings = ['mushrooms', 'olives', 'green peppers', 'pepperoni', 'pineapple', 'extra cheese']
requested_toppings = ['mushrooms', 'french fries', 'extra cheese']
for requested_topping in requested_toppings:
if requested_topping in available_toppings:
print(f"Adding {requested_topping}.")
else:
print(f"Sorry, we don't have {requested_topping}.")
print("\nFinished making your pizza!")

Adding mushrooms.
Sorry, we don’t have french fries.
Adding extra cheese.

Finished making your pizza!

Dictionaries

A Simple Dictionary

1
2
3
alien_0 = {'color': 'green', 'points': 5}
print(alien_0['color'])
print(alien_0['points'])

green
5

Working with Dictionaries

A dictionary in Python is a collection of key-value pairs. Each key is connected to
a value, and you can use a key to access the value associated with that key. A
key’s value can be a number, a string, a list, or even another dictionary.

a dictionary is wrapped in braces ({}) with a series of key-value
pairs inside the braces

A key-value pair is a set of values associated with each other. When you
provide a key, Python returns the value associated with that key. Every key is
connected to its value by a colon, and individual key-value pairs are separated
by commas.

Accessing Values in a Dictionary

To get the value associated with a key, give the name of the dictionary and
then place the key inside a set of square brackets

Adding New Key-Value Pairs

To add a new key-value pair, you would give the
name of the dictionary followed by the new key in square brackets, along
with the new value.

1
2
3
4
5
alien_0 = {'color': 'green', 'points': 5}
print(alien_0)
alien_0['x_position'] = 0
alien_0['y_position'] = 25
print(alien_0)

{‘color’: ‘green’, ‘points’: 5}
{‘color’: ‘green’, ‘points’: 5, ‘x_position’: 0, ‘y_position’: 25}

Dictionaries retain the order in which they were defined

Starting with an Empty Dictionary

1
2
3
4
alien_0 = {}
alien_0['color'] = 'green'
alien_0['points'] = 5
print(alien_0)

{‘color’: ‘green’, ‘points’: 5}

Modifying Values in a Dictionary

To modify a value in a dictionary, give the name of the dictionary with the
key in square brackets and then the new value you want associated with
that key.

1
2
3
4
alien_0 = {'color': 'green'}
print(f"The alien is {alien_0['color']}.")
alien_0['color'] = 'yellow'
print(f"The alien is now {alien_0['color']}.")

The alien is green.
The alien is now yellow.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
alien_0 = {'x_position': 0, 'y_position': 25, 'speed': 'medium'}
print(f"Original position: {alien_0['x_position']}")
# Move the alien to the right.
# Determine how far to move the alien based on its current speed.
if alien_0['speed'] == 'slow':
x_increment = 1
elif alien_0['speed'] == 'medium':
x_increment = 2
else:
# This must be a fast alien.
x_increment = 3
# The new position is the old position plus the increment.
alien_0['x_position'] = alien_0['x_position'] + x_increment
print(f"New position: {alien_0['x_position']}")

Original x-position: 0
New x-position: 2

Removing Key-Value Pairs

1
2
3
4
alien_0 = {'color': 'green', 'points': 5}
print(alien_0)
del alien_0['points']
print(alien_0)

A Dictionary of Similar Objects

It’s good practice to include a comma after the
last key-value pair as well, so you’re ready to add a new key-value pair on the
next line.

1
2
3
4
5
6
7
8
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'rust',
'phil': 'python',
}
language = favorite_languages['sarah'].title()
print(f"Sarah's favorite language is {language}.")

Using get() to Access Values

1
2
alien_0 = {'color': 'green', 'speed': 'slow'}
print(alien_0['points'])
1
2
3
4
5
Traceback (most recent call last):
File "alien_no_points.py", line 2, in <module>
print(alien_0['points'])
~~~~~~~^^^^^^^^^^
KeyError: 'points'

As a second optional
argument, you can pass the value to be returned if the key doesn’t exist:

1
2
3
alien_0 = {'color': 'green', 'speed': 'slow'}
point_value = alien_0.get('points', 'No point value assigned.')
print(point_value)

No point value assigned.

If you leave out the second argument in the call to get() and the key doesn’t exist, Python will return the value None. The special value None means “no value exists.” This is not an error: it’s a special value meant to indicate the absence of a value.

Looping Through a Dictionary

Looping Through All Key-Value Pairs

1
2
3
4
5
6
7
8
9
user_0 = {
'username': 'efermi',
'first': 'enrico',
'last': 'fermi',
}

for key, value in user_0.items():
print(f"\nKey: {key}")
print(f"Value: {value}")

Key: username
Value: efermi
Key: first
Value: enrico
Key: last
Value: fermi

1
2
3
4
5
6
7
8
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'rust',
'phil': 'python',
}
for name, language in favorite_languages.items():
print(f"{name.title()}'s favorite language is {language.title()}.")

Jen’s favorite language is Python.
Sarah’s favorite language is C.
Edward’s favorite language is Rust.
Phil’s favorite language is Python.

Looping Through All the Keys in a Dictionary

1
2
3
4
5
6
7
8
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'rust',
'phil': 'python',
}
for name in favorite_languages.keys():
print(name.title())

Jen
Sarah
Edward
Phil

Looping through the keys is actually the default behavior when looping
through a dictionary, so this code would have exactly the same output if you
wrote:

for name in favorite_languages:

1
2
3
4
5
6
7
8
9
favorite_languages = {
--snip--
}
friends = ['phil', 'sarah']
for name in favorite_languages.keys():
print(f"Hi {name.title()}.")
if name in friends:
language = favorite_languages[name].title()
print(f"\t{name.title()}, I see you love {language}!")

Hi Jen.
Hi Sarah.
Sarah, I see you love C!
Hi Edward.
Hi Phil.
Phil, I see you love Python!

The keys() method isn’t just for looping: it actually returns a sequence of
all the keys

1
2
3
4
5
favorite_languages = {
--snip--
}
if 'erin' not in favorite_languages.keys():
print("Erin, please take our poll!")

Erin, please take our poll!

Looping Through a Dictionary’s Keys in a Particular Order

Looping through a dictionary returns the items in the same order they
were inserted.

1
2
3
4
5
6
7
8
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'rust',
'phil': 'python',
}
for name in sorted(favorite_languages.keys()):
print(f"{name.title()}, thank you for taking the poll.")

Edward, thank you for taking the poll.
Jen, thank you for taking the poll.
Phil, thank you for taking the poll.
Sarah, thank you for taking the poll.

Looping Through All Values in a Dictionary

use the values() method to return a sequence of values without any
keys

1
2
3
4
5
6
7
8
9
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'rust',
'phil': 'python',
}
print("The following languages have been mentioned:")
for language in favorite_languages.values():
print(language.title())

The following languages have been mentioned:
Python
C
Rust
Python

To see each language chosen without repetition, we can use a set. A set
is a collection in which each item must be unique:

1
2
3
4
5
6
favorite_languages = {
--snip--
}
print("The following languages have been mentioned:")
for language in set(favorite_languages.values()):
print(language.title())

The following languages have been mentioned:
Python
C
Rust

You can build a set directly using braces and separating the elements with commas:

languages = {‘python’, ‘rust’, ‘python’, ‘c’}
languages
{‘rust’, ‘python’, ‘c’}

Unlike
lists and dictionaries, sets do not retain items in any specific order.

Nesting

store multiple dictionaries in a list, or a list of
items as a value in a dictionary. This is called nesting. You can nest dictionaries inside a list, a list of items inside a dictionary, or even a dictionary inside
another dictionary.

1
2
3
4
5
6
alien_0 = {'color': 'green', 'points': 5}
alien_1 = {'color': 'yellow', 'points': 10}
alien_2 = {'color': 'red', 'points': 15}
aliens = [alien_0, alien_1, alien_2]
for alien in aliens:
print(alien)

{‘color’: ‘green’, ‘points’: 5}
{‘color’: ‘yellow’, ‘points’: 10}
{‘color’: ‘red’, ‘points’: 15}

1
2
3
4
5
6
7
8
9
10
11
12
# Make an empty list for storing aliens.
aliens = []
# Make 30 green aliens.
for alien_number in range(30):
new_alien = {'color': 'green', 'points': 5, 'speed': 'slow'}
aliens.append(new_alien)
# Show the first 5 aliens.
for alien in aliens[:5]:
print(alien)
print("...")
# Show how many aliens have been created.
print(f"Total number of aliens: {len(aliens)}")

{‘color’: ‘green’, ‘points’: 5, ‘speed’: ‘slow’}
{‘color’: ‘green’, ‘points’: 5, ‘speed’: ‘slow’}
{‘color’: ‘green’, ‘points’: 5, ‘speed’: ‘slow’}
{‘color’: ‘green’, ‘points’: 5, ‘speed’: ‘slow’}
{‘color’: ‘green’, ‘points’: 5, ‘speed’: ‘slow’}

Total number of aliens: 30

A List in a Dictionary

1
2
3
4
5
6
7
8
9
10
# Store information about a pizza being ordered.
pizza = {
'crust': 'thick',
'toppings': ['mushrooms', 'extra cheese'],
}
# Summarize the order.
print(f"You ordered a {pizza['crust']}-crust pizza "
"with the following toppings:")
for topping in pizza['toppings']:
print(f"\t{topping}")

You ordered a thick-crust pizza with the following toppings:
mushrooms
extra cheese

1
2
3
4
5
6
7
8
9
10
favorite_languages = {
'jen': ['python', 'rust'],
'sarah': ['c'],
'edward': ['rust', 'go'],
'phil': ['python', 'haskell'],
}
for name, languages in favorite_languages.items():
print(f"\n{name.title()}'s favorite languages are:")
for language in languages:
print(f"\t{language.title()}")

Jen’s favorite languages are:
Python
Rust
Sarah’s favorite languages are:
C
Edward’s favorite languages are:
Rust
Go
Phil’s favorite languages are:
Python
Haskell

A Dictionary in a Dictionary

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
users = {
'aeinstein': {
'first': 'albert',
'last': 'einstein',
'location': 'princeton',
},
'mcurie': {
'first': 'marie',
'last': 'curie',
'location': 'paris',
},
}
for username, user_info in users.items():
print(f"\nUsername: {username}")
full_name = f"{user_info['first']} {user_info['last']}"
location = user_info['location']
print(f"\tFull name: {full_name.title()}")
print(f"\tLocation: {location.title()}")

Username: aeinstein
Full name: Albert Einstein
Location: Princeton
Username: mcurie
Full name: Marie Curie
Location: Paris

Notice that the structure of each user’s dictionary is identical. Although
not required by Python, this structure makes nested dictionaries easier to
work with. If each user’s dictionary had different keys, the code inside the
for loop would be more complicated.

User Input and while Loops

How the input() Function Works

The input() function pauses your program and waits for the user to enter
some text. Once Python receives the user’s input, it assigns that input to a
variable to make it convenient for you to work with.

message = input(“Tell me something, and I will repeat it back to you: “)
print(message)

Writing Clear Prompts

include a clear, easy-tofollow prompt that tells the user exactly what kind of information you’re
looking for. Any statement that tells the user what to enter should work.

Add a space at the end of your prompts (after the colon in the preceding example) to separate the prompt from the user’s response and to make
it clear to your user where to enter their text.

1
2
name = input("Please enter your name: ")
print(f"\nHello, {name}!")

Please enter your name: Eric
Hello, Eric!

1
2
3
4
prompt = "If you share your name, we can personalize the messages you see."
prompt += "\nWhat is your first name? "
name = input(prompt)
print(f"\nHello, {name}!")

If you share your name, we can personalize the messages you see.
What is your first name? Eric
Hello, Eric!

Using int() to Accept Numerical Input

1
2
3
4
>>> age = input("How old are you? ")
How old are you? 21
>>> age
'21'
1
2
3
4
5
6
>>> age = input("How old are you? ")
How old are you? 21
>>> age >= 18
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: '>=' not supported between instances of 'str' and 'int'

age = input(“How old are you? “)
How old are you? 21
age = int(age)
age >= 18
True

The Modulo Operator

modulo operator (%),
which divides one number by another number and returns the remainder:

1
2
3
4
5
6
number = input("Enter a number, and I'll tell you if it's even or odd: ")
number = int(number)
if number % 2 == 0:
print(f"\nThe number {number} is even.")
else:
print(f"\nThe number {number} is odd.")

Introducing while Loops

1
2
3
4
current_number = 1
while current_number <= 5:
print(current_number)
current_number += 1

Letting the User Choose When to Quit

1
2
3
4
5
6
prompt = "\nTell me something, and I will repeat it back to you:"
prompt += "\nEnter 'quit' to end the program. "
message = ""
while message != 'quit':
message = input(prompt)
print(message)

Tell me something, and I will repeat it back to you:
Enter ‘quit’ to end the program. Hello everyone!
Hello everyone!
Tell me something, and I will repeat it back to you:
Enter ‘quit’ to end the program. Hello again.
Hello again.
Tell me something, and I will repeat it back to you:
Enter ‘quit’ to end the program. quit
quit

Using a Flag

more complicated programs in
which many different events could cause the program to stop running?
trying to test all these conditions in one while
statement becomes complicated and difficult.

For a program that should run only as long as many conditions are
true, you can define one variable that determines whether or not the entire
program is active. This variable, called a flag, acts as a signal to the program. We can write our programs so they run while the flag is set to True
and stop running when any of several events sets the value of the flag to
False.

1
2
3
4
5
6
7
8
9
prompt = "\nTell me something, and I will repeat it back to you:"
prompt += "\nEnter 'quit' to end the program. "
active = True
while active:
message = input(prompt)
if message == 'quit':
active = False
else:
print(message)

Using break to Exit a Loop

To exit a while loop immediately without running any remaining code in
the loop, regardless of the results of any conditional test, use the break statement.

1
2
3
4
5
6
7
8
prompt = "\nPlease enter the name of a city you have visited:"
prompt += "\n(Enter 'quit' when you are finished.) "
while True:
city = input(prompt)
if city == 'quit':
break
else:
print(f"I'd love to go to {city.title()}!")

Using continue in a Loop

Rather than breaking out of a loop entirely without executing the rest of its
code, you can use the continue statement to return to the beginning of the
loop, based on the result of a conditional test.

1
2
3
4
5
6
current_number = 0
while current_number < 10:
current_number += 1
if current_number % 2 == 0:
continue
print(current_number)

1
3
5
7
9

Avoiding Infinite Loops

1
2
3
4
# This loop runs forever!
x = 1
while x <= 5:
print(x)

If
your program gets stuck in an infinite loop, press CTRL-C or just close the
terminal window displaying your program’s output.

Using a while Loop with Lists and Dictionaries

A for loop is effective for looping through a list, but you shouldn’t modify a list inside a for loop because Python will have trouble keeping track of
the items in the list. To modify a list as you work through it, use a while loop

Moving Items from One List to Another

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Start with users that need to be verified,
# and an empty list to hold confirmed users.
unconfirmed_users = ['alice', 'brian', 'candace']
confirmed_users = []
# Verify each user until there are no more unconfirmed users.
# Move each verified user into the list of confirmed users.
while unconfirmed_users:
current_user = unconfirmed_users.pop()
print(f"Verifying user: {current_user.title()}")
confirmed_users.append(current_user)
# Display all confirmed users.
print("\nThe following users have been confirmed:")
for confirmed_user in confirmed_users:
print(confirmed_user.title())

Verifying user: Candace
Verifying user: Brian
Verifying user: Alice

The following users have been confirmed:
Candace
Brian
Alice

Removing All Instances of Specific Values from a List

1
2
3
4
5
pets = ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']
print(pets)
while 'cat' in pets:
pets.remove('cat')
print(pets)

[‘dog’, ‘cat’, ‘dog’, ‘goldfish’, ‘cat’, ‘rabbit’, ‘cat’]
[‘dog’, ‘dog’, ‘goldfish’, ‘rabbit’]

Filling a Dictionary with User Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
responses = {}
# Set a flag to indicate that polling is active.
polling_active = True
while polling_active:
# Prompt for the person's name and response.
name = input("\nWhat is your name? ")
response = input("Which mountain would you like to climb someday? ")
# Store the response in the dictionary.
responses[name] = response
# Find out if anyone else is going to take the poll.
repeat = input("Would you like to let another person respond? (yes/ no) ")
if repeat == 'no':
polling_active = False
# Polling is complete. Show the results.
print("\n--- Poll Results ---")
for name, response in responses.items():
print(f"{name} would like to climb {response}.")

What is your name? Eric
Which mountain would you like to climb someday? Denali
Would you like to let another person respond? (yes/ no) yes
What is your name? Lynn
Which mountain would you like to climb someday? Devil’s Thumb
Would you like to let another person respond? (yes/ no) no
— Poll Results —
Eric would like to climb Denali.
Lynn would like to climb Devil’s Thumb.

Functions

Defining a Function

1
2
3
4
def greet_user():
"""Display a simple greeting."""
print("Hello!")
greet_user()

The text on the second line is a comment called a docstring, which
describes what the function does. When Python generates documentation
for the functions in your programs, it looks for a string immediately after
the function’s definition. These strings are usually enclosed in triple quotes,
which lets you write multiple lines.

Passing Information to a Function

1
2
3
4
def greet_user(username):
"""Display a simple greeting."""
print(f"Hello, {username.title()}!")
greet_user('jesse')

Hello, Jesse!

Arguments and Parameters

The variable username in the definition of greet_user() is an example of a
parameter, a piece of information the function needs to do its job. The value
‘jesse’ in greet_user(‘jesse’) is an example of an argument. An argument is
a piece of information that’s passed from a function call to a function.

Passing Arguments

Positional Arguments

def describe_pet(animal_type, pet_name):
“””Display information about a pet.”””
print(f”\nI have a {animal_type}.”)
print(f”My {animal_type}’s name is {pet_name.title()}.”)
describe_pet(‘hamster’, ‘harry’)

Multiple Function Calls

1
2
3
4
5
6
def describe_pet(animal_type, pet_name):
"""Display information about a pet."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet('hamster', 'harry')
describe_pet('dog', 'willie')

I have a hamster.
My hamster’s name is Harry.
I have a dog.
My dog’s name is Willie.

Order Matters in Positional Arguments
1
2
3
4
5
def describe_pet(animal_type, pet_name):
"""Display information about a pet."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet('harry', 'hamster')

I have a harry.
My harry’s name is Hamster.

Keyword Arguments

1
2
3
4
5
def describe_pet(animal_type, pet_name):
"""Display information about a pet."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet(animal_type='hamster', pet_name='harry')

Default Values

When writing a function, you can define a default value for each parameter.
If an argument for a parameter is provided in the function call, Python
uses the argument value. If not, it uses the parameter’s default value.

When you use default values, any parameter with a default value needs to be listed
after all the parameters that don’t have default values. This allows Python to continue interpreting positional arguments correctly.

1
2
3
4
5
def describe_pet(pet_name, animal_type='dog'):
"""Display information about a pet."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet(pet_name='willie')

I have a dog.
My dog’s name is Willie.

describe_pet(‘willie’)
describe_pet(pet_name=’harry’, animal_type=’hamster’)

Equivalent Function Calls

Because positional arguments, keyword arguments, and default values can
all be used together, you’ll often have several equivalent ways to call a function

1
2
3
4
5
6
7
8
def describe_pet(pet_name, animal_type='dog'):
# A dog named Willie.
describe_pet('willie')
describe_pet(pet_name='willie')
# A hamster named Harry.
describe_pet('harry', 'hamster')
describe_pet(pet_name='harry', animal_type='hamster')
describe_pet(animal_type='hamster', pet_name='harry')

Avoiding Argument Errors

1
2
3
4
5
def describe_pet(animal_type, pet_name):
"""Display information about a pet."""
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}.")
describe_pet()
1
2
3
4
5
6
7
Traceback (most recent call last):
File "pets.py", line 6, in <module>
describe_pet()
^^^^^^^^^^^^^^
TypeError: describe_pet() missing 2 required positional arguments:
'animal_type' and 'pet_name'

Return Values

1
2
3
4
5
6
def get_formatted_name(first_name, last_name):
"""Return a full name, neatly formatted."""
full_name = f"{first_name} {last_name}"
return full_name.title()
musician = get_formatted_name('jimi', 'hendrix')
print(musician)

Making an Argument Optional

1
2
3
4
5
6
7
8
def get_formatted_name(first_name, middle_name, last_name):
"""Return a full name, neatly formatted."""
full_name = f"{first_name} {middle_name} {last_name}"
return full_name.title()
musician = get_formatted_name('john', 'lee', 'hooker')
print(musician)
musician = get_formatted_name('jimi', 'hendrix')
print(musician)

John Lee Hooker
Jimi Hendrix

Returning a Dictionary

1
2
3
4
5
6
7
8
def build_person(first_name, last_name, age=None):
"""Return a dictionary of information about a person."""
person = {'first': first_name, 'last': last_name}
if age:
person['age'] = age
return person
musician = build_person('jimi', 'hendrix', age=27)
print(musician)

Using a Function with a while Loop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def get_formatted_name(first_name, last_name):
"""Return a full name, neatly formatted."""
full_name = f"{first_name} {last_name}"
return full_name.title()
while True:
print("\nPlease tell me your name:")
print("(enter 'q' at any time to quit)")
f_name = input("First name: ")
if f_name == 'q':
break
l_name = input("Last name: ")
if l_name == 'q':
break
formatted_name = get_formatted_name(f_name, l_name)
print(f"\nHello, {formatted_name}!")

Passing a List

1
2
3
4
5
6
7
def greet_users(names):
"""Print a simple greeting to each user in the list."""
for name in names:
msg = f"Hello, {name.title()}!"
print(msg)
usernames = ['hannah', 'ty', 'margot']
greet_users(usernames)

Hello, Hannah!
Hello, Ty!
Hello, Margot!

Modifying a List in a Function

1
2
3
4
5
6
7
8
9
10
11
12
13
# Start with some designs that need to be printed.
unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
completed_models = []
# Simulate printing each design, until none are left.
# Move each design to completed_models after printing.
while unprinted_designs:
current_design = unprinted_designs.pop()
print(f"Printing model: {current_design}")
completed_models.append(current_design)
# Display all completed models.
print("\nThe following models have been printed:")
for completed_model in completed_models:
print(completed_model)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def print_models(unprinted_designs, completed_models):
"""
Simulate printing each design, until none are left.
144 Chapter 8
Move each design to completed_models after printing.
"""
while unprinted_designs:
current_design = unprinted_designs.pop()
print(f"Printing model: {current_design}")
completed_models.append(current_design)
def show_completed_models(completed_models):
"""Show all the models that were printed."""
print("\nThe following models have been printed:")
for completed_model in completed_models:
print(completed_model)
unprinted_designs = ['phone case', 'robot pendant', 'dodecahedron']
completed_models = []
print_models(unprinted_designs, completed_models)
show_completed_models(completed_models)

Preventing a Function from Modifying a List

You can send a copy of a list to a function like this:
function_name(list_name[:])

print_models(unprinted_designs[:], completed_models)

Passing an Arbitrary Number of Arguments

1
2
3
4
5
def make_pizza(*toppings):
"""Print the list of toppings that have been requested."""
print(toppings)
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')

(‘pepperoni’,)
(‘mushrooms’, ‘green peppers’, ‘extra cheese’)

1
2
3
4
5
6
7
8
def make_pizza(*toppings):
"""Summarize the pizza we are about to make."""
Functions 147
print("\nMaking a pizza with the following toppings:")
for topping in toppings:
print(f"- {topping}")
make_pizza('pepperoni')
make_pizza('mushrooms', 'green peppers', 'extra cheese')

Making a pizza with the following toppings:

  • pepperoni
    Making a pizza with the following toppings:
  • mushrooms
  • green peppers
  • extra cheese

Mixing Positional and Arbitrary Arguments

If you want a function to accept several different kinds of arguments, the
parameter that accepts an arbitrary number of arguments must be placed
last in the function definition. Python matches positional and keyword
arguments first and then collects any remaining arguments in the final
parameter.

1
2
3
4
5
6
7
def make_pizza(size, *toppings):
"""Summarize the pizza we are about to make."""
print(f"\nMaking a {size}-inch pizza with the following toppings:")
for topping in toppings:
print(f"- {topping}")
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

Making a 16-inch pizza with the following toppings:

  • pepperoni

Making a 12-inch pizza with the following toppings:

  • mushrooms
  • green peppers
  • extra cheese

Using Arbitrary Keyword Arguments

def build_profile(first, last, **user_info):
“””Build a dictionary containing everything we know about a user.”””
user_info[‘first_name’] = first
user_info[‘last_name’] = last
return user_info
user_profile = build_profile(‘albert’, ‘einstein’,
location=’princeton’,
field=’physics’)
print(user_profile)

{‘location’: ‘princeton’, ‘field’: ‘physics’,
‘first_name’: ‘albert’, ‘last_name’: ‘einstein’}

write functions that accept as many key-value
pairs as the calling statement provides

You’ll often see the parameter name **kwargs used to collect nonspecific keyword
arguments.

Storing Your Functions in Modules

storing your functions in a separate file called a module and then importing
that module into your main program. An import statement tells Python to
make the code in a module available in the currently running program file

Importing an Entire Module

1
2
3
4
5
def make_pizza(size, *toppings):
"""Summarize the pizza we are about to make."""
print(f"\nMaking a {size}-inch pizza with the following toppings:")
for topping in toppings:
print(f"- {topping}")

import pizza
pizza.make_pizza(16, ‘pepperoni’)
pizza.make_pizza(12, ‘mushrooms’, ‘green peppers’, ‘extra cheese’)

Importing Specific Functions

from module_name import function_name

from module_name import function_0, function_1, function_2

1
2
3
from pizza import make_pizza
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

Using as to Give a Function an Alias

1
2
3
from pizza import make_pizza as mp
mp(16, 'pepperoni')
mp(12, 'mushrooms', 'green peppers', 'extra cheese')

Using as to Give a Module an Alias

1
2
3
import pizza as p
p.make_pizza(16, 'pepperoni')
p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

Importing All Functions in a Module

from pizza import *
make_pizza(16, ‘pepperoni’)
make_pizza(12, ‘mushrooms’, ‘green peppers’, ‘extra cheese’)

The best approach is to import the function or functions you want, or
import the entire module and use the dot notation. This leads to clear code
that’s easy to read and understand

Classes

Creating and Using a Class

1
2
3
4
5
6
7
8
9
10
11
12
class Dog:
"""A simple attempt to model a dog."""
def __init__(self, name, age):
"""Initialize name and age attributes."""
self.name = name
self.age = age
def sit(self):
"""Simulate a dog sitting in response to a command."""
print(f"{self.name} is now sitting.")
def roll_over(self):
"""Simulate rolling over in response to a command."""
print(f"{self.name} rolled over!")

The __init__() method is a special method
that Python runs automatically whenever we create a new instance based
on the Dog class. This method has two leading underscores and two trailing underscores, a convention that helps prevent Python’s default method
names from conflicting with your method names.

The self parameter is required in the method definition, and
it must come first, before the other parameters. It must be included in
the definition because when Python calls this method later (to create an
instance of Dog), the method call will automatically pass the self argument.
Every method call associated with an instance automatically passes self,
which is a reference to the instance itself; it gives the individual instance
access to the attributes and methods in the class

Making an Instance from a Class

1
2
3
my_dog = Dog('Willie', 6)
print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")

My dog’s name is Willie.
My dog is 6 years old.

Calling Methods

1
2
3
4
5
class Dog:
--snip--
my_dog = Dog('Willie', 6)
my_dog.sit()
my_dog.roll_over()

Willie is now sitting.
Willie rolled over!

Creating Multiple Instances

1
2
3
4
5
6
7
8
9
10
class Dog:
--snip--
my_dog = Dog('Willie', 6)
your_dog = Dog('Lucy', 3)
print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")
my_dog.sit()
print(f"\nYour dog's name is {your_dog.name}.")
print(f"Your dog is {your_dog.age} years old.")
your_dog.sit()

My dog’s name is Willie.
My dog is 6 years old.
Willie is now sitting.
Your dog’s name is Lucy.
Your dog is 3 years old.
Lucy is now sitting.

Working with Classes and Instances

1
2
3
4
5
6
7
8
9
10
11
12
13
class Car:
"""A simple attempt to represent a car."""
def __init__(self, make, model, year):
"""Initialize attributes to describe a car."""
self.make = make
self.model = model
self.year = year
def get_descriptive_name(self):
"""Return a neatly formatted descriptive name."""
long_name = f"{self.year} {self.make} {self.model}"
return long_name.title()
my_new_car = Car('audi', 'a4', 2024)
print(my_new_car.get_descriptive_name())

2024 Audi A4

Setting a Default Value for an Attribute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Car:
def __init__(self, make, model, year):
"""Initialize attributes to describe a car."""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
--snip--
def read_odometer(self):
"""Print a statement showing the car's mileage."""
print(f"This car has {self.odometer_reading} miles on it.")
my_new_car = Car('audi', 'a4', 2024)
print(my_new_car.get_descriptive_name())
my_new_car.read_odometer()

2024 Audi A4
This car has 0 miles on it.

Modifying Attribute Values

Modifying an Attribute’s Value Directly
1
2
3
4
5
6
class Car:
--snip--
my_new_car = Car('audi', 'a4', 2024)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()

2024 Audi A4
This car has 23 miles on it.

Modifying an Attribute’s Value Through a Method
1
2
3
4
5
6
7
8
class Car:
--snip--
def update_odometer(self, mileage):
"""Set the odometer reading to the given value."""
self.odometer_reading = mileage
my_new_car = Car('audi', 'a4', 2024)
my_new_car.update_odometer(23)
my_new_car.read_odometer()

2024 Audi A4
This car has 23 miles on it.

1
2
3
4
5
6
7
8
9
10
11
class Car:
--snip--
def update_odometer(self, mileage):
"""
Set the odometer reading to the given value.
Reject the change if it attempts to roll the odometer back.
"""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
Incrementing an Attribute’s Value Through a Method
1
2
3
4
5
6
7
8
9
10
11
12
13
class Car:
--snip--
def update_odometer(self, mileage):
--snip--
def increment_odometer(self, miles):
"""Add the given amount to the odometer reading."""
self.odometer_reading += miles
my_used_car = Car('subaru', 'outback', 2019)
print(my_used_car.get_descriptive_name())
2 my_used_car.update_odometer(23_500)
my_used_car.read_odometer()
my_used_car.increment_odometer(100)
my_used_car.read_odometer()

2019 Subaru Outback
This car has 23500 miles on it.
This car has 23600 miles on it.

Inheritance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Car:
"""A simple attempt to represent a car."""
def __init__(self, make, model, year):
"""Initialize attributes to describe a car."""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""Return a neatly formatted descriptive name."""
long_name = f"{self.year} {self.make} {self.model}"
return long_name.title()
def read_odometer(self):
"""Print a statement showing the car's mileage."""
print(f"This car has {self.odometer_reading} miles on it.")
def update_odometer(self, mileage):
"""Set the odometer reading to the given value."""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
"""Add the given amount to the odometer reading."""
self.odometer_reading += miles

class ElectricCar(Car):
"""Represent aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year):
"""Initialize attributes of the parent class."""
super().__init__(make, model, year)
my_leaf = ElectricCar('nissan', 'leaf', 2024)
print(my_leaf.get_descriptive_name())

2024 Nissan Leaf

Defining Attributes and Methods for the Child Class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Car:
--snip--
class ElectricCar(Car):
"""Represent aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year):
"""
Initialize attributes of the parent class.
Then initialize attributes specific to an electric car.
"""
super().__init__(make, model, year)
self.battery_size = 40
def describe_battery(self):
"""Print a statement describing the battery size."""
print(f"This car has a {self.battery_size}-kWh battery.")
my_leaf = ElectricCar('nissan', 'leaf', 2024)
print(my_leaf.get_descriptive_name())
my_leaf.describe_battery()

2024 Nissan Leaf
This car has a 40-kWh battery.

Overriding Methods from the Parent Class

the class Car had a method called fill_gas_tank(). This method is
meaningless for an all-electric vehicle, so you might want to override this
method

1
2
3
4
5
class ElectricCar(Car):
--snip--
def fill_gas_tank(self):
"""Electric cars don't have gas tanks."""
print("This car doesn't have a gas tank!")

Instances as Attributes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Battery:
"""A simple attempt to model a battery for an electric car."""
def __init__(self, battery_size=40):
"""Initialize the battery's attributes."""
self.battery_size = battery_size
def describe_battery(self):
"""Print a statement describing the battery size."""
print(f"This car has a {self.battery_size}-kWh battery.")

class ElectricCar(Car):
"""Represent aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year):
"""Initialize attributes of the parent class."""
super().__init__(make, model, year)
self.battery = Battery()


my_leaf = ElectricCar('nissan', 'leaf', 2024)
print(my_leaf.get_descriptive_name())
my_leaf.battery.describe_battery()

2024 Nissan Leaf
This car has a 40-kWh battery.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Car:
--snip--
class Battery:
--snip--
def get_range(self):
"""Print a statement about the range this battery provides."""
if self.battery_size == 40:
range = 150
elif self.battery_size == 65:
range = 225
print(f"This car can go about {range} miles on a full charge.")
class ElectricCar(Car):
--snip--
my_leaf = ElectricCar('nissan', 'leaf', 2024)
print(my_leaf.get_descriptive_name())
my_leaf.battery.describe_battery()
my_leaf.battery.get_range()

Importing Classes

Importing a Single Class

car.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"""A class that can be used to represent a car."""
class Car:
"""A simple attempt to represent a car."""
def __init__(self, make, model, year):
"""Initialize attributes to describe a car."""
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
"""Return a neatly formatted descriptive name."""
long_name = f"{self.year} {self.make} {self.model}"
return long_name.title()
def read_odometer(self):
"""Print a statement showing the car's mileage."""
print(f"This car has {self.odometer_reading} miles on it.")
def update_odometer(self, mileage):
"""Set the odometer reading to the given value."""
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print("You can't roll back an odometer!")
def increment_odometer(self, miles):
"""Add the given amount to the odometer reading."""
self.odometer_reading += miles

my_car.py

1
2
3
4
5
from car import Car
my_new_car = Car('audi', 'a4', 2024)
print(my_new_car.get_descriptive_name())
my_new_car.odometer_reading = 23
my_new_car.read_odometer()

2024 Audi A4
This car has 23 miles on it.

Storing Multiple Classes in a Module

car.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
"""A set of classes used to represent gas and electric cars."""
class Car:
--snip--

class Battery:
"""A simple attempt to model a battery for an electric car."""
def __init__(self, battery_size=40):
"""Initialize the battery's attributes."""
self.battery_size = battery_size
def describe_battery(self):
"""Print a statement describing the battery size."""
print(f"This car has a {self.battery_size}-kWh battery.")

def get_range(self):
"""Print a statement about the range this battery provides."""
if self.battery_size == 40:
range = 150
elif self.battery_size == 65:
range = 225
print(f"This car can go about {range} miles on a full charge.")

class ElectricCar(Car):
"""Represent aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year):
"""Initialize attributes of the parent class."""
super().__init__(make, model, year)
self.battery = Battery()

my_electric_car.py

1
2
3
4
5
from car import ElectricCar
my_leaf = ElectricCar('nissan', 'leaf', 2024)
print(my_leaf.get_descriptive_name())
my_leaf.battery.describe_battery()
my_leaf.battery.get_range()

2024 Nissan Leaf
This car has a 40-kWh battery.
This car can go about 150 miles on a full charge.

Importing Multiple Classes from a Module

1
2
3
4
5
from car import Car, ElectricCar
my_mustang = Car('ford', 'mustang', 2024)
print(my_mustang.get_descriptive_name())
my_leaf = ElectricCar('nissan', 'leaf', 2024)
print(my_leaf.get_descriptive_name())

2024 Ford Mustang
2024 Nissan Leaf

Importing an Entire Module0

1
2
3
4
5
import car
my_mustang = car.Car('ford', 'mustang', 2024)
print(my_mustang.get_descriptive_name())
my_leaf = car.ElectricCar('nissan', 'leaf', 2024)
print(my_leaf.get_descriptive_name())

Importing All Classes from a Module

from module_name import *

This method is not recommended for two reasons. First, it’s helpful to be
able to read the import statements at the top of a file and get a clear sense of
which classes a program uses. With this approach it’s unclear which classes
you’re using from the module. This approach can also lead to confusion
with names in the file. If you accidentally import a class with the same name
as something else in your program file, you can create errors that are hard
to diagnose.

Importing a Module into a Module

car.py

“””A class that can be used to represent a car.”””
class Car:
–snip–

electric_car.py

“””A set of classes that can be used to represent electric cars.”””
from car import Car
class Battery:
–snip–
class ElectricCar(Car):
–snip–

my_cars.py

1
2
3
4
5
6
from car import Car
from electric_car import ElectricCar
my_mustang = Car('ford', 'mustang', 2024)
print(my_mustang.get_descriptive_name())
my_leaf = ElectricCar('nissan', 'leaf', 2024)
print(my_leaf.get_descriptive_name())

Using Aliases

from electric_car import ElectricCar as EC
my_leaf = EC(‘nissan’, ‘leaf’, 2024)

import electric_car as ec
my_leaf = ec.ElectricCar(‘nissan’, ‘leaf’, 2024)

Files and Exceptions

Testing Your Code

pierian data python django

errors and exception handling

try: code to be attempted(may lead to an error)
except: code will execute in case there is an error in try block
finally: a final block of code to be executed, ragardless of an error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
try:
print('10' + 10)
except IOError:
print('you have input/output error!')
print('do you check the file permissions?')
except TypeError:
print('you are using the wrong data types!')
except:
print("there is an error!")
# else:
# print("Else block ran")
finally:
print("finally will always run, error or no error!")

object oriented programming

part one: syntax structure

1
2
3
4
5
6
7
8
class NameOfClass():
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2

def some_method(self):
#perform some action
print(self.param1)

create a class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Student():

# class attribute
planet = 'Earth'

def __init__(self, name, gpa):
self.name = name
self.gpa = gpa

stu1 = Student(name='Jose', gpa=4.0)
print(stu1) # <__main__.Student object at 0x0000026F37D5E810>
print(type(stu1)) # <class '__main__.Student'>
print(stu1.name) # Jose
stu2 = Student(name='Mini', gpa=3.5)
print(Student.planet) # Earth
print(stu1.planet) # Earth
print(stu2.planet) # Earth

methods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Circle():

pi = 3.14

def __init__(self, radius=1):
self.radius = radius

def area(self):
return self.radius * self.radius * Circle.pi
# return self.radius * self.radius * self.pi

def perimeter(self):
return self.radius * 2 * Circle.pi

def double_radius(self):
self.radius *= 2

def multiply_radius(self, number):
self.radius *= number


my_circle = Circle(radius=20)
print(my_circle.radius) # 20

my_circle.double_radius()
print(my_circle.radius) # 40

my_circle.multiply_radius(3)
print(my_circle.radius) # 120

print(my_circle.area) # <bound method Circle.area of <__main__.Circle object at 0x00000219A522EAD0>>

print(my_circle.area()) # 1256.0
print(my_circle.perimeter()) # 125.60000000000001

inheritance

create derived variations of classes through the use of inheritance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class Person():

def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name


def hello(self):
print("hello!")

def report(self):
print(f"I am {self.first_name} {self.last_name}")


x = Person("John", "Smith")

x.hello()
x.report()

class Agent(Person):

def __init__(self, first_name, last_name, code_name):
super().__init__(first_name, last_name)
# Person.__init__(first_name, last_name)
self.code_name = code_name

def report(self):
print('I am here')
# return super().report()

def reveal(self, passcode):
if passcode == '123':
print('i am a secret agent')
else:
self.report()


y = Agent('John', 'sme', '007')
y.hello()
y.report()
y.reveal('123') # i am a secret agent
y.reveal('000') # I am here

print(y.code_name) # 007

special methods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Book():

def __init__(self, title, author, pages) -> None:
self.title = title
self.author = author
self.pages = pages

def __str__(self):
return f"{self.title} written by {self.author}"

def __len__(self):
return self.pages


my_book = Book('Python Rocks!', 'Jose', 120)

# print(my_book) # <__main__.Book object at 0x00000284301FE810>
# print(len(my_book)) # TypeError: object of type 'Book' has no len()

print(my_book) # Python Rocks! written by Jose

print(len(my_book)) # 120

modules and packages

1
2
3
4
5
6
7
8
9
from mymodule import useful_func, UsefulClass
# from mymodule import UsefulClass
from mypackage.mysubmodule import my_sub_func

useful_func() # Using the useful_func

my_usefull_object = UsefulClass('hello')
my_usefull_object.report() # hello
my_sub_func() # using a functiong from mysubmodule.py

mymodule.py

1
2
3
4
5
6
7
8
9
10
11
def useful_func():
print("Using the useful_func")

class UsefulClass():

def __init__(self, message) -> None:
self.message = message


def report(self):
print(self.message)

mypackage -> __init__.py

mypackage -> mysubmodule.py

1
2
def my_sub_func():
print('using a functiong from mysubmodule.py')

django

Alt text

first django project

django-admin startproject my_site_1

python manage.py runserver
python manage.py runserver 8080

django applications

a sub-component of a single django project(web application)

Alt text

python manage.py startapp app_name

views, routing, and urls

path()

  • urlpattern
  • view
  • name
  • kwargs

urlpatterns = [
path(‘’, home_view, name=’homepage’),]

dynamic views and logic

responses and 404

1
2
3
4
5
6
7
8
9
def news_view(request, topic):
try:
result = articles[topic]
return HttpResponse(articles[topic])
except:
# result = 'No page for that topic'
# return HttpResponseNotFound(result)
raise Http404("404 GENERIC ERROR!")
# return HttpResponse(articles[topic])

url names and reverse

mosh python

Alt text

Alt text

expression : a statement get a result

primitive type

boolean only -> False True

string

1
2
3
4
5
6
7
message = """
dasf
as dg
adgs
asdg asdf
adsf
"""
1
2
str1 = "hello"
str1[0]
1
2
3
4
5
first = "Mosh"
last = "Hamedani"
full = f"{first + last}"

print(full)
1
2
3
4
5
str1 = "Hello world"

str1.find("lo")
if "lo" in course:
pass
1
2
3
4
abs(-2.9)

import math
math.ceil(2.2)

falsy -> bool()
“”
0
None


ternary operator

1
2
3
4
5
6
7
8
age = 22
# if age >= 18:
# message = "Eligible"
# else:
# message = "Not eligible"

message = "Eligible" if age >= 18 else "Not eligible"
print(message)

short circule

1
2
if high_income and good_credit and not student:
pass

如果high_income 是FALSE,good_credit 根本没有进行判断

“b” > “a” -> True

iterable

for x in “hello”
pass

function default return None


class level attribute

1
2
3
4
5
6
7
8
9
10
11


class Point:
default_color = "red"
def __init__(self):
pass

point = Point()
print(point.default_color)
print(Point.default_color)

class method

1
2
3
4
5
6
7
8
9
10
class Point:
def __init__(self, x, y):
pass

@classmethod
def zero(cls):
return cls(0, 0) # Point(0, 0)
pass

point = Point.zero()
1
2
3
4
5
6
7
8
9
10
11
class Point:
def __init__(self, x, y):
self.x = x
self.y = y

def __str__(self):
return f"({self.x}, {self.y})"

point = Point(1, 2)
print(point)
print(str(point))

python 100 days

语言元素

变量和类型

整型:支持二进制(如0b100,换算成十进制是4)、八进制(如0o100,换算成十进制是64)、十进制(100)和十六进制(0x100,换算成十进制是256)的表示法。

浮点型:支持科学计数法(如1.23456e2)。

字符串型:字符串是以单引号或双引号括起来的任意文本,比如’hello’和”hello”,字符串还有原始字符串表示法、字节字符串表示法、Unicode字符串表示法,而且可以书写成多行的形式(用三个单引号或三个双引号开头,三个单引号或三个双引号结尾)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"""
使用type()检查变量的类型

Version: 0.1
Author: 骆昊
"""
a = 100
b = 12.345
c = 1 + 5j
d = 'hello, world'
e = True
print(type(a)) # <class 'int'>
print(type(b)) # <class 'float'>
print(type(c)) # <class 'complex'>
print(type(d)) # <class 'str'>
print(type(e)) # <class 'bool'>

可以使用Python中内置的函数对变量类型进行转换。

int():将一个数值或字符串转换成整数,可以指定进制。
float():将一个字符串转换成浮点数。
str():将指定的对象转换成字符串形式,可以指定编码。
chr():将整数转换成该编码对应的字符串(一个字符)。
ord():将字符串(一个字符)转换成对应的编码(整数)。

变量命名

硬性规则:

  • 变量名由字母(广义的Unicode字符,不包括特殊字符)、数字和下划线构成,数字不能开头。
  • 大小写敏感(大写的a和小写的A是两个不同的变量)。
  • 不要跟关键字(有特殊含义的单词,后面会讲到)和系统保留字(如函数、模块等的名字)冲突。

PEP 8要求:

  • 用小写字母拼写,多个单词用下划线连接。
  • 受保护的实例属性用单个下划线开头。
  • 私有的实例属性用两个下划线开头。
运算符 描述
[] [:] 下标,切片
** 指数
~ + - 按位取反, 正负号
* / % // 乘,除,模,整除
+ - 加,减
>> << 右移,左移
& 按位与
^ | 按位异或,按位或
<= < > >= 小于等于,小于,大于,大于等于
== != 等于,不等于
is is not 身份运算符
in not in 成员运算符
not or and 逻辑运算符
= += -=
*= /= %=
//= **= &=
|= ^= >>= <<= (复合)赋值运算符
运算符 描述 实例
& 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 (a & b) 输出结果 12 ,二进制解释: 0000 1100
按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。
^ 按位异或运算符:当两对应的二进位相异时,结果为1 (a ^ b) 输出结果 49 ,二进制解释: 0011 0001
~ 按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1 。~x 类似于 -x-1 (~a ) 输出结果 -61 ,二进制解释: 1100 0011,在一个有符号二进制数的补码形式。
<< 左移动运算符:运算数的各二进位全部左移若干位,由 << 右边的数字指定了移动的位数,高位丢弃,低位补0。 a << 2 输出结果 240 ,二进制解释: 1111 0000
>> 右移动运算符:把”>>”左边的运算数的各二进位全部右移若干位,>> 右边的数字指定了移动的位数 a >> 2 输出结果 15 ,二进制解释: 0000 1111
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
a = 60            # 60 = 0011 1100 
b = 13 # 13 = 0000 1101
c = 0

c = a & b; # 12 = 0000 1100

c = a | b; # 61 = 0011 1101

c = a ^ b; # 49 = 0011 0001


c = ~a; # -61 = 1100 0011

c = a << 2; # 240 = 1111 0000

c = a >> 2; # 15 = 0000 1111

身份运算符用于比较两个对象的存储单元

is 是判断两个标识符是不是引用自一个对象
x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False

注: id() 函数用于获取对象内存地址。

比较运算符和逻辑运算符

在and运算符左边为False的情况下,右边的表达式根本不会执行。

or运算符也是有短路功能的,在它左边的布尔值为True的情况下,右边的表达式根本不会执行。

print(f'{f:.1f}华氏度 = {c:.1f}摄氏度')
其中{f:.1f}{c:.1f}可以先看成是{f}{c},表示输出时会用变量f和变量c的值替换掉这两个占位符,后面的:.1f表示这是一个浮点数,小数点后保留1位有效数字。

1
2
3
f = float(input('请输入华氏温度: '))
c = (f - 32) / 1.8
print('%.1f华氏度 = %.1f摄氏度' % (f, c))

print函数中的字符串%.1f是一个占位符,稍后会由一个float类型的变量值替换掉它。同理,如果字符串中有%d,后面可以用一个int类型的变量值替换掉它,而%s会被字符串的值替换掉。

1
2
3
4
5
6
7
8
9
"""
输入年份 如果是闰年输出True 否则输出False

"""
year = int(input('请输入年份: '))
# 如果代码太长写成一行不便于阅读 可以使用\对代码进行折行
is_leap = year % 4 == 0 and year % 100 != 0 or \
year % 400 == 0
print(is_leap)

循环结构

break关键字来提前终止循环,需要注意的是break只能终止它所在的那个循环,这一点在使用嵌套的循环结构需要引起注意。除了break之外,还有另一个关键字是continue,它可以用来放弃本次循环后续的代码直接让循环进入下一轮。

sqrt() function is an inbuilt function in Python programming language that returns the square root of any number. Syntax: math.sqrt(x) Parameter: x is any number such that x>=0 Returns: It returns the square root of the number passed in the parameter. Error: When x<0 it does not executes due to a runtime error.

最大公因数,也称最大公约数、最大公因子,指两个或多个整数共有约数中最大的一个。
两个或多个整数公有的倍数叫做它们的公倍数,其中除0以外最小的一个公倍数就叫做这几个整数的最小公倍数。
最小公倍数=两数的乘积/最大公约(因)数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"""
输入两个正整数计算它们的最大公约数和最小公倍数
"""

x = int(input('x = '))
y = int(input('y = '))
# 如果x大于y就交换x和y的值
if x > y:
# 通过下面的操作将y的值赋给x, 将x的值赋给y
x, y = y, x
# 从两个数中较小的数开始做递减的循环
for factor in range(x, 0, -1):
if x % factor == 0 and y % factor == 0:
print('%d和%d的最大公约数是%d' % (x, y, factor))
print('%d和%d的最小公倍数是%d' % (x, y, x * y // factor))
break

函数和模块的使用

在Python中,函数的参数可以有默认值,也支持使用可变参数,所以Python并不需要像其他语言一样支持函数的重载

函数重载(英语:function overloading)或方法重载,是某些编程语言(如 C++、C#、Java、Swift、Kotlin 等)具有的一项特性,该特性允许创建多个具有不同实现的同名函数。对重载函数的调用会运行其适用于调用上下文的具体实现,即允许一个函数调用根据上下文执行不同的任务。

例如,doTask() 和 doTask(object o) 是重载函数。调用后者,必须传入一个 object 作为参数,而调用前者时则不需要参数。

用模块管理函数

module1.py

1
2
def foo():
print('hello, world!')

module2.py

1
2
def foo():
print('goodbye, world!')

test.py

1
2
3
4
5
import module1 as m1
import module2 as m2

m1.foo()
m2.foo()

如果我们导入的模块除了定义函数之外还有可以执行代码,那么Python解释器在导入这个模块时就会执行这些代码,事实上我们可能并不希望如此,因此如果我们在模块中编写了执行代码,最好是将这些执行代码放入如下所示的条件中,这样的话除非直接运行该模块,if条件下的这些代码是不会执行的,因为只有直接执行的模块的名字才是"__main__"

module3.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def foo():
pass


def bar():
pass


# __name__是Python中一个隐含的变量它代表了模块的名字
# 只有被Python解释器直接执行的模块的名字才是__main__
if __name__ == '__main__':
print('call foo()')
foo()
print('call bar()')
bar()

test.py

1
2
3
import module3

# 导入module3时 不会执行模块中if条件成立时的代码 因为模块的名字是module3而不是__main__

变量的作用域

Python查找一个变量时会按照“局部作用域”、“嵌套作用域”、“全局作用域”和“内置作用域”的顺序进行搜索.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def foo():
b = 'hello'

# Python中可以在函数内部再定义函数
def bar():
c = True
print(a)
print(b)
print(c)

bar()
# print(c) # NameError: name 'c' is not defined


if __name__ == '__main__':
a = 100
# print(b) # NameError: name 'b' is not defined
foo()

代码的if分支中定义了一个变量a,这是一个全局变量(global variable),属于全局作用域,因为它没有定义在任何一个函数中。在上面的foo函数中我们定义了变量b,这是一个定义在函数中的局部变量(local variable),属于局部作用域,在foo函数的外部并不能访问到它;但对于foo函数内部的bar函数来说,变量b属于嵌套作用域,在bar函数中我们是可以访问到它的。
bar函数中的变量c属于局部作用域,在bar函数之外是无法访问的。

“内置作用域”就是Python内置的那些标识符,我们之前用过的input、print、int等都属于内置作用域。

global关键字来指示foo函数中的变量a来自于全局作用域,如果全局作用域中没有a,那么下面一行的代码就会定义变量a并将其置于全局作用域。同理,如果我们希望函数内部的函数能够修改嵌套作用域中的变量,可以使用nonlocal关键字来指示变量来自于嵌套作用域,请大家自行试验。

1
2
3
4
5
6
7
def main():
# Todo: Add your code here
pass


if __name__ == '__main__':
main()

字符串和常用数据结构

在\后面还可以跟一个八进制或者十六进制数来表示字符,例如\141和\x61都代表小写字母a,前者是八进制的表示法,后者是十六进制的表示法。也可以在\后面跟Unicode字符编码来表示字符,例如\u9a86\u660a代表的是中文“骆昊”。

raw string

如果不希望字符串中的\表示转义,我们可以通过在字符串的最前面加上字母r来加以说明

To include the newline character in the string, prefix the string variable with r or R to create a raw string:

raw_s = r'Hi\nHello'

print(raw_s)
The output is:

Hi\nHello

Including Double Backslash Characters in a String Using Raw String


1
2
str2 = 'abc123456'
print(str2[::-1]) # 654321cba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
s1 = 'hello ' * 3
print(s1) # hello hello hello
s2 = 'world'
s1 += s2
print(s1) # hello hello hello world
print('ll' in s1) # True
print('good' in s1) # False
str2 = 'abc123456'
# 从字符串中取出指定位置的字符(下标运算)
print(str2[2]) # c
# 字符串切片(从指定的开始索引到指定的结束索引)
print(str2[2:5]) # c12
print(str2[2:]) # c123456
print(str2[2::2]) # c246
print(str2[::2]) # ac246
print(str2[::-1]) # 654321cba
print(str2[-3:-1]) # 45
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
str1 = 'hello, world!'
# 通过内置函数len计算字符串的长度
print(len(str1)) # 13
# 获得字符串首字母大写的拷贝
print(str1.capitalize()) # Hello, world!
# 获得字符串每个单词首字母大写的拷贝
print(str1.title()) # Hello, World!
# 获得字符串变大写后的拷贝
print(str1.upper()) # HELLO, WORLD!
# 从字符串中查找子串所在位置
print(str1.find('or')) # 8
print(str1.find('shit')) # -1
# 与find类似但找不到子串时会引发异常
# print(str1.index('or'))
# print(str1.index('shit'))
# 检查字符串是否以指定的字符串开头
print(str1.startswith('He')) # False
print(str1.startswith('hel')) # True
# 检查字符串是否以指定的字符串结尾
print(str1.endswith('!')) # True
# 将字符串以指定的宽度居中并在两侧填充指定的字符
print(str1.center(50, '*'))
# 将字符串以指定的宽度靠右放置左侧填充指定的字符
print(str1.rjust(50, ' '))
str2 = 'abc123456'
# 检查字符串是否由数字构成
print(str2.isdigit()) # False
# 检查字符串是否以字母构成
print(str2.isalpha()) # False
# 检查字符串是否以数字和字母构成
print(str2.isalnum()) # True
str3 = ' jackfrued@126.com '
print(str3)
# 获得字符串修剪左右两侧空格之后的拷贝
print(str3.strip())

1
2
3
a, b = 5, 10
print('{0} * {1} = {2}'.format(a, b, a * b))
print(f'{a} * {b} = {a * b}')

常用数据结构

1
2
3
4
5
6
7
8
9
10
list1 = [1, 3, 5, 7, 100]
# 通过循环用下标遍历列表元素
for index in range(len(list1)):
print(list1[index])
# 通过for循环遍历列表元素
for elem in list1:
print(elem)
# 通过enumerate函数处理列表之后再遍历可以同时获得元素索引和值
for index, elem in enumerate(list1):
print(index, elem)

向列表中添加元素以及如何从列表中移除元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
list1 = [1, 3, 5, 7, 100]
# 添加元素
list1.append(200)
list1.insert(1, 400)
# 合并两个列表
# list1.extend([1000, 2000])
list1 += [1000, 2000]
print(list1) # [1, 400, 3, 5, 7, 100, 200, 1000, 2000]
print(len(list1)) # 9
# 先通过成员运算判断元素是否在列表中,如果存在就删除该元素
if 3 in list1:
list1.remove(3)
if 1234 in list1:
list1.remove(1234)
print(list1) # [1, 400, 5, 7, 100, 200, 1000, 2000]
# 从指定的位置删除元素
list1.pop() #最后一个
list1.pop(0)
list1.pop(len(list1) - 1)
print(list1) # [400, 5, 7, 100, 200, 1000]
# 清空列表元素
list1.clear()
print(list1) # []

列表的排序操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
list1 = ['orange', 'apple', 'zoo', 'internationalization', 'blueberry']
list2 = sorted(list1)
# sorted函数返回列表排序后的拷贝不会修改传入的列表
# 函数的设计就应该像sorted函数一样尽可能不产生副作用
list3 = sorted(list1, reverse=True)
# 通过key关键字参数指定根据字符串长度进行排序而不是默认的字母表顺序
list4 = sorted(list1, key=len)
print(list1)
print(list2)
print(list3)
print(list4)
# 给列表对象发出排序消息直接在列表对象上进行排序
list1.sort(reverse=True)
print(list1)

生成式和生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sys
f = [x for x in range(1, 10)]
print(f)
f = [x + y for x in 'ABCDE' for y in '1234567']
print(f)
# 用列表的生成表达式语法创建列表容器
# 用这种语法创建列表之后元素已经准备就绪所以需要耗费较多的内存空间
f = [x ** 2 for x in range(1, 1000)]
print(sys.getsizeof(f)) # 查看对象占用内存的字节数
print(f)
# 请注意下面的代码创建的不是一个列表而是一个生成器对象
# 通过生成器可以获取到数据但它不占用额外的空间存储数据
# 每次需要数据的时候就通过内部的运算得到数据(需要花费额外的时间)
f = (x ** 2 for x in range(1, 1000))
print(sys.getsizeof(f)) # 相比生成式生成器不占用存储数据的空间
print(f)
for val in f:
print(val)

通过yield关键字将一个普通函数改造成生成器函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def fib(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
yield a


def main():
for val in fib(20):
print(val)


if __name__ == '__main__':
main()
1
2
3
4
5
6
# instead of doing:
temp = a
a = b
b = temp
# do this:
a, b = b, a

使用集合

Python中的集合跟数学上的集合是一致的,不允许有重复元素,而且可以进行交集、并集、差集等运算。

字典

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 创建字典的字面量语法
scores = {'骆昊': 95, '白元芳': 78, '狄仁杰': 82}
print(scores)

# 创建字典的构造器语法
items1 = dict(one=1, two=2, three=3, four=4)
# 通过zip函数将两个序列压成字典
items2 = dict(zip(['a', 'b', 'c'], '123'))
# 创建字典的推导式语法
items3 = {num: num ** 2 for num in range(1, 10)}
print(items1, items2, items3)


# 通过键可以获取字典中对应的值
print(scores['骆昊'])
print(scores['狄仁杰'])
# 对字典中所有键值对进行遍历
for key in scores:
print(f'{key}: {scores[key]}')
# 更新字典中的元素
scores['白元芳'] = 65
scores['诸葛王朗'] = 71
scores.update(冷面=67, 方启鹤=85)
print(scores)
if '武则天' in scores:
print(scores['武则天'])
print(scores.get('武则天'))
# get方法也是通过键获取对应的值但是可以设置默认值
print(scores.get('武则天', 60))
# 删除字典中的元素
print(scores.popitem())
print(scores.popitem())
print(scores.pop('骆昊', 100))
# 清空字典
scores.clear()
print(scores)

index = pos if has_dot else pos + 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def get_suffix(filename, has_dot=False):
"""
获取文件名的后缀名

:param filename: 文件名
:param has_dot: 返回的后缀名是否需要带点
:return: 文件的后缀名
"""
pos = filename.rfind('.')
if 0 < pos < len(filename) - 1:
index = pos if has_dot else pos + 1
return filename[index:]
else:
return ''

面向对象编程基础

属性到底具有怎样的访问权限(也称为可见性)。因为在很多面向对象编程语言中,我们通常会将对象的属性设置为私有的(private)或受保护的(protected),简单的说就是不允许外界访问,而对象的方法通常都是公开的(public),因为公开的方法就是对象能够接受的消息。

在Python中,属性和方法的访问权限只有两种,也就是公开的和私有的,如果希望属性是私有的,在给属性命名时可以用两个下划线作为开头

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Test:

def __init__(self, foo):
self.__foo = foo

def __bar(self):
print(self.__foo)
print('__bar')


def main():
test = Test('hello')
# AttributeError: 'Test' object has no attribute '__bar'
test.__bar()
# AttributeError: 'Test' object has no attribute '__foo'
print(test.__foo)


if __name__ == "__main__":
main()

但是,Python并没有从语法上严格保证私有属性或方法的私密性,它只是给私有的属性和方法换了一个名字来妨碍对它们的访问,事实上如果你知道更换名字的规则仍然可以访问到它们

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Test:

def __init__(self, foo):
self.__foo = foo

def __bar(self):
print(self.__foo)
print('__bar')


def main():
test = Test('hello')
test._Test__bar()
print(test._Test__foo)


if __name__ == "__main__":
main()

不建议将属性设置为私有的,因为这会导致子类无法访问(后面会讲到)。所以大多数Python程序员会遵循一种命名惯例就是让属性名以单下划线开头来表示属性是受保护的,本类之外的代码在访问这样的属性时应该要保持慎重。这种做法并不是语法上的规则,单下划线开头的属性和方法外界仍然是可以访问的,所以更多的时候它是一种暗示或隐喻

封装

封装的理解是”隐藏一切可以隐藏的实现细节,只向外界暴露(提供)简单的编程接口”

面向对象进阶

通过属性的getter(访问器)和setter(修改器)方法进行对应的操作。如果要做到这点,就可以考虑使用@property包装器来包装getter和setter方法,使得对属性的访问既安全又方便

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Person(object):

def __init__(self, name, age):
self._name = name
self._age = age

# 访问器 - getter方法
@property
def name(self):
return self._name

# 访问器 - getter方法
@property
def age(self):
return self._age

# 修改器 - setter方法
@age.setter
def age(self, age):
self._age = age

def play(self):
if self._age <= 16:
print('%s正在玩飞行棋.' % self._name)
else:
print('%s正在玩斗地主.' % self._name)


def main():
person = Person('王大锤', 12)
person.play()
person.age = 22
person.play()
# person.name = '白元芳' # AttributeError: can't set attribute


if __name__ == '__main__':
main()

slots

Python是一门动态语言。通常,动态语言允许我们在程序运行时给对象绑定新的属性或方法,当然也可以对已经绑定的属性和方法进行解绑定。但是如果我们需要限定自定义类型的对象只能绑定某些属性,可以通过在类中定义__slots__变量来进行限定。需要注意的是__slots__的限定只对当前类的对象生效,对子类并不起任何作用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Person(object):

# 限定Person对象只能绑定_name, _age和_gender属性
__slots__ = ('_name', '_age', '_gender')

def __init__(self, name, age):
self._name = name
self._age = age

@property
def name(self):
return self._name

@property
def age(self):
return self._age

@age.setter
def age(self, age):
self._age = age

def play(self):
if self._age <= 16:
print('%s正在玩飞行棋.' % self._name)
else:
print('%s正在玩斗地主.' % self._name)


def main():
person = Person('王大锤', 22)
person.play()
person._gender = '男'
# AttributeError: 'Person' object has no attribute '_is_gay'
# person._is_gay = True

静态方法和类方法

先写一个方法来验证三条边长是否可以构成三角形,这个方法很显然就不是对象方法,因为在调用这个方法时三角形对象尚未创建出来(因为都不知道三条边能不能构成三角形),所以这个方法是属于三角形类而并不属于三角形对象的。我们可以使用静态方法来解决这类问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from math import sqrt


class Triangle(object):

def __init__(self, a, b, c):
self._a = a
self._b = b
self._c = c

@staticmethod
def is_valid(a, b, c):
return a + b > c and b + c > a and a + c > b

def perimeter(self):
return self._a + self._b + self._c

def area(self):
half = self.perimeter() / 2
return sqrt(half * (half - self._a) *
(half - self._b) * (half - self._c))


def main():
a, b, c = 3, 4, 5
# 静态方法和类方法都是通过给类发消息来调用的
if Triangle.is_valid(a, b, c):
t = Triangle(a, b, c)
print(t.perimeter())
# 也可以通过给类发消息来调用对象方法但是要传入接收消息的对象作为参数
# print(Triangle.perimeter(t))
print(t.area())
# print(Triangle.area(t))
else:
print('无法构成三角形.')


if __name__ == '__main__':
main()

在类中定义类方法,类方法的第一个参数约定名为cls,它代表的是当前类相关的信息的对象(类本身也是一个对象,有的地方也称之为类的元数据对象),通过这个参数我们可以获取和类相关的信息并且可以创建出类的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from time import time, localtime, sleep


class Clock(object):
"""数字时钟"""

def __init__(self, hour=0, minute=0, second=0):
self._hour = hour
self._minute = minute
self._second = second

@classmethod
def now(cls):
ctime = localtime(time())
return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec)

def run(self):
"""走字"""
self._second += 1
if self._second == 60:
self._second = 0
self._minute += 1
if self._minute == 60:
self._minute = 0
self._hour += 1
if self._hour == 24:
self._hour = 0

def show(self):
"""显示时间"""
return '%02d:%02d:%02d' % \
(self._hour, self._minute, self._second)


def main():
# 通过类方法创建对象并获取系统时间
clock = Clock.now()
while True:
print(clock.show())
sleep(1)
clock.run()


if __name__ == '__main__':
main()

类之间的关系

Alt text

在已有类的基础上创建新类,这其中的一种做法就是让一个类从另一个类那里将属性和方法直接继承下来,从而减少重复代码的编写。提供继承信息的我们称之为父类,也叫超类或基类;得到继承信息的我们称之为子类,也叫派生类或衍生类。子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法,所以子类比父类拥有的更多的能力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
class Person(object):
"""人"""

def __init__(self, name, age):
self._name = name
self._age = age

@property
def name(self):
return self._name

@property
def age(self):
return self._age

@age.setter
def age(self, age):
self._age = age

def play(self):
print('%s正在愉快的玩耍.' % self._name)

def watch_av(self):
if self._age >= 18:
print('%s正在观看爱情动作片.' % self._name)
else:
print('%s只能观看《熊出没》.' % self._name)


class Student(Person):
"""学生"""

def __init__(self, name, age, grade):
super().__init__(name, age)
self._grade = grade

@property
def grade(self):
return self._grade

@grade.setter
def grade(self, grade):
self._grade = grade

def study(self, course):
print('%s的%s正在学习%s.' % (self._grade, self._name, course))


class Teacher(Person):
"""老师"""

def __init__(self, name, age, title):
super().__init__(name, age)
self._title = title

@property
def title(self):
return self._title

@title.setter
def title(self, title):
self._title = title

def teach(self, course):
print('%s%s正在讲%s.' % (self._name, self._title, course))


def main():
stu = Student('王大锤', 15, '初三')
stu.study('数学')
stu.watch_av()
t = Teacher('骆昊', 38, '砖家')
t.teach('Python程序设计')
t.watch_av()


if __name__ == '__main__':
main()

用子类对象去替换掉一个父类对象,这是面向对象编程中一个常见的行为,对应的原则称之为里氏替换原则。

子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写(override)。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态(poly-morphism)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from abc import ABCMeta, abstractmethod


class Pet(object, metaclass=ABCMeta):
"""宠物"""

def __init__(self, nickname):
self._nickname = nickname

@abstractmethod
def make_voice(self):
"""发出声音"""
pass


class Dog(Pet):
"""狗"""

def make_voice(self):
print('%s: 汪汪汪...' % self._nickname)


class Cat(Pet):
"""猫"""

def make_voice(self):
print('%s: 喵...喵...' % self._nickname)


def main():
pets = [Dog('旺财'), Cat('凯蒂'), Dog('大黄')]
for pet in pets:
pet.make_voice()


if __name__ == '__main__':
main()

将Pet类处理成了一个抽象类,所谓抽象类就是不能够创建对象的类,这种类的存在就是专门为了让其他类去继承它。

Dog和Cat两个子类分别对Pet类中的make_voice抽象方法进行了重写并给出了不同的实现版本,当我们在main函数中调用该方法时,这个方法就表现出了多态行为(同样的方法做了不同的事情)。

python从语法层面并没有像Java或C#那样提供对抽象类的支持,但是我们可以通过abc模块的ABCMeta元类和abstractmethod包装器来达到抽象类的效果,如果一个类中存在抽象方法那么这个类就不能够实例化(创建对象)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
"""
某公司有三种类型的员工 分别是部门经理、程序员和销售员
需要设计一个工资结算系统 根据提供的员工信息来计算月薪
部门经理的月薪是每月固定15000元
程序员的月薪按本月工作时间计算 每小时150元
销售员的月薪是1200元的底薪加上销售额5%的提成
"""
from abc import ABCMeta, abstractmethod


class Employee(object, metaclass=ABCMeta):
"""员工"""

def __init__(self, name):
"""
初始化方法

:param name: 姓名
"""
self._name = name

@property
def name(self):
return self._name

@abstractmethod
def get_salary(self):
"""
获得月薪

:return: 月薪
"""
pass


class Manager(Employee):
"""部门经理"""

def get_salary(self):
return 15000.0


class Programmer(Employee):
"""程序员"""

def __init__(self, name, working_hour=0):
super().__init__(name)
self._working_hour = working_hour

@property
def working_hour(self):
return self._working_hour

@working_hour.setter
def working_hour(self, working_hour):
self._working_hour = working_hour if working_hour > 0 else 0

def get_salary(self):
return 150.0 * self._working_hour


class Salesman(Employee):
"""销售员"""

def __init__(self, name, sales=0):
super().__init__(name)
self._sales = sales

@property
def sales(self):
return self._sales

@sales.setter
def sales(self, sales):
self._sales = sales if sales > 0 else 0

def get_salary(self):
return 1200.0 + self._sales * 0.05


def main():
emps = [
Manager('刘备'), Programmer('诸葛亮'),
Manager('曹操'), Salesman('荀彧'),
Salesman('吕布'), Programmer('张辽'),
Programmer('赵云')
]
for emp in emps:
if isinstance(emp, Programmer):
emp.working_hour = int(input('请输入%s本月工作时间: ' % emp.name))
elif isinstance(emp, Salesman):
emp.sales = float(input('请输入%s本月销售额: ' % emp.name))
# 同样是接收get_salary这个消息但是不同的员工表现出了不同的行为(多态)
print('%s本月工资为: ¥%s元' %
(emp.name, emp.get_salary()))


if __name__ == '__main__':
main()

图形用户界面和游戏开发

基本上使用tkinter来开发GUI应用需要以下5个步骤:

  • 导入tkinter模块中我们需要的东西。
  • 创建一个顶层窗口对象并用它来承载整个GUI应用。
  • 在顶层窗口对象上添加GUI组件。
  • 通过代码将这些GUI组件的功能组织起来。
  • 进入主事件循环(main loop)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import tkinter
import tkinter.messagebox


def main():
flag = True

# 修改标签上的文字
def change_label_text():
nonlocal flag
flag = not flag
color, msg = ('red', 'Hello, world!')\
if flag else ('blue', 'Goodbye, world!')
label.config(text=msg, fg=color)

# 确认退出
def confirm_to_quit():
if tkinter.messagebox.askokcancel('温馨提示', '确定要退出吗?'):
window.quit()

# 创建顶层窗口
window = tkinter.Tk()
# 设置窗口大小
window.geometry('240x160')
# 设置窗口标题
window.title('小游戏')
# 创建标签对象并添加到顶层窗口
label = tkinter.Label(window, text='Hello, world!', font='Arial -32', fg='red')
label.pack(expand=1)
# 创建一个装按钮的容器
panel = tkinter.Frame(window)
# 创建按钮对象 指定添加到哪个容器中 通过command参数绑定事件回调函数
button1 = tkinter.Button(panel, text='修改', command=change_label_text)
button1.pack(side='left')
button2 = tkinter.Button(panel, text='退出', command=confirm_to_quit)
button2.pack(side='right')
panel.pack(side='bottom')
# 开启主事件循环
tkinter.mainloop()


if __name__ == '__main__':
main()

文件和异常

操作模式 具体含义
'r' 读取 (默认)
'w' 写入(关闭文件之后,会先截断/删除之前的内容)
'x' 写入,如果文件已经存在会产生异常
'a' 追加,将内容写入到已有文件的末尾
'b' 二进制模式
't' 文本模式(默认)
'+' 更新(既可以读又可以写)

如果open函数指定的文件并不存在或者无法打开,那么将引发异常状况导致程序崩溃。为了让代码有一定的健壮性和容错性,我们可以使用Python的异常机制对可能在运行时发生状况的代码进行适当的处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def main():
f = None
try:
f = open('致橡树.txt', 'r', encoding='utf-8')
print(f.read())
except FileNotFoundError:
print('无法打开指定的文件!')
except LookupError:
print('指定了未知的编码!')
except UnicodeDecodeError:
print('读取文件时解码错误!')
finally:
if f:
f.close()


if __name__ == '__main__':
main()

调用了sys模块的exit函数退出Python环境,finally块都会被执行,因为exit函数实质上是引发了SystemExit异常)

由于finally块的代码不论程序正常还是异常都会执行到,因此我们通常把finally块称为“总是执行代码块”,它最适合用来做释放外部资源的操作。如果不愿意在finally代码块中关闭文件对象释放资源,也可以使用上下文语法,通过with关键字指定文件对象的上下文环境并在离开上下文环境时自动释放文件资源,代码如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def main():
try:
with open('致橡树.txt', 'r', encoding='utf-8') as f:
print(f.read())
except FileNotFoundError:
print('无法打开指定的文件!')
except LookupError:
print('指定了未知的编码!')
except UnicodeDecodeError:
print('读取文件时解码错误!')


if __name__ == '__main__':
main()

除了使用文件对象的read方法读取文件之外,还可以使用for-in循环逐行读取或者用readlines方法将文件按行读取到一个列表容器中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import time


def main():
# 一次性读取整个文件内容
with open('致橡树.txt', 'r', encoding='utf-8') as f:
print(f.read())

# 通过for-in循环逐行读取
with open('致橡树.txt', mode='r') as f:
for line in f:
print(type(line)) #str
print(line, end='')
time.sleep(0.5)
print()

# 读取文件按行读取到列表中
with open('致橡树.txt') as f:
lines = f.readlines()
print(lines)


if __name__ == '__main__':
main()

JSON

JSON Python
object dict
array list
string str
number (int / real) int / float
true / false True / False
null None

json模块主要有四个比较重要的函数,分别是:

  • dump - 将Python对象按照JSON格式序列化到文件中
  • dumps - 将Python对象处理成JSON格式的字符串
  • load - 将文件中的JSON数据反序列化成对象
  • loads - 将字符串的内容反序列化成Python对象

序列化(serialization)在计算机科学的数据处理中,是指将数据结构或对象状态转换为可以存储或传输的形式,这样在需要的时候能够恢复到原先的状态,而且通过序列化的数据重新获取字节时,可以利用这些字节来产生原始对象的副本(拷贝)。与这个过程相反的动作,即从一系列字节中提取数据结构的操作,就是反序列化(deserialization)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import json


def main():
mydict = {
'name': '骆昊',
'age': 38,
'qq': 957658,
'friends': ['王大锤', '白元芳'],
'cars': [
{'brand': 'BYD', 'max_speed': 180},
{'brand': 'Audi', 'max_speed': 280},
{'brand': 'Benz', 'max_speed': 320}
]
}
try:
with open('data.json', 'w', encoding='utf-8') as fs:
json.dump(mydict, fs)
except IOError as e:
print(e)
print('保存数据完成!')


if __name__ == '__main__':
main()

re

函数 说明
compile(pattern, flags=0) 编译正则表达式返回正则表达式对象
match(pattern, string, flags=0) 用正则表达式匹配字符串 成功返回匹配对象 否则返回None
search(pattern, string, flags=0) 搜索字符串中第一次出现正则表达式的模式 成功返回匹配对象 否则返回None
fullmatch(pattern, string, flags=0) match函数的完全匹配(从字符串开头到结尾)版本
findall(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式 返回字符串的列表
finditer(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式 返回一个迭代器
purge() 清除隐式编译的正则表达式的缓存
re.I / re.IGNORECASE 忽略大小写匹配标记
re.M / re.MULTILINE 多行匹配标记

进程和线程

进程就是操作系统中执行的一个程序,操作系统以进程为单位分配存储空间,每个进程都有自己的地址空间、数据栈以及其他用于跟踪进程执行的辅助数据,操作系统管理所有进程的执行,为它们合理的分配资源。进程可以通过fork或spawn的方式来创建新的进程来执行其他的任务,不过新的进程也有自己独立的内存空间,因此必须通过进程间通信机制(IPC,Inter-Process Communication)来实现数据共享,具体的方式包括管道、信号、套接字、共享内存区等。

一个进程还可以拥有多个并发的执行线索,简单的说就是拥有多个可以获得CPU调度的执行单元,这就是所谓的线程。由于线程在同一个进程下,它们可以共享相同的上下文,因此相对于进程而言,线程间的信息共享和通信更加容易。
在单核CPU系统中,真正的并发是不可能的,因为在某个时刻能够获得CPU的只有唯一的一个线程,多个线程共享了CPU的执行时间。
在其他进程的角度,多线程的程序对其他程序并不友好,因为它占用了更多的CPU执行时间,导致其他程序无法获得足够的CPU执行时间;

多进程

程序中的代码只能按顺序一点点的往下执行,那么即使执行两个毫不相关的下载任务,也需要先等待一个文件下载完成后才能开始下一个下载任务,很显然这并不合理也没有效率。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from random import randint
from time import time, sleep


def download_task(filename):
print('开始下载%s...' % filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))


def main():
start = time()
download_task('Python从入门到住院.pdf')
download_task('Peking Hot.avi')
end = time()
print('总共耗费了%.2f秒.' % (end - start))


if __name__ == '__main__':
main()

开始下载Python从入门到住院.pdf…
Python从入门到住院.pdf下载完成! 耗费了6秒
开始下载Peking Hot.avi…
Peking Hot.avi下载完成! 耗费了7秒
总共耗费了13.01秒.

通过Process类创建了进程对象,通过target参数我们传入一个函数来表示进程启动后要执行的代码,后面的args是一个元组,它代表了传递给函数的参数。Process对象的start方法用来启动进程,而join方法表示等待进程执行结束。运行上面的代码可以明显发现两个下载任务“同时”启动了,而且程序的执行时间将大大缩短,不再是两个任务的时间总和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from multiprocessing import Process
from os import getpid
from random import randint
from time import time, sleep


def download_task(filename):
print('启动下载进程,进程号[%d].' % getpid())
print('开始下载%s...' % filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))


def main():
start = time()
p1 = Process(target=download_task, args=('Python从入门到住院.pdf', ))
p1.start()
p2 = Process(target=download_task, args=('Peking Hot.avi', ))
p2.start()
p1.join()
p2.join()
end = time()
print('总共耗费了%.2f秒.' % (end - start))


if __name__ == '__main__':
main()

启动下载进程,进程号[1530].
开始下载Python从入门到住院.pdf…
启动下载进程,进程号[1531].
开始下载Peking Hot.avi…
Peking Hot.avi下载完成! 耗费了7秒
Python从入门到住院.pdf下载完成! 耗费了10秒
总共耗费了10.01秒.

多线程

直接使用threading模块的Thread类来创建线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from random import randint
from threading import Thread
from time import time, sleep


def download(filename):
print('开始下载%s...' % filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))


def main():
start = time()
t1 = Thread(target=download, args=('Python从入门到住院.pdf',))
t1.start()
t2 = Thread(target=download, args=('Peking Hot.avi',))
t2.start()
t1.join()
t2.join()
end = time()
print('总共耗费了%.3f秒' % (end - start))


if __name__ == '__main__':
main()

通过继承Thread类的方式来创建自定义的线程类,然后再创建线程对象并启动线程。代码如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from random import randint
from threading import Thread
from time import time, sleep


class DownloadTask(Thread):

def __init__(self, filename):
super().__init__()
self._filename = filename

def run(self):
print('开始下载%s...' % self._filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下载完成! 耗费了%d秒' % (self._filename, time_to_download))


def main():
start = time()
t1 = DownloadTask('Python从入门到住院.pdf')
t1.start()
t2 = DownloadTask('Peking Hot.avi')
t2.start()
t1.join()
t2.join()
end = time()
print('总共耗费了%.2f秒.' % (end - start))


if __name__ == '__main__':
main()

如果一个资源被多个线程竞争使用,那么我们通常称之为“临界资源”,对“临界资源”的访问需要加上保护,否则资源会处于“混乱”的状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
from time import sleep
from threading import Thread


class Account(object):

def __init__(self):
self._balance = 0

def deposit(self, money):
# 计算存款后的余额
new_balance = self._balance + money
# 模拟受理存款业务需要0.01秒的时间
sleep(0.01)
# 修改账户余额
self._balance = new_balance

@property
def balance(self):
return self._balance


class AddMoneyThread(Thread):

def __init__(self, account, money):
super().__init__()
self._account = account
self._money = money

def run(self):
self._account.deposit(self._money)


def main():
account = Account()
threads = []
# 创建100个存款的线程向同一个账户中存钱
for _ in range(100):
t = AddMoneyThread(account, 1)
threads.append(t)
t.start()
# 等所有存款的线程都执行完毕
for t in threads:
t.join()
print('账户余额为: ¥%d元' % account.balance)


if __name__ == '__main__':
main()

通过“锁”来保护“临界资源”,只有获得“锁”的线程才能访问“临界资源”,而其他没有得到“锁”的线程只能被阻塞起来,直到获得“锁”的线程释放了“锁”,其他线程才有机会获得“锁”,进而访问被保护的“临界资源”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
from time import sleep
from threading import Thread, Lock


class Account(object):

def __init__(self):
self._balance = 0
self._lock = Lock()

def deposit(self, money):
# 先获取锁才能执行后续的代码
self._lock.acquire()
try:
new_balance = self._balance + money
sleep(0.01)
self._balance = new_balance
finally:
# 在finally中执行释放锁的操作保证正常异常锁都能释放
self._lock.release()

@property
def balance(self):
return self._balance


class AddMoneyThread(Thread):

def __init__(self, account, money):
super().__init__()
self._account = account
self._money = money

def run(self):
self._account.deposit(self._money)


def main():
account = Account()
threads = []
for _ in range(100):
t = AddMoneyThread(account, 1)
threads.append(t)
t.start()
for t in threads:
t.join()
print('账户余额为: ¥%d元' % account.balance)


if __name__ == '__main__':
main()

Python的多线程并不能发挥CPU的多核特性

任务的类型,可以把任务分为计算密集型和I/O密集型

计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如对视频进行编码解码或者格式转换等等
计算密集型任务由于主要消耗CPU资源,这类任务用Python这样的脚本语言去执行效率通常很低,最能胜任这类任务的是C语言

涉及到网络、存储介质I/O的任务都可以视为I/O密集型任务.这类任务的特点是CPU消耗很少,任务的大部分时间都在等待I/O操作完成(因为I/O的速度远远低于CPU和内存的速度)
网络应用和Web应用。

单线程+异步I/O

充分利用操作系统提供的异步I/O支持,就可以用单进程单线程模型来执行多任务,这种全新的模型称为事件驱动模型。

Nginx就是支持异步I/O的Web服务器,它在单核CPU上采用单进程模型就可以高效地支持多任务。在多核CPU上,可以运行多个进程(数量与CPU核心数相同),充分利用多核CPU。

在Python语言中,单线程+异步I/O的编程模型称为协程,基于事件驱动编写高效的多任务程序.

协程最大的优势就是极高的执行效率,因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销。协程的第二个优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不用加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

如果想要充分利用CPU的多核特性,最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。

网络编程

协议族就是一系列的协议及其构成的通信模型.

TCP/IP模型。与国际标准化组织发布的OSI/RM这个七层模型不同,TCP/IP是一个四层模型,也就是说,该模型将我们使用的网络从逻辑上分解为四个层次,自底向上依次是:网络接口层、网络层、传输层和应用层,如下图所示。

Alt text

IP通常被翻译为网际协议,它服务于网络层,主要实现了寻址和路由的功能。
“路由器”的网络中继设备,它们会存储转发我们发送到网络上的数据分组,让从源头发出的数据最终能够找到传送到目的地通路,这项功能就是所谓的路由。

TCP全称传输控制协议,它是基于IP提供的寻址和路由服务而建立起来的负责实现端到端可靠传输的协议.

  • 数据不传丢不传错(利用握手、校验和重传机制可以实现)。
  • 流量控制(通过滑动窗口匹配数据发送者和接收者之间的传输速度)。
  • 拥塞控制(通过RTT时间以及对滑动窗口的控制缓解网络拥堵)。

网络应用模式
C/S模式和B/S模式。这里的C指的是Client(客户端),通常是一个需要安装到某个宿主操作系统上的应用程序;而B指的是Browser(浏览器),它几乎是所有图形化操作系统都默认安装了的一个应用软件;通过C或B都可以实现对S(服务器)的访问。
去中心化的网络应用通常没有固定的服务器或者固定的客户端,所有应用的使用者既可以作为资源的提供者也可以作为资源的访问者。

requests

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from time import time
from threading import Thread

import requests


# 继承Thread类创建自定义的线程类
class DownloadHanlder(Thread):

def __init__(self, url):
super().__init__()
self.url = url

def run(self):
filename = self.url[self.url.rfind('/') + 1:]
resp = requests.get(self.url)
with open('/Users/Hao/' + filename, 'wb') as f:
f.write(resp.content)


def main():
# 通过requests模块的get函数获取网络资源
# 下面的代码中使用了天行数据接口提供的网络API
# 要使用该数据接口需要在天行数据的网站上注册
# 然后用自己的Key替换掉下面代码的中APIKey即可
resp = requests.get(
'http://api.tianapi.com/meinv/?key=APIKey&num=10')
# 将服务器返回的JSON格式的数据解析为字典
data_model = resp.json()
for mm_dict in data_model['newslist']:
url = mm_dict['picUrl']
# 通过多线程的方式实现图片下载
DownloadHanlder(url).start()


if __name__ == '__main__':
main()

套接字编程 socket

套接字就是一套用C语言写成的应用程序开发库,主要用于实现进程间通信和网络编程,在网络应用开发中被广泛使用。

基于套接字来使用传输层提供的传输服务,并基于此开发自己的网络应用。实际开发中使用的套接字可以分为三类:流套接字(TCP套接字)、数据报套接字和原始套接字。

TCP套接字

在Python中可以通过创建socket对象并指定type属性为SOCK_STREAM来使用TCP套接字。
一台主机可能拥有多个IP地址,而且很有可能会配置多个不同的服务,所以作为服务器端的程序,需要在创建套接字对象后将其绑定到指定的IP地址和端口上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from socket import socket, SOCK_STREAM, AF_INET
from datetime import datetime


def main():
# 1.创建套接字对象并指定使用哪种传输服务
# family=AF_INET - IPv4地址
# family=AF_INET6 - IPv6地址
# type=SOCK_STREAM - TCP套接字
# type=SOCK_DGRAM - UDP套接字
# type=SOCK_RAW - 原始套接字
server = socket(family=AF_INET, type=SOCK_STREAM)
# 2.绑定IP地址和端口(端口用于区分不同的服务)
# 同一时间在同一个端口上只能绑定一个服务否则报错
server.bind(('127.0.0.1', 6789))
# 3.开启监听 - 监听客户端连接到服务器
# 参数512可以理解为连接队列的大小
server.listen(512)
print('服务器启动开始监听...')
while True:
# 4.通过循环接收客户端的连接并作出相应的处理(提供服务)
# accept方法是一个阻塞方法如果没有客户端连接到服务器代码不会向下执行
# accept方法返回一个元组其中的第一个元素是客户端对象
# 第二个元素是连接到服务器的客户端的地址(由IP和端口两部分构成)
client, addr = server.accept()
print(str(addr) + '连接到了服务器.')
# 5.发送数据
client.send(str(datetime.now()).encode('utf-8'))
# 6.断开连接
client.close()


if __name__ == '__main__':
main()

运行服务器程序后我们可以通过Windows系统的telnet来访问该服务器,结果如下图所示

Alt text

通过Python的程序来实现TCP客户端的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from socket import socket


def main():
# 1.创建套接字对象默认使用IPv4和TCP协议
client = socket()
# 2.连接到服务器(需要指定IP地址和端口)
client.connect(('127.0.0.1', 6789))
# 3.从服务器接收数据
print(client.recv(1024).decode('utf-8'))
client.close()


if __name__ == '__main__':
main()

使用多线程技术处理多个用户请求的服务器,该服务器会向连接到服务器的客户端发送一张图片。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from socket import socket, SOCK_STREAM, AF_INET
from base64 import b64encode
from json import dumps
from threading import Thread


def main():

# 自定义线程类
class FileTransferHandler(Thread):

def __init__(self, cclient):
super().__init__()
self.cclient = cclient

def run(self):
my_dict = {}
my_dict['filename'] = 'guido.jpg'
# JSON是纯文本不能携带二进制数据
# 所以图片的二进制数据要处理成base64编码
my_dict['filedata'] = data
# 通过dumps函数将字典处理成JSON字符串
json_str = dumps(my_dict)
# 发送JSON字符串
self.cclient.send(json_str.encode('utf-8'))
self.cclient.close()

# 1.创建套接字对象并指定使用哪种传输服务
server = socket()
# 2.绑定IP地址和端口(区分不同的服务)
server.bind(('192.168.1.2', 5566))
# 3.开启监听 - 监听客户端连接到服务器
server.listen(512)
print('服务器启动开始监听...')
with open('guido.jpg', 'rb') as f:
# 将二进制数据处理成base64再解码成字符串
data = b64encode(f.read()).decode('utf-8')
while True:
client, addr = server.accept()
# 启动一个线程来处理客户端的请求
FileTransferHandler(client).start()


if __name__ == '__main__':
main()

client:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from socket import socket
from json import loads
from base64 import b64decode


def main():
client = socket()
client.connect(('192.168.1.2', 5566))
# 定义一个保存二进制数据的对象
in_data = bytes()
# 由于不知道服务器发送的数据有多大每次接收1024字节
data = client.recv(1024)
while data:
# 将收到的数据拼接起来
in_data += data
data = client.recv(1024)
# 将收到的二进制数据解码成JSON字符串并转换成字典
# loads函数的作用就是将JSON字符串转成字典对象
my_dict = loads(in_data.decode('utf-8'))
filename = my_dict['filename']
filedata = my_dict['filedata'].encode('utf-8')
with open('/Users/Hao/' + filename, 'wb') as f:
# 将base64格式的数据解码成二进制数据并写入文件
f.write(b64decode(filedata))
print('图片已保存.')


if __name__ == '__main__':
main()

JSON并不能携带二进制数据,因此对图片的二进制数据进行了Base64编码的处理。Base64是一种用64个字符表示所有二进制数据的编码方式,通过将二进制数据每6位一组的方式重新组织,刚好可以使用0~9的数字、大小写字母以及“+”和“/”总共64个字符表示从000000到111111的64种状态。

udp

不对传输的可靠性和可达性做出任何承诺从而避免了TCP中握手和重传的开销,所以在强调性能和而不是数据完整性的场景中(例如传输网络音视频数据),UDP可能是更好的选择

email

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from smtplib import SMTP
from email.header import Header
from email.mime.text import MIMEText


def main():
# 请自行修改下面的邮件发送者和接收者
sender = 'abcdefg@126.com'
receivers = ['uvwxyz@qq.com', 'uvwxyz@126.com']
message = MIMEText('用Python发送邮件的示例代码.', 'plain', 'utf-8')
message['From'] = Header('王大锤', 'utf-8')
message['To'] = Header('骆昊', 'utf-8')
message['Subject'] = Header('示例代码实验邮件', 'utf-8')
smtper = SMTP('smtp.126.com')
# 请自行修改下面的登录口令
smtper.login(sender, 'secretpass')
smtper.sendmail(sender, receivers, message.as_string())
print('邮件发送完成!')


if __name__ == '__main__':
main()

进阶

数据结构和算法

迭代器/生成器

并发编程

dead simple python

your workbench

Packages and Virtual Environments

A package is a collection of code, which is analogous to a library in most
other programming languages.

Some packages require other packages to be installed first. Certain packages
have conflicts with other packages. You can also install specific versions
of a package, depending on what exactly you need.
This is why virtual environments exist.

A virtual environment is a sandbox where you can install only the
Python packages you need for a particular project, without the risk of
those packages clashing with those for another project (or your system).
You never
actually change what Python packages are installed on your system, so
you avoid breaking important things that have nothing to do with your
project.

You may even create virtual environments that have nothing to do with
a particular project.

Creating a Virtual Environment

To create the virtual environment with the name venv_1 in the current
working directory, run the following command in the command line:

python3 -m venv venv_1

venv_1 is the desired path to the virtual environment. In this
case, venv is just a relative path, creating a venv/ directory in the current
working directory. However, you could also use an absolute path, and you
could call it whatever you want

python3 -m venv /opt/myvirtualenv


vscode

python create environment

Activating a Virtual Environment

On Windows, run this:

venv_1\Scripts\activate.bat

venv_1/Scripts/activate.bat

vscode
python select interpreter

If you have multiple shells (usually terminal windows) open, you should be
aware that the virtual environment is only active for the one shell you explicitly
activated it in!

environment paths will be overridden by the virtual environment.
Practically speaking, any packages you install in the virtual environment
are only usable there, and from the venv, the system-wide packages cannot
be accessed unless you explicitly specify otherwise.

If you want the virtual environment to also see the system-wide packages, you can do so with a special flag

python3 -m venv –system-site-packages venv_1

Leaving a Virtual Environment

venv_1\Scripts\deactivate.bat

Introducing pip

System-Wide Packages

python3 -m pip command

Installing Packages

pip install package

If you want to install a specific version of something, append two equal
signs (==), followed by the desired version number (no spaces):

pip install PySide6==6.1.2

Bonus: you can even use operators like >=, to mean “at least this version
or greater.” These are called requirement specifiers.

pip install PySide6>=6.1.2

If you’re on a UNIX-like system, you may need to use pip install
“PySide6>=6.1.2” instead, since > has another meaning in the shell.

requirements.txt

writing a requirements
.txt file for your project. This file lists the packages your project needs. When
creating a virtual environment, you and other users can install all the
required packages with a single command, using this file.

To create this file, list the name of a pip package, as well as its version (if
required), on each line.

requirements.txt

1
2
PySide2>=5.11.1
appdirs

install all those packages in one shot with this
command:

pip install -r requirements.txt

Upgrading Packages

pip install –upgrade PySide6

pip install –upgrade -r requirements.txt

Removing Packages

pip uninstall package

Installing one package will also install any
other packages it relies upon, which we call its dependencies. Uninstalling a
package does not remove its dependencies, so you may need to go through
and remove them yourself.

Herein lies one more advantage of virtual environments. Once I’m in
that sort of a pickle, I can delete the virtual environment, create a new one,
and install only those packages I need.

Seriously. Never use sudo pip

Virtual Environments and Git

If you’re using Git, create or edit a file called .gitignore in the root directory of your repository. Add this line somewhere in it:

venv_1/

the whole shebang

The shebang (short for haSH-BANG, or #!) 1 provides the path to the
Python interpreter. While it’s optional, I strongly recommend including
it in your code, as it means the file can be marked as executable and run
directly, like this:

./hello_world.py

hello_world.py

1
2
#!/usr/bin/env python3
print("Hello, world!")

If you happen to have a script which runs in both Python 2 and Python 3,
use this shebang instead:

#!/usr/bin/env python

File Encoding

Since Python 3.1, all Python files have used the UTF-8 encoding, allowing the
interpreter to use all of the characters in Unicode. (Prior to that version,
the default was to use the old ASCII encoding.)

# -*- coding: latin-1 -*-

# coding: latin-1

# This Python file uses the following encoding: latin-1

Whatever you use, it must be exactly as shown above, except for swapping latin-1 for whatever encoding you want. For this reason, the first or
second forms are preferred.

A Few Extra Virtual Environment Tricks

Using a Virtual Environment Without Activating

assuming my virtual environment is venv, I could do this
in the terminal:

1
2
3
venv/bin/pip install pylint
venv/bin/python
> import pylint

import pylint still will not work on the system-wide Python
interactive shell

Quality Control: Static Analyzers

static
analyzer, which reads your source code, looking for potential problems or
deviations from the standards.

One common type of static analyzer, called a linter,
checks your source code for common mistakes, potential errors, and style
inconsistencies. Two of the most popular linters are Pylint and PyFlakes.

Pylint

Style Janitors: Autoformatting Tools

an autoformatter, which can automatically change your Python code—spacing, indentation, and preferred equivalent expressions (such as != instead of <>)—to be PEP 8 compliant. Two
options are autopep8 and Black.

An Exhibition of Code Editors

PyCharm

The
professional edition adds tools for data, scientific development, and web
development.

SYNTA X CR ASH COURSE

Statements and Expression

Each line of code in Python that ends with a line break is a statement,
sometimes more specifically known as a simple statement.

A section of code that evaluates to a single value is called an expression.

put expressions nearly anywhere a value is expected.
The expression is evaluated down to a value, and that value is used in that
position in the statement.

The Importance of Whitespace

PEP 8 style guide stresses using either four spaces or a single tab per indentation level. Consistency is key! Python really doesn’t care whether you use
tabs, two spaces, four spaces, or even seven spaces (although that’s probably
a step too far) for each level of indentation. The point is to be consistent
within any and every given block of code.

Doing Nothing

On occasion, you will need to insert a statement that has absolutely no
effect. This is particularly useful when you need to put a syntactically valid
placeholder where a suite of code will exist later. For this purpose, Python
provides the pass keyword.

1
2
3
raining = True
if raining:
pass

Comments and Docstrings

To write comments in Python, precede the line with a hash (#). Everything
between the hash and the end of the line is a comment and will be ignored
by the interpreter.

Docstrings

Docstrings exist to provide documentation for functions, classes, and
modules, especially public ones. They conventionally begin and end with
three quotation marks (“””), allowing the string to automatically span multiple lines. You would typically place docstrings at the top, inside of whatever they’re defining, such as in the function above.

There are three important distinctions between comments and
docstrings:

  1. Docstrings are string literals, and they are seen by the interpreter; comments are ignored.
  2. Docstrings are used in automatic documentation generation.
  3. Docstrings are generally only docstrings when they appear at the top of
    the module, function, class, or method they define. Comments can live
    anywhere.

It is perfectly possible to use a triple-quoted string literal to write a sort
of “multiline comment,” but it’s not recommended, since a string literal can
easily get left in a place where Python will try to use it as a value.

Declaring Variables

Python is dynamically typed, meaning the data type of a value is determined when it is evaluated. This contrasts with statically typed languages,
in which you declare the data type initially. (C++ and Java are both statically
typed.)

using the
assignment operator (=). It infers the data type. If the name is a new variable, Python will create it; if the name already exists, Python will change
the value. It’s a pretty straightforward system.

two rules to follow with Python variables:

  1. Define a variable before you access it; otherwise, you’ll get an error.
  2. Don’t change what kind of data you’re storing in the variable, even
    when replacing a value.

Python is considered a strongly typed language, meaning you usually can’t
magically combine data of different types. For example, it won’t allow you
to add an integer and a string together.

Python is, however, weakly bound, so it is possible to assign a value of a
different type to an existing variable. While this is technically permissible,
it is strongly discouraged, as it can produce confusing code.

What About Constants?

Python doesn’t have any formally defined constants. In keeping with PEP 8,
you would indicate a variable is intended to be treated as a constant by
using all-caps names with underscores. This naming convention is sometimes humorously referred to as screaming snake case for the all-caps (screaming) and the underscores (snakes).

For example, the name INTEREST_RATE

Mathematics

Meet the Number Types

Integers (int) store whole numbers. In Python, integers are always signed
and effectively have no maximum value. Integers use decimal base (base-10)
by default,

Floating-point numbers (float) store numbers with a decimal part (for
example, 3.141592).
Internally, values are stored as double-precision, IEEE 754 floatingpoint numbers, which are subject to the limits inherent in that format.

specify an invalid number with float(“nan”), a number
larger than the largest possible value with float(“inf”), or a number smaller
than the smallest possible value with float(“-inf”).

Decimal stores fixed-point decimal numbers, while Fraction
does the same for fractions
To use either, you’ll need to import them first.

1
2
3
4
5
6
7
8
9
10
11
12
from decimal import Decimal
from fractions import Fraction
third_fraction = Fraction(1, 3)
third_fixed = Decimal("0.333")
third_float = 1 / 3
print(third_fraction) # 1/3
print(third_fixed) # 0.333
print(third_float) # 0.3333333333333333
third_float = float(third_fraction)
print(third_float) # 0.3333333333333333
third_float = float(third_fixed)
print(third_float) # 0.333
1
2
3
4
5
6
7
8
9
10
print(-42) # negative (unary), evaluates to -42
print(abs(-42)) # absolute value, evaluates to 42
print(40 + 2) # addition, evaluates to 42
print(44 - 2) # subtraction, evaluates to 42
print(21 * 2) # multiplication, evaluates to 42
print(680 / 16) # division, evaluates to 42.5
print(680 // 16) # floor division (discard remainder), evaluates to 42
print(1234 % 149) # modulo, evaluates to 42
print(7 ** 2) # exponent, evaluates to 49
print((9 + 5) * 3) # parentheses, evaluates to 42

Python offers augmented
assignment operators, sometimes informally called compound assignment
operators. These allow you to perform an operation with the current value
of the variable as the left operand.

1
2
3
4
5
6
7
8
foo = 10
foo += 10 # value is now 20 (10 + 10)
foo -= 5 # value is now 15 (20 – 5)
foo *= 16 # value is now 240 (15 * 16)
foo //= 5 # value is now 48 (240 // 5)
foo /= 4 # value is now 12.0 (48 / 4)
foo **= 2 # value is now 144.0 (12.0 ** 2)
foo %= 51 # value is now 42.0 (144.0 % 15)

the divmod() function to efficiently perform the calculation, returning the two results in a tuple. Thus, c = divmod(a, b) is the
same as c = (a // b, a % b).

bitwise operators

1
2
3
4
5
6
print(9 & 8) # bitwise AND, evaluates to 8
print(9 | 8) # bitwise OR, evaluates to 9
print(9 ^ 8) # bitwise XOR, evaluates to 1
print(~8) # unary bitwise ones complement (flip), evaluates to -9
print(1 << 3) # bitwise left shift, evaluates to 8
print(8 >> 3) # bitwise right shift, evaluates to 1

the math module

1
2
3
4
5
6
7
8
9
import math
print(math.pi) # PI 3.141592653589793
print(math.tau) # TAU 6.283185307179586
print(math.e) # Euler's number 2.718281828459045
print(math.inf) # Infinity
print(math.nan) # Not-a-Number
infinity_1 = float('inf')
infinity_2 = math.inf
print(infinity_1 == infinity_2) # prints True
1
2
3
4
5
6
7
8
9
10
import math
distance_ft = 65 # the distance to the object
angle_deg = 74 # the angle to the top of the object
# Convert from degrees to radians
angle_rad = math.radians(angle_deg)
# Calculate the height of the object
height_ft = distance_ft * math.tan(angle_rad)
# Round to one decimal place
height_ft = round(height_ft, 1)
print(height_ft) # outputs 226.7

Comparison Operators

1
2
3
4
5
6
7
8
score = 98
high_score = 100
print(score == high_score) # equals, evaluates to False
print(score != high_score) # not equals, evaluates to True
print(score < high_score) # less than, evaluates to True
print(score <= high_score) # less than or equals, evaluates to True
print(score > high_score) # greater than, evaluates to False
print(score >= high_score) # greater than or equals, evaluates to False

Boolean, None, and Identity Operators

Take particular note of the last condition, eggs is spam which illustrates an important gotcha with the is operator. It actually compares the identity of the
variables, rather than the value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
spam = True
eggs = False
potatoes = None
if spam is True: # Evaluates to True
print("We have spam.")
if spam is not False: # Evaluates to True
print("I DON'T LIKE SPAM!")
if spam: # Implicitly evaluates to True (preferred)
print("Spam, spam, spam, spam...")
if eggs is False: # Evaluates to True
print("We're all out of eggs.")
if eggs is not True: # Evaluates to True
print("No eggs, but we have spam, spam, spam, spam...")
if not eggs: # Implicitly evaluates to True (preferred)
print("Would you like spam instead?")
if potatoes is not None: # Evaluates to False (preferred)
print("Yum") # We never reach this...potatoes is None!
if potatoes is None: # Evaluates to True (preferred)
print("Yes, we have no potatoes.")
if eggs is spam: # Evaluates to False (CAUTION!!!)
print("This won't work.")

Truthiness

Most expressions and values in Python can be evaluated to a True or False
value. This is typically done by using the value as an expression by itself,
although you can also pass it to the bool() function to convert it explicitly.

1
2
3
4
answer = 42
if answer:
print("Evaluated to True") # this runs
print(bool(answer)) # prints True

When an expression will evaluate to True, it is considered “truthy.”
When it will evaluate to False, it is “falsey.”

The None constant, values representing zero, and empty collections are all considered “falsey,” while most
other values are “truthy.”

Logical Operators

1
2
3
4
5
6
7
8
spam = True
eggs = False
if spam and eggs: # AND operator, evaluates to False
print("I do not like green eggs and spam.")
if spam or eggs: # OR operator, evaluates to True
print("Here's your meal.")
if (not eggs) and spam: # NOT (and AND) operators, evaluates to True
print("But I DON'T LIKE SPAM!")
1
2
3
4
score = 98
high_score = 100
print(score != high_score) # not equals operator, evaluates to True
print(not score == high_score) # not operator, evaluates to True

The condition employing the != operator is preferred for readability.

The Walrus Operator

Python 3.8 introduced assignment expressions, which allow you to assign a
value to a variable and use that variable in another expression at the same
time. This is possible with the so-called walrus operator (:=).

1
2
3
if (eggs := 7 + 5) == 12:
print("We have one dozen eggs")
print(eggs) # prints 12

Python first evaluates the expression on the
left (7+5) and then assigns it to the variable eggs.
The assignment expression is then evaluated to a single value, namely
the value of eggs, which is used in the comparison

Two particularly useful style rules are put forth
by this PEP:
• If either assignment statements or assignment expressions can be used,
then prefer statements; they are clear declarations of intent.
• If using assignment expressions would lead to ambiguity about execution order, then restructure to use statements instead.

Strings

String Literals

The only time you’d really need to escape either single or double
quotes with backslashes would be if you had both types of quotes in the
string at once:
question = "What do you mean, \"it's fine\"?"

triple quotes define multiline string literals. In other
words, I can use them to do this:

1
2
3
4
5
6
7
8
9
parrot = """\
This parrot is no more!
He has ceased to be!
He's expired
and gone to meet his maker!
He's a stiff!
Bereft of life,
he rests in peace!"""
print(parrot)

The only exception occurs when you use a backslash (\) to escape
particular character, like I did with that newline at the beginning 1. It is
conventional to escape the first newline after the opening triple quotes, just
to make the code look cleaner.

concatenate (combine) string literals, simply by
writing them next to one another, without any operators between them. For
example, spam = “Hello “ “world” “!” is valid, resulting in the string Hello
world!.

Raw Strings

Raw strings constitute another form of string literal, wherein the backslash
(\) is always treated as a literal character. They’re preceded with an r, such
as in this example:
print(r"I love backslashes: \ Aren't they cool?")

Formatted Strings

1
2
3
in_stock = 0
print("This cheese shop has " + str(in_stock) + " types of cheese.")
print(f"This cheese shop has {in_stock} types of cheese.")

Instead, you’d have to
evaluate that expression in advance, assign the result to a name, and use it
in the f-string.

The ord() function returns the number representing the unicode code of a specified character.

print(f”{ord(‘\n’)}”) # SyntaxError

newline_ord = ord(‘\n’)
print(f”{newline_ord}”) # prints “10”

Format Specifications

Immediately after the expression, you may choose to include one of
three special flags: !r, !a, or !s (although that last one is the default behavior, so it can be omitted in most cases). These determine which function
is used to fetch the string representation of some value: repr(), ascii(), or
str(), respectively

Next comes the format specification itself, which always begins with a
colon (:), followed by one or more flags. These have to be specified in a particular order to work, although any of them may be omitted if they’re not
desired:

Align An alignment flag, specifying left (<), right (>), center (^), or (if
numeric) split with the sign aligned left but the digits aligned right (=).
This is optionally preceded by a character that will be used to fill any
blank space in the alignment.
Sign A flag controlling when the sign is displayed on a number. The
plus (+) flag displays the sign on both positive and negative numbers,
while the minus (–) flag only displays it on negative numbers. A third
option is to show a leading space on positive numbers and a sign on
negative numbers (SPACE).
Alternative form The hash (#) flag turns on the “alternative form,”
which has different meanings for different types (see documentation).
Leading zeros The zero (0) flag causes leading zeros to be displayed
(unless a fill character is specified for alignment).
Width The width of the output string in characters. This is where the
alignment comes into play.
Grouping A flag controlling whether numbers should separate thousands with a comma (,) or an underscore (_). If omitted, no separator
is used. If enabled, the underscore separator also appears every four
digits in octal, hexadecimal, and binary numbers.
Precision A dot (.), followed by an integer for decimal precision
Type A flag controlling how numbers are displayed; common options
include binary (b), character (c), decimal (d), hexadecimal (x), exponent notation (e), fixed-point (f), and general (g). There are more (see
documentation).

1
2
3
4
5
6
spam = 1234.56789
print(f"{spam:=^+15,.2f}") # prints "===+1,234.57==="
spam = 42
print(f"{spam:#07x}") # prints "0x0002a"
spam = "Hi!"
print(f"{spam:-^20}") # prints "--------Hi!---------"

String Conversion

str(), is the one you’ll use most often, as it returns
the human-readable representation of the value.

repr() returns the canonical string representation of the value:
that is, (usually) the value as Python sees it. In the case of many basic data
types, this will return the same thing as str(), but when used on most
objects, the output contains additional information useful in debugging.

The ascii() function is the same as repr(), except that the string literal
it returns is completely ASCII-compatible, having escaped any non-ASCII
(for example, Unicode) characters.

A Note on String Concatenation

Typical concatenation with + or the join() function has the same result,
but the latter function will be as fast or faster, especially when you’re using
other implementations of Python besides CPython. Therefore, whenever
you need to concatenate and f-strings aren’t right for the job, you should
consider using join() instead of the + or += operators. In practice, f-strings
are the fastest, but join() is your next-best option.

1
2
3
4
5
6
7
8
9
greeting = "Hello"
name = "Jason"

message = greeting + ", " + name + "!" # value is "Hello, Jason!"
print(message)

message = "".join((greeting, ", ", name, "!")) # value is "Hello, Jason!"
print(message)

Functions 0

Python functions are first-class citizens, which means they can be treated like
any other object

Classes and Objects 0

Error Handling 0

1
2
3
4
5
6
7
num_from_user = input("Enter a number: ")
try:
num = int(num_from_user)
except ValueError:
print("You didn't enter a valid number.")
num = 0
print(f"Your number squared is {num**2}")

Tuples and Lists

Lists constitute the most array-like collection in Python. In CPython,
they are implemented as variable-length arrays

A tuple is somewhat similar to a list, but with a few key differences.
First, a tuple cannot have items added, reassigned, or removed after its creation. Attempting to modify the contents of a tuple with bracket notation
will result in a TypeError. This is because tuples, unlike lists, are immutable, effectively meaning their contents cannot be modified

The guideline is to use tuples for collections of items of different types
(heterogeneous collections) and to use lists for collections of items of the same
type (homogeneous collections).

Loops

Structural Pattern Matching

Python 3.10 gained structural pattern matching via PEP 634.
This provides conditional logic that is at least syntactically similar to switch
statements of other languages. In short, you test a single subject, such as a
variable, against one or more patterns. If the subject matches the pattern,
the associated suite of code runs.

lunch_order = input(“What would you like for lunch? “)
match lunch_order:
case ‘pizza’:
print(“Pizza time!”)
case ‘sandwich’:
print(“Here’s your sandwich”)
case ‘taco’:
print(‘Taco, taco, TACO, tacotacotaco!’)
case _:
print(“Yummy.”)

The underscore (_) in the last case is the wildcard, which will match any
value. This serves as a fallback case, and it must come last, as it will match
anything.

PROJECT STRUCTURE AND IMPORTS

Setting Up the Repository

Your Python code belongs in a separate subdirectory and not in the
root of the repository. This is very important, as your repository’s root directory will get mighty cluttered with build files, packaging scripts, documentation, virtual environments, and all manner of other things that aren’t
actually part of the source code.

Modules and Packages

A module is any Python (.py) file.

A package, occasionally called a regular package, is one or more modules within a directory. That directory must include a file called __init__
.py (which can be empty). The __init__.py file is important! If it isn’t there,
Python will not know the directory constitutes a package.

PEP 8 and Naming

Modules should have short, all-lowercase names. Underscores can
be used in the module name if it improves readability. Python
packages should also have short, all-lowercase names, although
the use of underscores is discouraged.

Do this: omission/data/data_loader.py
NOT this: omission/Data/DataLoader.py

another special file in my top-level package: __main__.py. This
is the file that runs when I execute my top-level package directly, via this
command:

Import Dos and Don’ts

1
2
3
4
5
6
7
8
#!/usr/bin/env python3
def open():
print("Ahhhhhhhhhhhhhh.")
def close():
print("Thank you for making a simple door very happy.")
import smart_door
smart_door.open()
smart_door.close()

The namespace of open() and close() is smart_door. A namespace is an
explicitly defined path to something, such as a function. The function
open() has the namespace smart_door, which tells me that open() belongs to
that particular module.

Importing Within Your Project

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
omission-git/
└── omission/
├── __init__.py
├── __main__.py
├── app.py
├── common/
│ ├── __init__.py
│ ├── classproperty.py
│ ├── constants.py
│ └── game_enums.py
├── data/
│ ├── __init__.py
│ ├── data_loader.py
│ ├── game_round_settings.py
│ ├── scoreboard.py
│ └── settings.py

Listing 4-8: Directory structure of omission-git/

Absolute Imports

I have a class GameMode defined within the game_enums.py module, which
lives in the omission/common package. I want to use that class within my
game_round_settings.py module, defined in the omission/data package

Because I defined omission as a top-level package and organized my modules into subpackages, it’s pretty straightforward. In game_round_settings.py,
I’d write the following:

from omission.common.game_enums import GameMode

This line is an absolute import. It starts at the top-level package, omission,
and walks down into the common package

Relative Imports

You can also import from a module in the same package or subpackage.
This is known as a relative import or an intrapackage reference.

A module knows what package it belongs to, and a package knows its
parent package (if it has one). Because of this, relative imports can start the
search from the current package and move up and down through the project structure.

Within omission/data/game_round_settings.py, I can use the following
import statement:

from ..common.game_enums import GameMode

Listing 4-11: game_round_settings.py:1c

The two dots (..) mean “the current package’s direct parent package,”
which, in this case, is omission

Importing from the Same Package

In omission/data/settings.py, I have
this statement for importing a class from the module omission/data/game
_round_settings.py:

from omission.data.game_round_settings import GameRoundSettings

from game_round_settings import GameRoundSettings

However, that will not work. It will fail to locate the game_round_settings
.py module because I am running the top-level package (python3 -m omission),
and absolute imports for anything within the package being executed
(omission) have to start from the top.

use a relative import, which looks much simpler than the
absolute import:

from .game_round_settings import GameRoundSettings

Entry Points

The parts of the project that are run first when importing or
executing are called entry points

Module Entry Points

When you import a Python module or package, it is given a special variable
called __name__. This contains the fully qualified name of the module or package, which is the name as the import system sees it. For example, the fully
qualified name of the module omission/common/game_enums.py would be
omission.common.game_enums.

when a module or package is run directly, its __name__ is set to the value “__main__“.

a package called testpkg, which contains the module awesome.py. It defines a function, greet():

1
2
3
def greet():
print("Hello, world!")
print("Awesome module was run.")

In another module in the same directory as testpkg, I have this module
(example.py), which I run directly with python3 example.py:

1
2
3
from testpkg import awesome
print(__name__) # prints "__main__"
print(awesome.__name__) # prints "testpkg.awesome"
1
2
3
Awesome module was run.
__main__
testpkg.awesome

what if I want that first message to appear only if awesome.py is executed directly, and not when the module is only imported? To accomplish
that, I’d check the value of __name__ variable in a conditional statement. I’ve
rewritten my awesome.py file to do exactly that:

1
2
3
4
def greet():
print("Hello, world!")
if __name__ == "__main__":
print("Awesome module was run.")

Package Entry Points

omission project has a file called __main__ in the top-level
package. This file is automatically run when a package is executed directly,
but never when importing the package

So, when executing omission via python3 -m omission, Python first runs
the __init__.py module (as always), followed by its __main__.py module.
Otherwise, if the package is imported instead, only __init__.py is executed.

A good __main__.py for a top-level package would look something like
the following:

1
2
3
4
def main():
# Code to start/run your package.
if __name__ == "__main__":
main()

Program Entry Points

However, you (or your eventual end user) may want to run the program
merely by double-clicking or directly executing some single Python file.
With everything else in place, this is trivial to implement.

To make my omission project easy to run, I created a single script file
outside the top-level package, named omission.py:

1
2
from omission.__main__ import main
main()

VARIABLES AND TYPES

Variables According to Python: Names and Values

A name refers to a value or an object
. A value is a particular instance of data in memory
The term variable refers to the combination of the two: a name that refers to a value.

answer = 42
insight = answer

insight is not bound to answer, but rather to the same
value that answer was already bound to when I assigned insight. A name
always points to a value.

is
doesn’t check whether a name points to equivalent values, but rather whether
it points to the same value in memory.

When you make an assignment, Python makes its own decisions behind
the scenes about whether to create a new value in memory or bind to an
existing value

spam = 123456789
maps = spam
eggs = 123456789

print(spam == maps) # prints True
print(spam == eggs) # prints True

print(spam is maps) # prints True
print(spam is eggs) # prints False (probably)

(Interactive session)

answer = 42
insight = 42
print(answer is insight) # prints True

The is operator checks identity. Unless you really know what you’re doing,
only use this to check if something is None.>

the built-in function id() returns an integer representing the identity of whatever is passed to it.

Data Types

Names are bound to values, and those values exist in memory, as long as
there is some reference to them. You can bind a name to literally any value you
want, but you are limited as to what you can do with any particular value.

The type() Function

print(type(answer)) # prints <class 'int'>

if type(answer) is int:
print(“What’s the question?”)

use isinstance() instead of type(), as it accounts for subclasses and
inheritance

if isinstance(answer, int):
print(“What’s the question?”)

Duck Typing

If it looks like a duck, walks like a duck, and quacks like a duck,
then it probably is a duck.

Python doesn’t care much about what a value’s data type is, but rather
it cares about the functionality of the value’s data type.

If your class behaves as it
should, it usually won’t matter what it inherits from.

Scope and Garbage Collection

Scope is what defines where a variable can be accessed from. It might be
available to an entire module or limited to the suite (body) of a function.

A
name can be global, meaning it is defined by itself in a module, or it can be
local, meaning it only exists within a particular function or comprehension.

Local Scope and the Reference-Counting Garbage Collector

Functions (including lambdas) and comprehensions define their own
scope; they are the only structures in the language to do so.

When a scope reaches its end, all the names defined
within it are automatically deleted.

. Modules and
classes don’t have their own scope in the strictest sense; they only have
their own namespace.

loops don’t have their own scope.

a reference count, which is simply
a count of how many references exist for that value. Every time a value is
bound to a name, a reference is created (although there are other ways the
language may create references). When there are no more references, the
value is deleted. This is the reference-counting garbage collector, and it efficiently
handles most garbage collection scenarios.

def spam():
message = “Spam”
word = “spam”
for _ in range(100):
separator = “, “
message += separator + word
message += separator
message += “spam!”
return message

output = spam()
print(output)
even though the name message is deleted when spam() exits, the value is not.

Interpreter Shutdown

When the Python interpreter is asked to shut down, such as when a Python
program terminates, it enters interpreter shutdown. During this phase, the interpreter goes through the process of releasing all allocated resources, calling
the garbage collector multiple times, and triggering destructors in objects.

Global Scope

When a name is defined within a module but outside of any function, class,
or comprehension, it is considered to be in global scope

using
the global high_score name. This means that anywhere I assign a value to the
name high_score in score(), the function will use the global name, instead of
trying to create a new local name.

If you’re only accessing the current
value bound to a global name, you don’t need to use the global keyword.

The Dangers of Global Scope

The nonlocal Keyword

trying to assign to a global
name will actually define a new local name that shadows the global one.

The same behavior is true of the inner function using names defined in
the outer function, which is known as the nested scope or enclosing scope.

To
get around this, I specify that eggs is nonlocal,

The nonlocal keyword starts looking for the indicated name in the innermost nested scope, and if it doesn’t find it, it moves to the next enclosing
scope above that. It repeats this until it either finds the name or determines
that the name does not exist in a nonglobal enclosing scope.

Scope Resolution

which scopes it searches for a name, and in what order,
is called the scope resolution order

the acronym LEGB

Local
Enclosing-function locals (that is, anything found via nonlocal)
Global
Built-in

The Curious Case of the Class

Every name
declared directly within a class is known as an attribute, and it is accessed
through the dot (.) operator on the class (or object) name.

The Immutable Truth

Values in Python can be either immutable or mutable. The difference hinges
on whether the values can be modified in place, meaning they can be changed
right where they are in memory.

Immutable types cannot be modified in place. For example, integers (int),
floating-point numbers (float), strings (str), and tuples (tuple) are all immutable.

If you attempt to mutate an immutable value, you’ll wind up with a
completely different value being created:

eggs = 12
carton = eggs
print(eggs is carton) # prints True
eggs += 1
print(eggs is carton) # prints False
print(eggs) # prints 13
print(carton) # prints 12

Mutable types, on the other hand, can be modified in place.
Lists constitute one example of a mutable type:

temps = [87, 76, 79]
highs = temps
print(temps is highs) # prints True
temps += [81]
print(temps is highs) # prints True
print(highs) # prints [87, 76, 79, 81]
print(temps) # prints [87, 76, 79, 81]

达内 Python

程序: 计算机指令,实现需求的软件

多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Person():
def __init__(self, name):
self.name = name

def travel(self, vehicle, position):
vehicle.transport(position)

class Vehicle():
def __init__(self):
pass
def transport(self, position):
pass

class Car(Vehicle):
def transport(self, position):
print("car", position)

class Airplane(Vehicle):
def transport(self, position):
print("airplane", position)

person_1 = Person("lucfe")
car_1 = Car()
airplane_1 = Airplane()
person_1.travel(car_1, "beijing")
person_1.travel(airplane_1, "beijing")

car beijing
airplane beijing

url encoding

URL encoding is an encoding format used in URLs.
The standard allows the use of arbitrary data inside a Uniform Resource Identifier (a URI; typically a URL) while using only a narrow set of US-ASCII characters.

The encoding exists because URLs and HTTP request parameters often contain characters (or other data) that cannot be represented with the limited set of US-ASCII characters (i.e. control characters, etc.).

arbitrary随心所欲的
not seeming to be based on a reason, system or plan and sometimes seeming unfair

Reserved and unreserved characters

Unreserved characters are characters that have no special meaning; they can be displayed as-is and require no special handling. These include uppercase and lowercase letters (A-Z, a-z), decimal digits (0-9), hyphen (-), period (.), underscore (_), and tilde (~).

Reserved characters, on the other hand, are characters that may delimit the URI into sub-components: characters such as / # & and others. The following is the list of all reserved characters: ! # $ & ‘ ( ) * + , / : ; = ? @ [ ].

We cannot use reserved character as-is, because this would create ambiguous URIs.

Percent encoding

To encode reserved characters, we use the percent-encoding scheme. In percent-encoding, each byte is encoded as a character triplet that consists of the percent character % followed by the two hexadecimal digits that represent the byte numeric value.

For instance, %23 is the percent-encoding for the binary octet 00100011, which in US-ASCII, corresponds to the character #.

Other characters

Percent encoding is also used to represent other characters; characters that are neither reserved nor unreserved.

As an example, imagine a GET request containing a non-ASCII string parameter, such as a search query zajec in jež which is Slovenian for a rabbit and a hedgehog.

In such cases, we have to first encode non-ASCII characters as UTF-8 and then encode each byte of the new string with percent-encoding.

Encoding the space character

using the + instead of %20 is valid only when encoding the application/x-www-form-urlencoded content, such as the query part of an URL.

udemy html5 css3

browser
request
https://omnifood.de

web server
response
html css js

static website: website where files are simply sent to browser as they are
front end development

dynamic website: website files are assembled on the server
back end development
webserver app db
back-end languages that run on servers

html -> content -> nouns
css -> presentation -> adjectives
js -> programming language: dynamic effects and web applications -> verbs

HTML fundamentals

introduction to html

html: hypertext markup language

html is a markup language that web developers use to structure and descripe the content of a webpage(not a programming language)

html consists of elements that describe different types of content: paragraphs, links, headings, images, video, etc.

web browsers understand html and render Html code as websites

<p>HTML is a markup language</p>

Alt text

  • <p>opening tag: name of the element, wrapped in < and >

  • content: content of the element, in this example text. but it might be another element(child element). some elements have no content(e.g. <img>)

  • </p>closing tag: same as opening tag, but with a /. when element has no content, it’s omitted.

HTML document structure

1
2
3
4
5
6
7
8
9
<!DOCTYPE html>
<html>
<head>
<title>The Basic Language of the Web: HTML</title>
</head>
<body>
<h1>The Basic Language of the Web: HTML</h1>
</body>
</html>

text elements

<em></em>emphersized

lists

images and attributes

Structure our page

semantic html

css fundamentals

cascading style sheets

css describes the visual style and presentation of the content written in HTML

css consists of countless properties that developers use to format the content: properties about font, text, spacing, layout, etc.

Alt text

inline, internal and external css

styling text

16px default

combining selectors

working with colors

rgb(12,125,255)

rgba(0,255,255,0.3)

#00ffff
#0ff when allcolors are identical pairs

when colors in all 3 channels are the same, we get a gray color

pseudo class

using chrome devtools

conflicts between rules

Alt text

multiple -> last selector in code applies

marked !important

inline style

id selector

class or pseudo class selector

Alt text

element selector

universal selector (*)

inheritance and the universal selector

css box model

Alt text

margin and padding

clapping of margins

adding dimention

centering our page

class container

1
2
3
4
5
.container {
width: 800px;
margin-left: auto;
margin-right: auto;
}

types of boxes

  • inline elements
    occupies only the space necessary for its content
    causes on line-break after or before the element
    box model applies in a different way: heights and widths do not apply
    paddings and margins are applied only horizontally(left and right)

a
strong
em
button

with css
display: inline

  • block level elements
    elements are formatted visually as blocks
    elements occupy 100% of parent element’s width, no matter the content
    elements are stacked vertically by default, one after another
    the box-model applies as showed earlier

with css
display: block

  • inline block boxes
    looks like inline from the outside, behaves like block-level on the inside
    occupies only content’s space
    causes no line-breaks
    box-model applies as showed

img

with css
display: inliblock

absolute positioning

normal flow
in flow: laid out according to their order in the html code

absolute positioning
out of flow: no impact on surrounding elements, might overlap them
use top, bottom, left, or right to offset the element from its relatively positioned container(the first)

Alt text

pseudo elements

+
adjacent sibling
sibling right after the element

googling and reading documentation

debugging and asking questions

chrome dev tool
font-size
arrow
shift arrow

challenge #3

the 3 ways of building layouts

layout is the way text, images and other content is placed and arranged on a webpage
layout gives the page a visual structure, into which we place our content

building a layout: arranging page elements into a visual struture, instead of simply having them placed one after another(normal flow)

page layout

component layout

  • float layouts
    old way

element is removed from the normal flow: “out of flow”
text and inline elements will wrap around the floated element
the container will not adjust its height to the element

  • flexbox
    laying out elements in a 1-dimensional row without using floats. perfect for componnet layouts

  • css grid
    for laying out element in a fully-fledged 2-dimentional grid. perfect for page layouts and complex componnets.

using floats

both children float
collapse of the elements

clearing float

box-sizing: border-box

Alt text

challenge #1

introduction to flexbox

tall as the tallest

a flexbox overview

flexbox is a set of related css properties for building 1 dimentional layout
the main idea behind flexbox is that empty space inside a container element can be automatically divided by its child elemennts
flexbox makes it easy to automatically align items to one another inside a parent container, both horizontally and vertically
flexbox solves common problems such as vertical centering and creating equal-height colums

Alt text

spacing and aligning flex items

Alt text

the flex property

add flexbox to our project

building a simple flexbox layout

challenge #2

introduction to css grid

a css grid overview

css gird is a set of css properties for building 2-dimentional layouts
the main idea behind css grid is that we divide a container element into rows and columns that can be filled with its child elements
in two-dimentional contexts, css grid allows us write less nested html and easier to read css
css grid is not meant to replace flexbox! instead, they work perfectly together. need a 1d layout? use flexbox. need 2D layout? use css gird

Alt text

Alt text

sizing grid columns and rows

fr fraction

placing and spanning grid items

Alt text

aligning grid items and tracks

building a simple css grid layout

challenge #3.0

web design rules and framework

overview of web design and website personalities

ingredients

typography

colors

images/illustrations

icons

shaows

border-radius

whitespace

visual hierarchy

user experience

componnets/layout

Alt text

rule #1 typography

serif

sans-serif

Alt text

use only good and popular typefaces and play it safe

its okay to use just one typeface per page! if you want more, limit to typefaces.

choose the right typefaced according to your website personality:

choose the right personality for your website

  • decide between a serif and sans-serif typeface
  • experiment with all the “good” typefaces(and other typefaces from google fonts!) to see which ones best fits your websites message
  • keep trying different typefaces as you design and build the page

use good font sizes and weights

  • when choosing font-sizes, limit choices! use a “type scale” tool or other pre-defined range
  • use a font size between 16px and 32px for normal text
  • for long text (like a blog post), try a size of 20px or even bigger
  • for headlines, you can go really big (50px+) and bold (600+), depending on personality
  • for any text, dont use a font weight under 400 (regular)

create a good reading experience

  • use less than 75 character per line
  • for normal-sized text, use a line height between 1.5 and 2. for big text, go below 1.5
    • the smaller or longer the text, ther larger the line height needs to be!
  • decrease letter spcing in headlines, if it looks unnatural(this will come from experience, if the headline looks not nature)
  • experiment with all caps for short titles. make them small and bold and decrease letter spacing
  • usually, dont justify text(每行平铺)
  • dont center long text blocks. small blocks are fine.

rule # colors

choose the right color

  • make the main color match your website’s personality: colors covey meaning!
    • red drawing a lot of attention, and symbolizes power, passion, and excitment
    • orange is less aggressive, and conveys hapiness, cheerfulness, and creativity
    • yellow means joy, brightness and intelligece
    • greens represents harmony, nature, growth, and health
    • blue is associated with peach, trustworthiness and professionalism
    • purple conveys wealth, wisdom, and masic
    • pink represents romance, care and affection
    • brown is associated with nature, durability and comfort
    • black symbolizes power, elegence and minimalism, but also grief and sorrow
      -use a good color tone! dont choose a random tone or css named colors.

establish a color system

  • you need at least two types of colors in your color palette: a main color and a gray color
  • with more experience, you can add more colors: accent(secondary)
  • for diversity, create lighter and darker “version”(tints and shades)

when and how to use colors

  • use main color to draw attention to the most important elements on the page
  • use colors to add interesting accents or make entire components or sectoin stand out
  • you can try to use your color stategically in images and illustrations

color and typograghy

  • on dark colored backgrounds, try to use a tint of the background (“lighter version”) for text
    Alt text

  • text should usually not be completely black. lighten it up it looks heavy and uninviting

  • dont make text too light! use a tool to check contrast between text and background colors (tool: coolors)

    • contrast ratio needs to be at least 4.5:1 for normal text and 3 : 1 for large text(18px+)

implenting colors

images and illustations

  • different types of images: product photos, storytelling photos, illustrations, patterns
    • storytelling: using or related to the product
    • abstract way of storytelling
    • pattens -> background
  • use images to support your websites message and story. so only use relevant images!
  • perfer original images. if not possible, use orginal-looking stock images(not generic ones!)
  • try to show real people to trigger users emtions
  • if necessary, corp images to fit your message
  • experiment combining photos, illustration and pattern

handling text on images

  • method #1 darker or brighten image(completely or partially, using a gradient)
  • method #2 postion text into neutral image area
  • method #3 put text in a box

Alt text

some technical details

  • to account for high-res screens, make image dimensions 2X as big as their displayed size
  • compress imgaes for a lower file size and better perfomance
  • when using multiple images side by side, make sure they have the exack same dimensions

rule #4: ICONS

  • use a good icon pack, there are tons of free and paid icons packs
  • use only one icon pack. dont mix icons from different icon packs
  • use svg icons or icon fonts. dont use bitmap image formats(.jpg and .png)!
  • adjust to website personality! roundness, weight and filled/outlined depend on typography

Alt text

when to use icons

  • use icons to provide visual assitance to text
  • use icons for product feautre blocks

Alt text

  • use icons associated with actions, and label them(unless no space or icon is 100% clear)

Alt text

  • use icons as bullet points (list)

use icons well

  • to keep icons neutral, use same color as text. to draw more attention, use different color
  • dont confuse your users: icons need to make sense and fit the text or action!
  • dont make icons larger than what they were designed for. if needed, enclose them in a shape
    • icons were designed for big use:lots of details, thine lines

Alt text

implementing icons

rules #5: shadows

Alt text

shadow creates depth(3d): ther more shaow, the further away from the interface the element is

Alt text

use shadows well

  • you dont have to use shadows! only use them if it makes sense for the website personality
    • serious/elegant -> less shadows
    • playfull/fun -> more shadows
  • use shadows in small doses: dont add shadows to every element!
  • go light on shadows, dont make them too dark!

use shadows in the right situation

  • use small shadows for smaller elements that should stand out (to draw attention)

Alt text

  • use medium-sized shadows for larger areas that should stand out a bit more

Alt text

Alt text

  • use large shadows for elements that should really float above the interface

Alt text

  • experiment with changing shadows on mouse interaction (click and hover)

Alt text

  • bonus: experiment with glows(colored shadows)

implementing shadows

rules #6: border-radius

  • use border-radius to increase the playfulness and fun of the design, to make it less serious
  • typefaces have a certain roundness: make sure that border-radius matches that roundness!
  • use border-radius on buttons, image, around icons, standout sections and other elements

implementing border-radius

rules #7: whitespace

the right amount of whitespace make designs look clean, mordern and polished
whitespace communicates how different pieces of information are related to one another
whitespace implies invisible relationships between the elements of a layout

where to use whitespace

  • use tons of whitespace between sections
  • use a lot of whitespace between groups of elements
  • use whitespace between elements
  • inside groups of elements, try to use whitespace instead of lines

Alt text

how much whitespace

  • the more some elements(or groups of elements) belong together, the closer they should be!

Alt text

  • start with a lot of whitespace, maybe even too much! then remove whitespace from there
    • to much whitespace looks detached, too little looks too crammed
  • match other design choices.
    • if you have big text or big icons, you need more whitespace.
  • try a hard rule, such as using multiplesof 16px for all spacing

Alt text

rule #8: visual hierarchy

establishing which elements of a design are the most important ones

visual hierarchy is about drawing attention to these most important elements

visual hierarchy is about defining a “path” for users, to guide them through the page

we use a combination of position, size, colors, spacing, borders, and shadows to establish a meaningful visual hierarchy between elements/components

fundamentals

  • position important elements closer to the top the page, where they get more attention
  • use images mindfully, as they draw a lot of attention(larger images get more attention)
  • whitespace create separation, so use whitespace strategically to emphasize elements

hierarchy for text elements

  • for text elements, use font size, font weight, color, and whitespace to convey importance.

Alt text

Alt text

  • what text elements to emphasize? titles, subtitles, links, buttons, data points, icons
    • you can de-emphasize less important text, like labels or secondary/additional information

Alt text

hierarchy between components

  • emphasize an important component using background color, shadows, or border(or multiple)
  • try emphasizing some component a over component b by de-emphasizing component b
  • what components to emphasize?
    • testimonials, call-to-action sections, highlight sections, preview cards, form, pricing tables, important rows/columns in table, etc.

Alt texttestimonials, call-to-action sections, highlight sections

Alt textpreview cards

Alt textform, pricing tables, important rows/columns

implementing whitespace and visual hierarchy

rules #9: user experience(ux)

what is ux

“design is not just what it looks like and feels like. design is how it works” –Steve Jobs

user experience is the overall experience the user has while interacting with the product

  • does the app feel logical and well thought out
  • does the navigation work intuitively
  • are users reaching their goals

ux design guiding principle: goals

  • a website or application exists for a reason: a user has a goal for visiting it, and a business has a goal for creating it.

Alt text

ux rules for usability

  • dont design complicated layouts. dont reinvent the wheel. use patterns that users know.
  • make your call-to-action the most prominent element, and make the text descriptive.
  • use blue text and underlined text only for links
  • animations should have a purpose and be fast: between 200 and 500 ms
  • in forms, align labels and fields in a single vertical line, to make the form easier to scan
  • offer users good feedback for all actions: form errors, form success, etc.
  • place action buttons where they will create an effect(law of locality)

Alt text

ux rules for website content

  • use a descriptive, keyword-focused headline on your main page. dont be vague or fancy!
  • only include relevant information, efficiently! cut out fluff and make the content 100% clear
  • use simple words! avoid technical jargon and “smart-sounding” words
  • break up long text with sub-heading, images, block quotes, bullet points, etc.

the website-personalities-framework

Alt text

  • serious/elegant

industries: real estate, high fashion, jewelry, luxury products or services

typography: serif typefaces(especially in headings), light font weight, small body font size

colors: gold, pastel colors, black, dark blue or grey

image: big, high-quality images are used to feature elegant and expensive products

icons: usually no icons, but thin icons and lines may be used

shadows: usually no shadows

boarder-radius: usally no border-radius

layout: a creative and experimental layout is quite common

Alt text

  • minimalist/simple

industries: fashion, porfolios, minimalism companies, software startups

typography: boxy/squered sans-serif typefaces, small body font size

colors: usually black or dark grey, on pure white background. usually just one color throughout the design
images: few images, which can be uesed to add some color to the design. usually no illustrations, but if, then just black
icons: usally no icons, but small simple black icons may be used

shadow: usually no shadows
border-radius: usually no border-redius

layout: simple layout, a narrow one-column layout is quite common.

Alt text

  • plain/neutral

industries: well-established corporations, companies that dont want to make an impact through design

typography: neutral-looking sans-serif typefaces are used, and text is usually small and doesnt have visual impact

colors: safe colors are employed, nothing too bright or to washed-out. bule and blacks are common

images: images are frequently used, but usually in a small format

icons: usally no icons, but simple icons may be used

shadows: usually no shadows

border-radius: usually no border-radius

layout: structured and condensed layout, with lots of boxes and rows

Alt text

  • bold/confident

industries: digital agencies, software starups, travel, “strong” companies

typography: boxy/squared sans-serif typefaces, big and bold typography, especially headings. uppercase headings are common

color: usually multiple bright colors. big color blocks/sections are used to draw attention

images: lots of big images are usually displayed

icons, shadows, border-radius: usually no

layout: all kinds of layouts, no particular tendencies

Alt text

  • calm/peaceful

industries: healthcare, all products with focus on consummer well-being

typography: soft serif typefaces frequently used for headings, but sans-serif heading might be used too

colors: pastel/washed-out colors: light oranges, yellows, browns, greens, blues

images: images and illustrations are usual, matching calm color palette

icons: icons are quite frequent

shadows: usually no shadows, but might be used sparingly

border-radius: some border-radius is usual

layout: all kinds of layout, no particular tendencies

Alt text

  • startup/upbeat

industries: software starups, and other modern-looking companies

typography: medium-sized headings(not too large), usually one sans-serif typeface in whole design. tendency for light text colors

colors: blues, greens and purples are widely used. lots of light background(mainly gray), gradients are also common

image: images or illustrations are always usesd. 3d illustartions are morden. sometimes patterns and shapes add visual details

icons: icons are very frequent

shadows: subtle shadows are frequent. glows are becoming modern

border-radius: border-radius is very common

layout: rows of cards and z-pattens are usual, as well as animations

Alt text

  • playful/fun

industries: child products, animal products, food

typography: round and creative(e.g. handwritten) sans-serif typefaces are ferquent. centered text is more common

colors: multiple colors are frequently used to design a colorful layout, all over background and text

images: images, hand-drawn(or 3d)illustrations, and geometric shapes and patterns are all very frequently used

icons: icons are very frequent. many times in a hand-drawing style

shadows: subtle shadows are quite common, but not always used

border-radius: border-radius is very common

layout: all kinds of layouts, no particular tendencies

Alt text

Alt text

components and layout patterns

rule #10 - part 1: elements and components

elements -> components ->layouts -> webpage

use common elements and components to convey your websites information

combine components into layout using common layout patterns

assemble different layout areas into a complete, final page

A elements

text
buttons
images
input elements
tags

B components

breadcrumbs
pagination
alert and status bars
statistics
gallery
feature box
preview and profile cards
accordion
tabs
carousel
customer testimonials
customer logos
featured-in logos
steps
forms
tables
pricing tables
modal widows

C section components

navigaiton
herosection
footer
call to action section
feature row

D layout patterns

row of boxes or cards
grid of boxes or cards
z pattern
f pattern
single column
sidebar
multi-column/magzine
asymmetry/experimental

text

Alt text

Alt text

button

Alt text

image

Alt text

input elements

Alt text

tag

Alt text

components

breadcrumbs

Alt text

pagination

Alt text

alert and status bars

Alt text

statistics

Alt text

gallery

Alt text

Alt text

feature box

Alt text

Alt text

preview and profile cards

have data
click to some action

Alt text

Alt text

  • profile card

Alt text

accordion
hiding information

Alt text

Alt text

tab

Alt text

Alt text

carousel
slider

Alt text

Alt text

customer testimonials

Alt text

Alt text

Alt text

customer logos

Alt text

Alt text

featured-in logo

Alt text

steps

Alt text

Alt text

forms

Alt text

  • login

Alt text

Alt text

table

Alt text

Alt text

pricing table

Alt text

Alt text

modal windows
弹窗

function

Alt text

marketing

Alt text

building an accordion component - part 1

building an accordion component - part 2

chrome dev tool
delete elements

Alt text

building a table component - part 1

building a table component - part 2

building a pagination component challenge # 1

rule #10 part 2: layout patterns

Alt text

Alt text

Alt text

Alt text

Alt text

Alt text

hero secttion

  • type 1

text + image

text: header + description + botton

Alt text

  • type 2

Alt text

  • sitemap

Alt text

call to action section

Alt text

contact us

Alt text

feature row

Alt text

layout pattern

row of boxes/cards
Alt text

grid of boxes/cards

Alt text

nesting patterns in components

Alt text

z-pattern

Alt text

f-pattern

Alt text

single column

web app

Alt text

side bar

Alt text

multi-column/magazine

Alt text

asymmetry/experimental

Alt text

building a hero section - part 1

100vh viewport height

building a hero section - part 2

1
2
background-image: url(hero.jpg);
background-size: cover;

building a web application layout - part 1

building a web application layout - part 2

margin-left: auto;

how elements that dont fit into container appear

overflow: scroll;

omnifood project - setup and desktop version

7 steps

  1. define the project
  • define who the website is for. is it for yourself? for a client of your agency or your freelancing bussiness?

  • define what the website is for. in other words, define bussiness and user goals of your website project

bussiness goal examples: selling premium dog food
user goal example: finding high-quality dog food for good price

  • define a target audience. Be really specific if possible and if it makes sense for your website

example: “weomen, 20 to 40 years old, living in europe, earning over 2000$/month, with a passion for dogs”

  1. plan the project
  • plan and gather website content: copy (text), images, videos etc.

  • content is usually provided by the client, but you also can help

  • for bigger sites, plan out the sitemap: what pages the site needs, and how they are related to one another(content hierachy)

  • based on the content, plan what sections each page needs in order to convey the contents message, and in which order

  • define the website personality

  1. sketch layout and component ideas
  • think out what components you need, and how you can use them in layout pattens

  • get ideas out of your head: sketch them with pen and paper or with some design software(e.g. figma)

  • this is an iterative process: experiment with different components and layouts, until you arrive at a first good solution

  • you dont need to sktch everything, and dont make it perfect. at some point, youre ready to jump into html and css

  1. design and build
  • use decisions, content and sketches from step 1, 2, 3

  • use layout and components to design the actual visul styles

  • create the design based on selected website personality, the design guidelines, and inspiration

  • use the client’s branding(if exists) for design decisions whenever possible: colors, typography, icons, etc.

  1. test and optimize
  • make sure website works well in all major browsers

  • test the website on actual mobile devices, not just in dev tools

  • optimize all images, in term of dimension and file size

  • fix simple accessibility problems

  • run the lighthouse performance test in chrome devtools and try to fix reported issues

  • think about search engine optimization

  1. launch the masterpiece
  • upload your website files to hosting platform.

  • choose and buy a great domain name, one that represents the brand well, is memorable and easy to write.

  1. maintain and keep updating website
  • install analytic software(e.g. google analytics or fathom) to get statics about website users. this myy inform future changes in the site structure and content.

  • a blog that is updated regularly is a good way to keep users coming back, and is also good for seo.

defining and planning the project

step 1

whe the website is for

for a client

what the website is for

business goal: selling monthly food subscrition
user goal: eating well effortlessly, without spending a lot of time and money

define target audience

busy people who like technology, are interesting in a health diet, and have a well-paying job.

step 2

sitemap: one page marketing website

define website personality
startup/upbeat
calm/peaceful

plan page sections

  • logo + navigation
  • hero
  • featured in
  • how it works
  • meals(diets)
  • testimonials + gallery
  • pricing + feature
  • call to action
  • footer

sketching initial layout ideas

Alt text

first design and development steps

responsive design principles

4 ingredients

fluid layouts
to allow webpgae to adapt to the current viewport width(or even height)
use %(or vh/vw) unit instead of px for elements that should adapt to viewport(usually layout)
use max-width instead of width

responsive units
use rem unit instead of px for most lengths
to make it easy to scale the entire layout down (or up) automatically
helpfull trick: setting 1rem to 10px for easy calculations

flexible images
by default, images dont scale automatically as we change the viewport, so we need to fix that
always use % for image dimensions, together with the max-width property

media queries
bring responsive sites to life
to change css styles on certain viewport widths(called breakpoints)

how rem and max-width work

max-width: 1000px

container > 1000px ->elements width = 1000px
container < 1000px ->elements width = 100% container width

可以和width: 30%; 合用

rem -> root element
default browser font size 16px

1
2
3
4
html {
font-size: 62.5%;
/* set to percent so the user can change the root font size*/
}

building the hero - part 1

rarr: right arrow

building the hero - part 2

css default line height: 1.2
Normal: The default line height. If you’re using a desktop browser, the default is 1.2. However, this varies based on the element font family. Length: The length you identify is used to calculate line box height.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /* trick to add border inside */
a {box-shadow: inset 0 0 0 3px #fff;
}

a:link, a:visited {
/* put transition on original "state" */
transition: background-color 1s;
}

/* margin helper */
.margin-right-sm {
margin-right: 1.6rem !important;
}

building the hero - part 3

building the website header

building the navigation

building how it works secton - part 1

building how it works secton - part 2

1
2
3
4
5
6
7
8
9
10
.step-img-box::before {
content: "";
display: block;
width: 60%;
/* height: 60%; */

/* 60% of parents width */
padding-bottom: 60%;
background-color: #fdf2e9;
}

z-index: -1;

1
2
3
4
img {
opacity: 60%;
filter: brightness(0);
}

building the meals section - part 1

building the meals section - part 2

overflow: hidden;

building the meals section - part 3

currentColor
the text color

1
2
3
4
5
6
7
8
.link:link, .link:visited {
text-decoration: none;
border-bottom: 1px solid currentColor;
}

.link:hover, .link:active {
border-bottom: 1px solid transparent;
}

building the testimonials section - part 1

1
2
3
4
.section-testimonials {
display: grid;
grid-template-columns: 1fr 1fr;
}

building the pricing section - part 1

building the pricing section - part 2

building the feature part

1
2
3
4
5
6
7
8
9
.feature-icon {

height: 3.2rem;
width: 3.2rem;

background-color: #fdf2e9;
padding: 1.6rem;
border-radius: 50%;
}

building the call-to-action section - part 1

background-image: linear-gradient(90deg #e67e22, #eb984e);

background-image: url(../img/eating.jpg);
background-size: cover;
background-position: center;

background-image: linear-gradient(to right bottom, rgba(50, 50, 49, 0.35), rgba(235, 150, 76, 0.35)), url(../img/eating.jpg);

building the call-to-action section - part 2

font-family: inherit;

responsive design

how media queries work

Alt text

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* hero section */
.section-hero {
background-color: #fdf2e9;
padding: 4.8rem 0 9.6rem 0;
}

@media (max-width: 1200px) {
.section-hero {
background-color: orange;
}
}

@media (max-width: 600px) {
.section-hero {
background-color: red;
}
}

how to select breakpoints

Alt text

responding to small laptops

<meta name="viewport" content="width=device-width, initial-scale=1.0" />

rem and em do not depend on html font-size in media queries
Instead 1rem = 1em = 16px

responding to landscape tablets

responding to tablets

building the mobile navigation