文章目录
一、Python是用什么语言写的?为什么?
二、Python包管理和环境管理工具有哪些?
1、pip
2、pipenv
3、poetry
4、conda / anaconda
三、Python开发工具
四、Python的数据类型及操作符
1、数字
2、字符
3、列表
4、元组
5、集合
6、字典
五、Python流控制语法
六、Python函数的参数有哪几种?各有什么特点?
1、默认值参数
2、关键字参数
3、特殊参数
4、其它类别
七、local、nonlocal和global关键字的区别
八、Python代码的命名空间
未完待续。。。
一、Python是用什么语言写的?为什么?
Python语言本身最开始是用C语言写的。我们常说的 “Python 解释器”(比如最主流的 CPython)就是用C写成的。下面这张表格展示了当前Python的各种实现,但主流实现还是CPython。
实现名称
用什么语言写的
特点
CPython
C语言
官方标准实现,最常用,占比95%以上
PyPy
Python(RPython 子集)
JIT 编译,运行速度更快
Jython
Java
运行在 JVM 上,可调用 Java 库
IronPython
C#
运行在 .NET 平台上
MicroPython
C
用于嵌入式系统(如树莓派Pico)
【例】当我们用python写一句:
print("Hello World!")
这个print()其实是CPython实现,底层对应的是一个用C写的函数,源码位置大概在Python/bltinmodule.c,参见CPython源码。 那为什么用C来实现呢?可能是Python的创始人Guido van Rossum在 1989 年设计Python时就熟悉 C,因此用C写了解释器。但同时也可归因于C的优势,例如:
C运行快。它是编译型语言,接近底层,运行效率高;
C可移植性强。一次C的编写,轻松在各种平台(Windows、Linux、MacOS)上编译。
二、Python包管理和环境管理工具有哪些?
1、pip
Python官方包管理器,用于安装 / 卸载 PyPI 上的包。常见用法例如:
pip install xxx #安装包
pip uninstall xxx #卸载包
pip freeze > requirements.txt # 导出依赖
pip install -r requirements.txt # 安装指定依赖
以上看出pip的使用非常简单。但是,pip存在一些包依赖管理的缺陷,首先,使用pip需要手动freeze requirements.txt,这意味着如果项目的包依赖或者包的版本发生了变化,而没有及时手动freeze requirements.txt,你的项目在别人那里就可能报错。其次,pip是无法表达依赖来源和层级的,requirements.txt 只是列表,不是结构化文件,不能表达“哪个包依赖了哪个包”。最后,pip不创建隔离环境(所有包安装在全局环境),通常配合virtualenv进行环境手动管理。
2、pipenv
pipenv集成pip和virtualenv,自动创建虚拟环境并锁定依赖。常见用法例如:
# 创建环境并安装包
pipenv install requests
# 进入虚拟环境 shell
pipenv shell
# 生成锁定文件
pipenv lock
pipenv自动创建/管理虚拟环境,自动锁定依赖版本(生成 Pipfile 和 Pipfile.lock),替代传统 requirements.txt。但当前正被poetry逐渐替代。
3、poetry
poetry是一个集依赖管理、打包、发布于一体的工具。常见用法例如:
# 创建新项目
poetry new myproject
# 添加依赖
poetry add requests
# 生成锁定文件
poetry lock
# 构建和发布
poetry build && poetry publish
poetry使用pyproject.toml统一配置(替代setup.py、requirements.txt等),提供更强大且更严格的依赖解析器,并且支持版本自动更新和发布到 PyPI,此外,poetry自动生成 poetry.lock,可精确复现依赖环境。
4、conda / anaconda
conda是跨平台包管理器,支持 Python 及其他语言(如 R、C++),anaconda基于Conda,是预装了科学计算库的 Python 发行版。常见用法如下:
# 创建环境
conda create -n myenv python=3.8
# 激活环境
conda activate myenv
# 安装包
conda install numpy pandas
# 导出环境
conda env export > environment.yml
conda不依赖 PyPI,它有独立的 conda-forge 仓库,它能管理非 Python 依赖(如 CUDA、OpenCV 库)。conda环境隔离更彻底。适用于数据科学 / 机器学习项目(依赖复杂二进制库),多语言混合环境(如 Python+R)。 anaconda包含 1500 + 科学包(如 NumPy、Pandas、Jupyter),它自动处理复杂依赖(如 TensorFlow+Cuda),提供图形界面(Anaconda Navigator)适合新手,也同样适用于需要快速搭建机器学习 / 数据分析环境的场景。
三、Python开发工具
只要能编辑普通文本的工具,都可以用来编写Python代码。如一些轻量级的代码编辑器:
VS Code。开源、插件生态丰富(Python 插件支持智能补全、调试)。常用插件包括Pylance(类型检查)、Jupyter等。
Sublime Text。启动快、自定义性强,适合快速编辑、配置文件修改场景。
Vim/Neovim。键盘操作,适合习惯命令行的开发者。适合服务器端开发、远程编辑。 Python也有一些集成开发环境,比如:
PyCharm。智能代码补全,代码分析(检测未使用变量、PEP8 合规性),支持大量插件,如自动AI插件Codeium。
Jupyter Notebook。一种交互式计算环境,支持 Markdown、可视化。适用于数据科学、机器学习原型开发。Jupyter也有些高级版本,比如JupyterLab、Google Colab。
Spyder。专注科学计算,类似 MATLAB 的界面(变量浏览器、控制台)。适用于数据分析、数值计算(与 Anaconda 集成良好)。
四、Python的数据类型及操作符
1、数字
类型包括:整型、浮点型、复数(如3+5j,后缀为j或J都可)
操作符:+,-,*,/(除),//(向下取整),%(取余),**(乘方),=(赋值)
# _符号会记录上一次的计算结果,但不要显式赋值,否则会成为一个局部变量
3+2 = 5
print(_) #结果为5
2、字符
表示方法:
#单引号和双引号的结果完全相同
print('hello world!') #单引号
print("hello world!") #双引号
print('''hello
world
'''
) #三重单引号
print(' don\'t ') #转移字符\
print(r'usr\local\name') #r避免转义
操作方法:
'hello''world' #字面量直接拼接,不可用于变量
'hello' + 'world' #+符号拼接
'hello' * 3 #重复3次
#以下是索引和切片
word = 'hello'
word[0] #取第一个元素,即h
word[-1] #取最后一个元素,即o
#切片
word[0:3] #取0号位(含)到3号位(不含)的元素,即hel
word[0:] #取0号位(含)到末尾的所有元素,即hello
word[:3] #取开头到3号位(不含)的元素,即hel
word[-2:] #取倒数第二位(含)到末尾的元素,即lo
word[0:100] #切片自动处理越界,输出hello
#字符长度
len(word) #5
#Python的字符串无法更改
word[2] = 'e' # 报错!
3、列表
表示方法:
squares = [1,4,9,16,25] #同类型
examples = [1,'a',2,'bc',3,'def'] #不同类型
操作方法:
#索引和切片与字符操作一样
examples[1] #a
examples[0:3] # [1, 'a', 2]
#合并和添加
squares + [36,49] #[1, 4, 9, 16, 25, 36, 49]
squares.append(36) #[1, 4, 9, 16, 25, 36]
#修改
examples[1] = 'b' #[1, 'b', 2, 'bc', 3, 'def']
examples[0:3] = [0,1] #[0, 1, 'bc', 3, 'def']
#列表赋值给一个变量,实质上是引用,而不是值传递
examples1 = examples
id(examples1) == id(examples) #True
#切片赋值给一个变量,实质上是浅拷贝
squares1 = squares[0:2]
squares1.append(121) # [1, 4, 121]
#列表长度
len(squares) # 6
#列表嵌套,即构造高维
high_dims = [squares,examples] #[[1, 4, 9, 16, 25, 64], [0, 1, 'bc', 3, 'def']]
4、元组
表示方法:
# 元组用逗号(,)隔开的值组成
tupe = 'hello', #单元素,逗号结尾
tupe = 1,2,3,'hello' #多元素
操作方法:
#索引和切片
tupe[0] #1
tupe[0:2] #(1,2)
#嵌套
u = tupe,('a','b','c') # ((1, 2, 3, 'hello'), ('a', 'b', 'c'))
#元组不可变
tupe[0] = 1000 # 报错!
# 解包
a,b,c,d = tupe # a=1,b=2,c=3,d='hello'
#长度
len(tupe) #4
5、集合
表示方法:
set() #空集合
set('abcd') #非空集合
coll = {
'a','b','c','d','d'} #非空集合
操作方法:
coll #只显示不重复项且无序,即{'c', 'a', 'd', 'b'}
#检测集合中是否包含某个值
'a' in coll #True
#集合运算
coll1 = set('abcde')
coll2 = set ('acef')
coll1 - coll2 #差集,{'d', 'b'}
coll1 | coll2 # 或集,{'a', 'c', 'e', 'd', 'b', 'f'}
coll1 & coll2 #交集,{'c', 'a', 'e'}
coll1 ^ coll2 #异或,{'d', 'b', 'f'}
6、字典
表示方法:
dict = {
'a':1, 'b':2, 'c':3}
操作方法:
#索引
dict['a'] # 1
#删除
del dict['b'] #{'a': 1, 'c': 3}
#增加
dict['d'] = 4 #{'a': 1, 'c': 3, 'd': 4}
#键列表
list(dict) #['a', 'c', 'd']
#键排序
sorted(dict) # ['a', 'c', 'd']
#检测某个元素是否存在
'c' in dict # True
五、Python流控制语法
条件语句:if…elif…else…
循环语句:for,while,break,continue,for/while…else
range()生成等差数列
range(4) # range(0, 4),可迭代对象iterable
for i in range(5):
print(i) #0 1 2 3 4,不包括终止值
list(range(5, 10)) #[5, 6, 7, 8, 9]
list(range(0, 10, 3)) #[0, 3, 6, 9]
list(range(-10, -100, -30)) #[-10, -40, -70]
pass:语法上需要一个语句,但程序毋需执行任何动作时
match…case…:匹配一个或零个case。match仅支持Python3.10+版本。它是模式匹配,不像C中switch仅匹配值。_ 是通配符 必须放最后,相当于C中的default。match的类匹配需要 _match_args_ 或解构方法 否则不能通过位置参数匹配属性。
六、Python函数的参数有哪几种?各有什么特点?
1、默认值参数
在定义时为函数的部分参数指定默认值,调用时可以忽略这些默认值参数。例如,
#定义
def f(a,b,c=3):
print(a,b,c)
#调用
f(1,2) #1,2,3
这种方式需要注意的是,当默认值是列表、字典等可变对象时,默认值会累积,避免累积的方法是给默认值参数赋值为None。例如,
def f(a,b=[]):
b.append(a)
print(b)
f(1) # [1]
f(2) # [1,2]
#默认值赋值None
def f(a, L=None):
if L is None:
L = []
L.append(a)
print(L)
f(1) # [1]
f(2) #[2]
2、关键字参数
这种方式重点在函数调用时候,显式给函数参数赋值(即关键字参数)还是隐式赋值(即位置参数)。例如,
def f(a,b=1):
print(a,b)
f(a=1,b=3) #1,3
f(2,3) #2,3
f(a=1,3) #报错了!因为关键字参数必须在位置参数之后
f(1,b=3) # 1,3
f(1,a=3) #报错了!因为这试图在重复给a赋值
f() #报错了!没对a赋值
f(1,c=1) #报错了!未知参数c
另外需要说明的是, *name形参接收一个元组,name形参接收一个字典,*name必须在name之前。
3、特殊参数
这种方式一般用/和*符号将位置参数和关键字参数隔开了。例如,
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
pass
在/之前,调用时只能用位置参数的方式赋值,而*之后,只能用关键字参数的方式赋值,在二者间,既可以用位置参数,也可以用关键字参数的方式赋值。这是为了让代码易读、高效。此外,这种方式还有一些重要作用,比如:
仅使用位置形参时,可以让用户无法使用形参名,可以防止修改形参名导致的调用错误。
形参名有实际意义时,关键字参数调用可以让函数定义更易理解。
4、其它类别
任意数量参数,例如:
def concat(*a, sep="/"):
return sep.join(a)
concat("earth", "mars", "venus") #earth/mars/venus
concat("earth", "mars", "venus", "jupiter", sep=".") # earth.mars.venus.jupiter
解包参数,例如:
def f(a,b,c):
print(a,b,c)
f(*range(0,3)) # 0 1 2,*符号把实参从列表或元组解包出来,同样,字典可以用 ** 操作符传递关键字参数
lambda表达式,一种匿名函数,形如lambda a, b: a+b 函数返回两个参数的和。
七、local、nonlocal和global关键字的区别
python的局部变量默认使用local关键字,它仅限于当前作用域使用,例如:
a = 1
def f():
a = 2
print(a) #1
nonlocal要显式使用,声明当前变量的作用域为当前作用域的外面一层,例如:
def f():
a = 1
def f_sub():
nonlocal a
a = 2
f_sub()
print(a)
f() # 2
global也要显式使用,声明当前变量的作用域为全局,例如:
def f():
a = 1
def f_sub():
global a
a = 2
f_sub()
print(a)
f() # 1
Python作用域的设计是显式优于隐式,就是要指明当前变量的作用域。另外,Python的作用域遵循LEGB 规则,即从里到外四层作用域,从就是从L → E → G → B 顺序查找变量。具体如下:
缩写
名称
举例
L
Local
当前函数内的变量
E
Enclosing
当前函数外一层函数的变量(闭包)
G
Global
当前模块中的全局变量(Python 文件级)
B
Built-in
Python 内建名称(如 len, print)
注意区别以下例子:
# 报错!函数中的a变量是局部变量,不等于函数外的a
a = 1
def f():
a += 1
print(a)
f()
# 报错!no binding for nonlocal 'a' found.nonlocal用于闭包,而非全局
a = 1
def f():
nonlocal a #正确写法应该是 global a
a +=