Python 计算
数字
# 加减乘除
print(2 + 2) # 4
print(4 - 3) # 1
print(6 * 2) # 12
print(17 / 3) # 5.666667
# 去掉小数点
print(17 // 3) # 5
# 取模运算
print(17 % 3) # 2
# 幂运算
print(3 ** 2) # 9
# 变量赋值
tax = 12.5 / 100
price = 100.50
print(price * price)
文本
# 打印字符串
print("Hello") # Hello
# 转义
print("I\'m") # I'm
print(r'C:\user\local') # C:\user\local
# 打印多行
print("""\
Man,
what can I said.
""")
# 字符拼接
print(2*"O" + "k") # OOK
列表
# 打印列表
squares = [1, 4, 9]
print(squares) # [1, 4, 9]
# 索引切片
squares[0] # 1
squares[-1] # 9
squares[-2:] # [4, 9]
# 相同引用
rgb = ["Red", "Green", "Blue"]
rgba = rgb
print(id(rgb) == id(rgba)) # True
# 清空列表
squares[:] = []
print(squares) # []
Python 流程控制
分支结构
# if 语句
x = intput("请输入一个数字:")
if x < 0:
print("x是负数!")
elif x == 0:
print("x是零!")
else:
print("x是正数!")
循环结构
# for 循环
animals = ['cat', 'panda', 'elephant']
for a in animals:
print(a, len(a))
# 迭代集合副本
weeks = {'Mon':1, 'Tue':2, 'Wen':3}
for d, n in weeks.copy().items():
print(d, n)
其他语句
# range()函数
for i in range(4):
print(i) # 0 1 2 3
print(list(range(3, 5))) # 3 4
print(list(range(0, 10, 3))) # 0 3 6 9
print(sum(range(4))) # 6
# break 和 continue
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, '相当于', x, '*', n//x)
break
else:
print(n, '是质数')
for num in range(2, 10):
if num % 2 == 0:
print("偶数 ", num)
continue
print("奇数 ", num)
# pass 什么也不执行
while True:
pass
# match "_" 为通配符 一定会执行
def http_error(status):
match status:
case 400:
return "Bad request"
case 401|403:
return "Not allowed"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _:
return "Something's wrong with the internet"
Python 函数
函数定义
def fib(n):
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a + b
print()
def ask_ok(prompt, retries=4, reminder='Please try again!'):
while True:
reply = input(prompt)
if reply in {'y', 'ye', 'yes'}:
return True
if reply in {'n', 'no', 'nop', 'nope'}:
return False
retries = retries - 1
if retries < 0:
raise ValueError('invalid user response')
print(reminder)
函数参数
# *name 接收元组 **name 接收字典
def fun(*argument, **keywords):
for arg in argument:
print(arg)
print("-------")
for kw in kewords:
print(kw, ":", keywords[kw])
# / 限制前面的参数只能按位置传递
# * 限制后面的参数只能按关键字传递
def combined_example(pos_only, /, standard, *, kwd_only):
print(pos_only, standard, kwd_only)
print(combined_example(1, 2, kwd_only=3))
# 任意参数列表
def concat(*args, sep="/")
return sep.join(args)
print(concat("earth", "mars", "venus")) # 'earth/mars/venus'
# * 将实参从列表或元组解包
args = [3, 6]
print(list(range(*args)))
Lambda表达式
# 匿名函数写法
def make_incrementor(n):
return lambda x: x + n;
f = make_incrementor(3)
print(f(1)) # 4
print(f(2)) # 6
# 匿名函数作实参
paris = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
paris.sort(key=lambda pair:pair[1])
print(paris)
函数注解
# -> 用来指示函数返回类型
# __annotations__ 是函数的注解
def f(ham: str, eggs: str = 'eggs') -> str:
print("Annotations:", f.__annotations__)
print("Arguments:", ham, eggs)
return ham + ' and ' + eggs
高阶函数
map()
函数接收两个参数,一个是函数,一个是Iterable
,map
将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator
返回。
r = map(lambda x: x*x, [1, 2, 3, 4])
print(list(r))
reduce
把一个函数作用在一个序列[x1, x2, x3, ...]
上,这个函数必须接收两个参数,reduce
把结果继续和序列的下一个元素做累积计算。
from functools import reduce
i = reduce(lambda x, y: 10*x + y, [j for j in range(10) if j % 2 != 0])
print(i)
filter()
也接收一个函数和一个序列。和map()
不同的是,filter()
把传入的函数依次作用于每个元素,然后根据返回值是True
还是False
决定保留还是丢弃该元素。
def is_odd(n):
return n % 2 == 1
print(list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])))
yield
用法。
def g(n):
while n > 0:
yield n
n = n - 1
print(g(10))
Python 数据结构
列表
# 定义列表
animals = ['cat', 'dog', 'donkey', 'panda', 'elephant', 'panda']
# count() 计数
print(animals.count('panda')) # 2
# index() 索引
print(animals.index('elephant')) # 4
# reverse() 反转
print(animals.reverse()) # ['panda','elephant', 'panda', 'donkey', 'dog', 'cat']
# append() 添加
print(animals.append('pig')) # ['cat','dog', 'donkey', 'panda', 'elephant', 'panda', 'pig']
# sort() 排序
animals.sort()
print(animals) # ['cat','dog', 'donkey', 'panda', 'elephant', 'panda', 'pig']
# pop() 弹出
print(animals.pop) # pig
# 列表实现栈
stack = [3, 4, 5]
# 入栈
stack.append(6)
# 出栈
stack.pop()
# 列表实现队列
from collections import deque
queue = deque(["Mike", "John", "Tim"])
# 入队
queue.append("Terry")
# 出队
queue.popleft()
元组和序列
# 元组由多个逗号隔开的值组成
tuples = 123, 4455, 'python'
print(t) # (123, 455, 'python')
t = ([1,2,3], [3,2,1])
print(t) # ([1,2,3], [3,2,1])
集合
# 创建集合用 {} 或 set()
basket = {'apple', 'orange', 'apple'}
print(basket) # {'orange', 'banana', 'pear', 'apple'}
a = set('abracadabra')
b = set('alacazam')
print(a - b) # 'r', 'd', 'b'
print(a | b) # 'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'
print(a & b) # 'a', 'c'
print(a ^ b) # 'r', 'd', 'b', 'm', 'z', 'l'
字典
# 字典是键值对
tel = {'jack': 4098, 'sape': 4139}
t = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
# 删除
del tel['jack']
# 添加
tel['irv'] = 4127
# 判断
print('guido' in del) # True
循环技巧
# items() 提取键值对
knights = {'gallahad': 'the pure', 'robin': 'the brave'}
for k, v in knights.items():
print(k, v)
# enumerate() 提取索引和值
for i, v in enumerate(['tic', 'tac', 'toe']):
print(i, v)
# zip() 循环多个序列
questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for q, a in zip(questions, answers):
print('What is your {0}? It is {1}.'.format(q, a))
# reversed() 逆向
for i in reversed(range(1, 10, 2)):
print(i)
# sorted() 排序
basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
for i in sorted(basket):
print(i)
Python IO编程
由于CPU和内存的速度远远高于外设的速度,所以,在IO编程中,就存在速度严重不匹配的问题。同步和异步的区别就在于是否等待IO执行的结果。
文件读写
# 以读文件模式打开一个文件对象
f = open("/Users/local/test.txt", 'r')
# 一次读取文件全部内容
f.read()
# 关闭文件
f.close()
# 用 with 自动关闭文件和处理异常
# f.readline():读取单行数据保留换行符
# f.readline():返回空字符串表示到文件末尾
# f.tell():返回文件对象在文件中的位置
# f.seek(offset, whence):可改变文件对象位置
with open('/Users/local/test.txt', 'r', encoding='gbk') as f:
for line in f.readlines():
print(line.strip()) # 去掉换行符
with open('/Users/local/test.txt', 'w', encoding='gbk') as f:
f.write('Hello, World!')
内存读写
# StringIO 将字符串写入内存
from io import StringIO
f = StringIO()
f.write("Hello")
print(f.getvalue())
# BytesIO 将字节写入内存
from io import BytesIO
f = BytesIO()
f.write('中文'.encode('utf-8'))
print(f.getvalue())
文件和目录操作
# 导入 OS
import os
# 查看当前目录的绝对路径
os.path.abspath('.')
# 新目录完整路径表示
os.path.join('/Users/local', 'testdir')
# 创建目录
os.mkdir('/Users/local/testdir')
# 删除目录
os.rmdir('/Users/local/testdir')
# 文件路径拆分
os.path.split('/Users/local/testdir/file.txt')
# 获取文件拓展名
os.path.splitext('/Users/local/testdir/file.txt')
# 文件重命名
os.rename("file.txt", "file.py")
# 文件删除
os.remove("file.py")
# 列出当前目录下所有目录
[x for x in os.listdir('.') if os.path.isdir(x)]
# 列出所有 .py 文件
[x for x in os.listfir('.') if os.path.isfile(x) and os.paht.splitext(x)[1]='.py']
序列化
把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。
反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
# 将对象序列化为 bytes
import pickle
d = {'name':'Bob', 'age':20, 'score':88}
print(pickle.dumps(d))
# 将序列化的对象写入文件
with open('dump.txt', 'wb') as f:
pickle.dump(d, f)
# 直接读取序列化对象
with open('dump.txt', 'rb') as f:
print(pickle.load(f))
# JSON 格式
import json
d = {'name':'Bob', 'age':20, 'score':88}
print(json.dumps(d))
# 将序列化的对象写入文件
with open('dump.json', 'w') as f:
json.dump(d, f)
# 直接读取序列化对象
with open('dump.json', 'r') as f:
print(json.load(f))
# 类要转换为字典才能被序列化
print(json.dumps(s, default=lambda obj: obj.__dict__))
# 同理,反序列化也是一样的
print(json.loads(json_str, object_hook=dict2student))
字符串格式化
# 格式化字面值
year = 2024
name = 'Mike'
print(f'{name} love {year}')
# str.format() 方法
yes_votes = 42_572_654
no_votes = 43_132_495
percentage = yes_votes / (yes_votes + no_votes)
print('{:-9} YES votes {:2.2%}'.format(yes_votes, percentage))
print('{0}, {1}'.format(yes_votes, percentage))
Python 错误和异常
错误可(至少)被分为两种:语法错误 和 异常。
异常处理
# 单个值异常
while True:
try:
x = int(input("Please enter a number: "))
break
except ValueError:
print("Oops! That was no valid number. Try again...")
# 多个异常处理
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error:", err)
except ValueError:
print("Could not convert data to an integer.")
except Exception as err:
print(f"Unexpected {err=}, {type(err)=}")
raise
# else 子句
for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except OSError:
print('cannot open', arg)
else:
print(arg, 'has', len(f.readlines()), 'lines')
f.close()
异常触发
# raise 强制触发异常
raise NameError('HiThere')
# 只想判断是否有异常但不处理
try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
raise
调用栈
如果错误没有被捕获,它就会一直往上抛,最后被 Python 解释器捕获,打印一个错误信息,然后程序退出。
# 可以记录错误信息
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
try:
bar('0')
except Exception as e:
logging.exception(e)
main()
调试
# assert
def foo(s):
n = int(s)
# 如果 n !=0 就会抛出错误
assert n != 0, 'n is zero!'
return 10 / n
def main():
foo('0')
# logging
# 级别:debug、info、warning、error
import logging
logging.basicConfig(level=logging.INFO)
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
单元测试
单元测试是用来对一个模块、一个函数或一个类来进行正确性检验的测试工作。
# Dict类
class Dict(dict):
def __init__(self, **kw):
super().__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Dict' object has no attribute '%s'" % key)
def __setattr__(self, key, value):
self[key] = value
# Dict测试
"""
assertEqual(abs(-1), 1) 断言函数返回结果与1是否相等
assertRaises(KeyError) 期待抛出指定类型异常
"""
import unittest
from mydict import Dict
class TestDict(unittest.TestCase):
def test_init(self):
d = Dict(a=1, b='test')
self.assertEqual(d.a, 1)
self.assertEqual(d.b, 'test')
self.assertTrue(isinstance(d, dict))
def test_key(self):
d = Dict()
d['key'] = 'value'
self.assertEqual(d.key, 'value')
def test_attr(self):
d = Dict()
d.key = 'value'
self.assertTrue('key' in d)
self.assertEqual(d['key'], 'value')
def test_keyerror(self):
d = Dict()
with self.assertRaises(KeyError):
value = d['empty']
def test_attrerror(self):
d = Dict()
with self.assertRaises(AttributeError):
value = d.empty
# setUP 与 tearDown 分别在测试方法调用前后执行
class TestDice(unittest.TestCase):
def setUp(self):
print('setUp..')
def tearDown(self):
print('tearDown..')
Python 面向对象编程
作用域和命名空间
"""
nonlocal 会改变 scope_test 对 spam 的绑定
global 会改变模块层级的绑定
"""
def scope_test():
def do_local():
spam = "local spam"
def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"
def do_global():
global spam
spam = "global spam"
spam = "test spam"
do_local()
print("After local assignment:", spam)
do_nonlocal()
print("After nonlocal assignment:", spam)
do_global()
print("After global assignment:", spam)
scope_test()
print("In global scope:", spam)
类基础
# 定义一个基础的类
class Dog:
def __init__(self, name):
# 在变量前 __ 就变成私有变量
self.__name = name
self.tricks = []
def add_trick(self, trick):
self.tricks.append(trick)
继承和多态
# 继承基类方法,多态覆盖基类方法
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
pass
# 判断某个变量是否是某个类型
a = Animal()
d = Animal()
print(a, Animal) # True
print(d, Animal) # True
定制类
# __str__ 打印类实例
class Student:
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name: %s)' % self.name
# __repr___ 直接显示变量调用信息
__repr___ = __str___
print(Student("Tom"))
# __iter__ 获取一个迭代对象
class Fib:
def __init___(self):
self.a, self.b = 0, 1
def __iter___(self):
return self
def __next___(self):
self.a, self.b = self.b, self.a + self.b
if self.a > 100_100:
raise StopIteration()
return self.a
# __getitem__ 用下标取出元素
class Fib:
def __getitem__(self, n):
if isinstance(n, int) # n 是索引的时候
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
if isinstance(n, slice) # n 是切片
start = 0 if n.slice is None else n.slice
stop = n.stop
a, b = 1, 1
L = []
for x in range(stop):
if x >= start:
L.append(a)
a, b = b, a + b
return L
# __getattr___ 动态返回一个属性
class Student:
def __init__(self):
self.name = 'Mike'
def __getattr__(self, attr):
if attr=='score':
return 99
elif attr=='age':
return lambda: 25
# __call()__ 直接调用实例
class Student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print('My name is %s.' % self.name)
# Callable 判断调用是对象还是函数
print(callable(Student()))
print(callable([1, 2, 3]))