函数基础
函数的本质就是一功能代码块组织在一个函数名下,可以反复调用
1.去重 函数可以减少代码的重复性。通过将重复的代码逻辑封装成函数。可以避免再不同的地方重复编写相同的代码
**2.解耦 ** 函数对代码的组织结构化可以将代码分成逻辑上独立的模块,提高代码的可读性和可维护性,从而实现解耦
函数的声明和调用
# 声明
def 函数名():
# 函数体【功能模块】
# 调用
函数名()
函数的参数
函数的参数指的是函数定义中声明的变量,用于接收函数调用时传递的数据。参数允许我们将值或引用传递给函数,以便在函数内部进行计算、操作、处理。
函数参数可以有多个,每个参数都有一个名称和类型。函数定义中的参数称为形式参数即形参
,而函数调用时传递的参数成为实际参数实参
。
函数的参数允许函数在不同的上下文中接收不同的数据,并且增加了函数的灵活性和可复用性。
1.内置函数:print,type都需要传参数
2.函数传递参数本质是变量赋值,且该变量只在函数运行时存在,运行结束后销毁
位置参数
位置参数是按照定义时的顺序进行传递的参数。调用函数时,实参的位置必须与形参的位置一一对应。
默认参数
默认参数是在函数声明时为参数指定的默认值。如果在函数调用时没有传递函数的参数,函数将使用默认值。
如果有默认参数,一定要放在非默认参数的后面
关键字参数
关键字参数是通过指定参数名来传递的参数。调用函数时,可以根据参数名来传递实参,而不必遵循形参的顺序。
关键字参数一定要放在位置参数后面
可变参数
可变数量参数允许函数接收不定数量的参数。可以使用特殊符号来表示可变数量的参数,如
*args
用于接收任意数量的位置参数,**kwargs
用于接收任意数量的关键字参数。
函数的作用域
作用域(Scope)是指在程序中定义变量或函数时,这些变量或函数可以被访问的范围。变量和函数的可见性和访问性是不同的。
当访问一个变量时,会按照LEGB
的顺序进行查找,直到找到第一个匹配的变量,然后停止查找。如果在所有作用域中都找不到变量的定义,就会引发NameError。
- L (Local): 局部作用域。包含函数内部定义的变量和参数。在函数内部最先进行变量查找。
- E (Encloaing): 嵌套函数的父函数的作用域。如果在当前函数内部找不到变量,就会向上一层嵌套的函数中查找。
- G (Global):全局作用域。在模块层次定义的变量,对于整个模块都是可见的。
- B (Built-in):内置作用域。包含python的内置函数和异常。
global
关键字用于在函数内部声明一个变量为全局变量,表示在函数内部对该变量的修改将影响到全局作用域中的变量。
nonlocal
关键字用于在函数内部声明一个变量为非本地变量,表示在函数内部对该变量的修改将影响到上一级的嵌套作用域中的变量。
函数的返回值
函数的返回值是指函数执行完毕后,通过return
语句返回给调用者的结果。
使用return
语句可以将一个值或对象作为函数的返回值返回。这个返回值可以是任何有效的python对象,例如数字、字符串、列表、字典等。函数执行到return
语句时,会立即结束函数的执行,并将指定的返回值传递给调用者。
如果函数内没有return,默认返回None,代表没有什么结果返回
常用内置函数
模式 | 功能 |
---|---|
input([promopt]) | 从控制台获取用户输入 |
print() | 将一个或多个对象打印到控制台 |
type(object) | 返回对象的类型 |
range(stop) | 生成一个序列 |
id(object) | 获取对象的内存地址 |
len(s) | 返回对象的长度 |
str(object='') | 将值转换为字符串 |
repr(object) | 返回对象的字符串表示形式 |
int(x=0) | 将一个字符串或数字转换为整数 |
float(x) | 将一个字符串或数字转换为浮点数 |
bool(x) | 将值x转换为布尔值 |
list([iterable]) | 将一个序列转换为列表 |
tuple([iterable]) | 将一个序列转换为元组 |
set([iterable]) | 返回一个新的集合对象 |
bin(x) | 将整数x转换为一个二进制字符串 |
hex(x) | 将整数x转换为十六进制字符串 |
oct(x) | 将整数x转换为八进制字符串 |
abs(x) | 返回x的绝对值 |
pow(x, y[, z]) | 返回x的y次幂,如果z给出,则对其结果取模 |
max(iterable) | 返回序列中最大的元素 |
min(iterable) | 返回序列中最小的元素 |
round(number[, ndigits]) | 将一个数四舍五入到指定的精度 |
sum(iterable) | 返回序列元素的总和 |
divmod(a, b) | 返回a和b的商和余数元组 |
enumrate(iterable, start=0) | 返回枚举对象 |
eval() | 将字符串作为表达式求值,并返回结果 |
ord | 返回字符c的ASCII码 |
chr(i) | 返回证书i对应的ASCII字符 |
reversed(seq) | 返回序列seq的反转序列 |
filter(function, iterable) | 过滤序列,过滤掉不符合条件的元素 |
map(function, iterable) | 对序列中的每个元素应用function函数 |
sorted(iterable |key][reverse]) | 返回一个列表,其中的元素按指定的键排序 |
open() | 打开一个文件,并返回一个文件对象 |
文件操作
字符编码
编码是将字符转换为特定编码标准下的二进制表示形式,而解码则是将二进制数据转换为字符形式。
encoded = text.encoding('utf8')
decoded = encoded.decode('utf8')
文件操作
open(file, mode='r', encoding=None)
模式 | 意义 | 注意事项 |
---|---|---|
r | 只读模式打开文件,读文件内容的指针会放在文件开头 | 操作的文件必须存在 |
rb | 以二进制格式,只读模式打开文件,读文件内容的指针会放在文件开头。一般用于非文本文件,如图片、音频等 | 操作的文件必须存在 |
r+ | 打开文件后,既可以从头读取文件内容,也可以从开头向文件中写入新的内容,写入的新内容会覆盖文件中等长度的原有内容 | 操作的文件必须存在 |
rb+ | 以二进制格式,采用读写模式打开文件,读文件内容的指针会放在文件开头。一般用于非文本文件,如图片、音频等 | 操作的文件必须存在 |
w | 以只写模式打开文件,若文件存在,打开时会清空文件中原有的内容 | 若文件存在,会清空其原有内容,覆盖内容;反之,则创建新文件 |
wb | 以二进制格式,以只写模式打开文件,一般用于非文本文件。 | 若文件存在,会清空其原有内容,覆盖内容;反之,则创建新文件 |
w+ | 打开文件后,会对原有的内容进行清空,并对该文件有读写权限 | 若文件存在,会清空其原有内容,覆盖内容;反之,则创建新文件 |
wb+ | 以二进制格式,读写模式打开,一般用于非文本文件。 | 若文件存在,会清空其原有内容,覆盖内容;反之,则创建新文件 |
a | 追加模式,只写权限。如果文件已存在,文件指针将在文末;反之,会创建新文件 | |
ab | 以二进制格式,追加模式,只写权限。如果文件已存在,文件指针将在文末;反之,会创建新文件 | |
a+ | 以读写模式打开文件。如果文件已存在,文件指针将在文末;反之,会创建新文件 | |
ab+ | 以二进制格式,追加模式,只写权限。如果文件已存在,文件指针将在文末;反之,会创建新文件 |
读文件
# 读取整个文件内容
f.read()
# 读取一行内容
f.readline()
# 读取所有行内容并返回列表
f.readlines()
写文件
# 向文件写入内容
f.write()
# 将字符串列表写入文件中
f.writelines()
with open
# 自动分配并且释放资源
with open("file.txt", "r") as file:
content = file.read()
# 在这里进行文件操作,文件会在代码块结束后自动关闭
常用模块
random模块
random()
生成一个0到1之间的随机浮点数random(a, b)
生成一个指定范围内的随机整数,包括a
和b
choice(seq)
从给定的序列中随机选择一个元素sample(seq, k)
从给定的序列中随机选择k
个元素,返回一个新的列表shuffle(seq)
随机打乱给定序列的顺序
time模块
-
获取当前时间
time()
返回从1970年1月1日午夜开始经过的秒数(Unix时间戳)。
-
时间延迟和暂停
sleep(secs)
暂停指定的秒数。
-
时间戳和时间元组互换
-
localtime([secs])
将秒数转换为当前时区的struct_time对象。 -
mktime(t)
将struct_time对象转换为秒数。 -
gmtime([secs])
将秒数转换为UTC时间的struct_time对象。
-
-
时间格式化
strftime(format, t)
将时间元组对象t按照指定格式format进行格式化输出
datetime模块
datetime类
import datetime
# (1) 获取datetime对象
datetime.datetime.now():返回当前的本地日期和时间。
datetime.datetime.today():返回当前日期的datetime对象(时间部分为0时0分0秒)
# 创建特定日期和时间的对象:
datetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0):创建一个代表特定日期和时间的 datetime 对象。
# (2) datetime对象属性:
datetime_obj.year:年份。
datetime_obj.month:月份。
datetime_obj.day:日期。
datetime_obj.hour:小时。
datetime_obj.minute:分钟。
datetime_obj.second:秒数。
# (3) datetime对象和格式化字符串转换
# datetime对象转为格式化字符串
current_datetime = datetime.datetime.now()
format = "%Y-%m-%d %H:%M:%S"
formatted_datetime = current_datetime.strftime(format)
print(formatted_datetime) # 输出:2022-01-01 12:30:45
print(type(formatted_datetime)) # 输出:<class 'str'>
# 时间字符串转为datetime对象
date_string = "2022-01-01 12:30:45"
format = "%Y-%m-%d %H:%M:%S"
parsed_datetime = datetime.datetime.strptime(date_string, format)
print(parsed_datetime) # 输出:2022-01-01 12:30:45
date类
import datetime
# (1) 获取当前日期对象
today = datetime.date.today()
print(today)
# (2) 日期对象属性:
date_obj.year:年份。
date_obj.month:月份。
date_obj.day:日期。
# (3) date对象转为格式化字符串
today = datetime.date.today()
formatted_date = today.strftime("%Y-%m-%d")
print(formatted_date) # 输出:2024-02-13
timedelta类
timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0):创建一个 timedelta 对象。
timedelta.total_seconds():返回时间间隔的总秒数。
import datetime
# 案例1
from datetime import date
today = date.today()
birthday = date(1998, 5, 15)
age = today - birthday
print("Age:", age.days)
# 案例2
now = datetime.datetime.now()
ret = now + datetime.timedelta(days=3)
print(ret)
sys模块
sys.argv
:命令行参数的列表,包括脚本名称和传递给脚本的参数。sys.exit([arg])
:退出当前程序的执行,并返回可选的错误代码 arg。sys.path
:一个列表,包含用于查找模块的搜索路径。sys.version
:当前 Python 解释器的版本信息。
os模块
- 文件和目录操作:
os.getcwd()
: 获取当前工作目录的路径。os.chdir(path)
: 修改当前工作目录为指定路径。os.listdir(path)
: 返回指定目录中的文件和目录列表。os.mkdir(path)
: 创建一个新的目录。os.makedirs(path)
: 递归创建目录,包括中间目录。os.remove(path)
: 删除指定的文件。os.rmdir(path)
: 删除指定的空目录。os.removedirs(path)
: 递归删除目录,包括所有子目录。os.rename(src, dst)
: 将文件或目录从src重命名为dst。
- 操作系统命令:
os.system(command)
: 执行操作系统命令。os.popen(command)
: 执行操作系统命令,并返回一个文件对象。
- 路径操作:
os.path.join(path1, path2, ...)
: 将多个路径组合成一个路径。os.path.split(path)
: 将路径分割成目录和文件名。os.path.dirname(path)
: 返回路径的目录部分。os.path.basename(path)
: 返回路径的文件名部分。os.path.exists(path)
: 检查路径是否存在。os.path.abspath()
: 返回绝对路径
json模块
序列化是将数据结构或对象转换为字节流(二进制数据)以便存储或传输
反序列化是将字节流还原为原始数据结构或对象的过程
JSON(JavaScript Object Notation, JS 对象标记)是一种轻量级的数据交换格式。
Python | JSON |
---|---|
dict | object |
list, tuple | array |
str | string |
int, float | number |
True | true |
False | false |
None | null |
# 序列化 将本语言支持的高级数据对象转为json格式字符串的过程
num = 3.14
name = 'yuan'
l = [1, 2, 3]
t = (4, 5, 6)
d = {'name': "yuan", 'age': 18, "is_married": False, "gf": None}
print(repr(json.dumps(num))) # '3.14'
print(repr(json.dumps(name))) # '"yuan"'
print(repr(json.dumps(l))) # '[1, 2, 3]'
print(repr(json.dumps(t))) # '[4,5,6]'
print(repr(json.dumps(d))) # '{"name":"yuan","age":18,"is_married":false,"gf":null}'
# 反序列化 将json格式字符串转为本语言支持的数据对象格式
s = '{"name":"yuan","age":18,"isMarried":False}'
# 重点:反序列化前提数据得是json格式的字符串
data = json.loads(s)
print(data, type(data))
s2 = '[{"name":"yuan","age":18,"isMarried":false},{"name":"rain","age":28,"isMarried":true}]'
data2 = json.loads(s2)
print(data2,type(data2))
print(data2[1].get("name"))
日志模块
loguru
from loguru import logger
# 写入到文件
# logger.remove(handle_id=None)
# rotation 配置日志滚动记录的机制:rotation=200MB
logger.add("mylog.log", level='ERROR', ratation="200MB")
# 基本使用,可以打印到console,也可以打印到文件中去
logger.debug("这是一条测试日志")
logger.info("这是一条信息日志")
logger.success("这是一条成功日志")
logger.warning("这是一条警告日志")
logger.error("这是一条错误日志")
logger.critical("这是一条严重错误日志")
# 默认输出格式是:时间、级别、模块、行号以及日志内容
loguru的基本配置
import sys
from loguru import logger
logger.configure(handles=[
{
"sink":sys.stderr, # 表示输出到终端
# 表示日志格式化
"format": "<g><b>{time:YYYY-MM-DD HH:mm:ss.SSS}</b></g> |<lvl>{level:8}</>| {name} : {module}:{line:4} | <c>mymodule</> | - <lvl>{message}</>",
},
{
"sink": 'first.log',
"format": "{time:YYYY-MM-DD HH:mm:ss.SSS} |{level:8}| {name} : {module}:{line:4} | mymodule | - {message}",
"colorize": True
},
])
logger.debug('this is debug')
logger.info('this is info')
logger.warning('this is warning')
logger.error('this is error')
logger.critical('this is critical')
logger.add("mylog.log", level="WARNING", rotation="200 B")
常见key及其描述
Key | Description |
---|---|
time | 发出日志调用时的可感知的本地时间 |
level | 用于记录消息的严重程度 |
name | 进行日志记录调用的__name__ |
module | 进行日志记录调用的模块 |
line | 源代码中的行号 |
message | 记录的消息(尚未格式化) |
function | 进行日志记录调用的函数 |
thread | 进行日志记录调用的线程名 |
process | 进行日志记录调用的进程名 |
file | 进行日志记录调用的文件 |
extra | 用户绑定的属性字典(参见blind()) |
exception | 格式化异常(如果有),否则为None |
elapsed | 从程序开始经过的时间差 |
常用的颜色和样式标签
颜色 | 样式 |
---|---|
黑色(k) | 粗体(b) |
蓝色(e) | 暗淡(d) |
青色(c) | 正常(n) |
绿色(g) | 斜体(i) |
洋红色(m) | 下划线(u) |
红色(r) | 删除线(s) |
白色(w) | 反转(v) |
黄色(y) | 闪烁(l) |
模块与包
模块Module是指一个包含了函数、变量和类等定义的文件,而包Package是指包含了多个模块的目录。
模块(Module)
模块本质上就是一个py
文件
模块一共有三种:
- python标准库
- 第三方模块
- 应用程序自定义模块
模块是组织代码的更高级形式,提高代码的阅读性和可维护性。另外,使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中。
导入模块
关键点:
- 模块与包的命名遵从小写+下划线
- 导入的模块名和函数一样是一等公民
在编程语言中,”一等公民“(first-class-citizen)是指某个实体,(通常是数据类型或值)具有与其他实体相同的权利和特权。它表示在语言中,这些实体可以被像任何其他实体一样对待,可以作为参数传递给函数、赋值给变量、存储到数据结构中,以及作为函数的返回值。
- 使用
import module
导入模块的本质就是,将module.py中的全部代码加载到内存并执行,然后将整个模块内容赋值给与模块同名的变量。 - 导入同一个模块多次,Python只执行一次。
- 在导入模块后,可以在模块文件所在目录下看到一个名为pycache的文件夹,打开该文件夹,可以看到Python为每个模块都生成一个*.cpython-36.pyc文件,该文件其实是python为模块编译生成的字节码,用于提升该模块的运行效率。
语法:
import 模块名1 [as 别名1], 模块名2 [as 别名2], ...
:使用这种语法格式的import语句,会导入指定模块的所有成员,包括变量、函数、类等。不仅如此,当需要使用模块中的成员时,需用该模块名(或别名)作为前缀,否则Python解释器会报错。from 模块名 import 成员名1 [as 别名1] 成员名2 [as 别名2]
:使用这种语法格式的import语句,只会导入模块中指定的成员,而不是全部成员。同时,当程序中使用该成员时,无序附加任何前缀,直接使用成员名或别名即可。
__name__ == '__main__'
当前运行的程序,其__name__
的值为__main__
,而导入到当前程序中的模块,其__name__
值为自己的模块名。因此,__name__ == '__main__'
的作用是确保只有单独运行该模块时,此表达式才成立,才可以进入此判断语法,执行其中的测试代码;反之,如果只是作为模块导入到其他程序文件中,则此表达式不成立,运行其他程序时,也就不会执行该判断语句中的测试代码。
包
包(Package)
使用模块可以有效避免变量名或函数名重名引发的冲突,
包可以避免模块名重复
包就是文件夹,该文件夹下必须存__init__.py
的文件。
包的主要作用就是组织和管理模块,使得代码更加结构化和可维护。包的层次结构可以是多层的,即可以包含子包(子目录)和子模块。
导包
包本质上还是模块,因此导入模块的语法同样适用于导入包。
import 包名[.模块名 [as 别名]]
from 包名1.包名2 import 模块名 [as 别名]
from 包名1.包名2.模块名 import 成员名 [as 别名]
虚拟环境
虚拟环境(Virtual Environment)是Python中用于隔离项目依赖和运行环境的工具。
好处:
- 隔离依赖:每个项目可以有自己的依赖库,不同项目之间的依赖冲突不会发生。
- 简化部署:可以将项目的依赖库和运行环境一起打包,方便在其他计算机上部署和运行。
- 灵活性:可以在不同的项目中使用不同的Python版本,以满足项目的特定需求。
Python内置了vene
模块,用于创建和管理虚拟环境。
- 创建虚拟环境:
打开终端,进入要创建虚拟环境的目录,运行以下命令
python3 -m venv <env_name>
- 激活虚拟环境
# macOS Linux
source myenv/bin/activate
# Windows
myenv\Scripts\activate
激活后,终端的提示符会显示虚拟环境的名称。
- 使用虚拟环境
在激活的虚拟环境中可以安装和管理项目所需的依赖库,运行项目的代码等。所有操作都将在虚拟环境中进行,不会影响全局Python环境和其他虚拟环境。
- 退出虚拟环境
deactivate
- 导出和导入依赖
# 导出依赖到文件
pip freeze > requirements.txt
# 从文件中导入依赖
pip install -r requirements.txt
软件开发目录规范
一个良好的目录结构可以提高代码的可维护性和可扩展性。以下是一些常用的软件开发目录规范和最佳实践:
- 项目根目录:在项目的根目录下,英包含与项目相关的文件和文件夹,如README、LICENSE等。这是整个项目的起点。
- 源代码目录:通常将源代码放在一个独立的目录中。这个目录应该具有描述性的名称,如src、lib或app。在源代码目录下,可以按照项目的模块、功能或层次结构创建子目录。
- 测试目录:测试代码通常位于一个独立的目录中。可以使用如tests、test或spec的目录来存放单元测试、集成测试和其他测试相关的文件。
- 文档目录:为了方便团队成员和用户了解项目和代码的使用方式,可以创建一个文档目录,其中包含项目文档、API文档、用户手册等。
- 配置目录:存放项目的配置文件,如数据库配置、日志配置、环境变量配置等。可以将这些配置文件放在一个名为config或conf的目录下。
- 资源目录:存放项目所需的资源文件,如图像、样式表、静态文件等。可以将这些资源文件放在一个名为assets或resources的目录下。
- 日志目录:存放项目的日志文件,包括运行日志、错误日志等。可以将这些日志文件放在一个名为logs的目录下。
- 其他目录:根据项目的具体需求,可以创建其他目录来存放特定类型的文件,如缓存目录、备份目录等。
一个常见的目录规范示例:
project/
├── docs/ # 文档目录
│ ├── requirements/ # 需求文档
│ ├── design/ # 设计文档
│ └── api/ # API 文档
├── src/ # 源代码目录
│ ├── app/ # 应用代码
│ │ ├── models/ # 模型定义
│ │ ├── views/ # 视图逻辑
│ │ ├── controllers/ # 控制器逻辑
│ │ └── utils/ # 工具函数
│ ├── config/ # 配置文件
│ ├── tests/ # 测试代码
│ └── scripts/ # 脚本文件
├── static/ # 静态资源目录
│ ├── css/ # 样式文件
│ ├── js/ # JavaScript 文件
│ ├── images/ # 图片文件
│ └── fonts/ # 字体文件
├── templates/ # 模板文件目录
├── data/ # 数据文件目录
├── logs/ # 日志文件目录
├── dist/ # 分发版本目录
├── run.py # 用于启动应用程序或执行相关操作的文件。
├── vendor/ # 第三方依赖目录
├── requirements.txt # 依赖包列表
├── README.md # 项目说明文档
└── LICENSE # 许可证文件
上述示例中,主要包含以下目录:
docs/
:用于存放项目的文档,包括需求文档、设计文档和API文档等。src/
:存放项目的源代码,按照模块进行组织,例如app/
目录下存放应用代码,config/
目录下存放配置文件,tests/
目录下存放测试代码等。static/
:存放静态资源文件,例如CSS样式文件、JavaScript文件、图片文件和字体文件等。templates/
:存放模板文件,用于生成动态内容的页面。data/
:存放数据文件,例如数据库文件或其他数据存储文件。logs/
:存放日志文件,记录项目的运行日志。dist/
:存放项目的分发版本,例如编译后的可执行文件或打包后的软件包。vendor/
:存放第三方依赖,例如外部库或框架。requirements.txt
:列出项目所需的依赖包及其版本信息。README.md
:项目说明文档,包含项目的介绍、使用指南和其他相关信息。LICENSE
:许可证文件,定义项目的使用和分发条款。