[Python3] Python 基础教程

1 概述

1.1 简介

  • Python 是一种解释型、面向对象、动态数据类型的高级程序设计语言。
  • Python 由 Guido van Rossum 于 1989 年底发明,第一个公开发行版发行于 1991 年。
  • 像 Perl 语言一样, Python 源代码同样遵循 GPL(GNU General Public License) 协议。
Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。

Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有比其他语言更有特色语法结构。

Python 是一种解释型语言: 这意味着开发过程中没有了编译这个环节。类似于PHP和Perl语言。

Python 是交互式语言: 这意味着,您可以在一个 Python 提示符 >>> 后直接执行代码。

Python 是面向对象语言: 这意味着Python支持面向对象的风格或代码封装在对象的编程技术。

Python 是初学者的语言:Python 对初级程序员而言,是一种伟大的语言,它支持广泛的应用程序开发,从简单的文字处理到 WWW 浏览器再到游戏。
  • Python 2 与 Python 3
  • 官方宣布,2020 年 1 月 1 日, 停止 Python 2 的更新。Python 2.7 被确定为最后一个 Python 2.x 版本。
  • Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。

1.2 第1个Python程序

在线模拟环境(Python3) - 菜鸟教程

#!/usr/bin/python3

print("Hello, World!")
  • Python 常用文件扩展名为 .py。

  • 你可以将以上代码保存在 hello.py 文件中,并使用 python 命令执行该脚本文件。

$ python3 hello.py
Hello, World!

1.3 Python的安装/运维

1.3.0 安装 Python

安装方式1(源码编译方式)

  • 源码编译式安装(python + pip)
  • step1 安装 前置依赖
# 安装 python 的前置依赖 : make
apt-get update
#apt-get -y install vim
apt-get -y install make gcc build-essential

# 安装 pip 的前置依赖: zlib
apt-get -y install zlib1g zlib1g-dev
# yum install zlib*
  • step2 编译安装 python
# 安装 python
PYTHON_VERSION=3.12.10
#curl -o /tmp/python.tgz https://www.python.org/ftp/python/3.12.10/Python-3.12.10.tgz
curl -o /opt/python.tgz https://mirrors.aliyun.com/python-release/source/Python-$PYTHON_VERSION.tgz

tar -zxvf /opt/python.tgz -C /opt/

#### 修改 Setup 文件,以确保后续安装 pip 时,不会因所依赖的 zlib 模块异常而报错 (此步骤,即 取消注释掉如下配置行) | 参考文献: 问题解决zipimport.ZipImportError: can‘t decompress data; zlib not availabl - CSDN - https://blog.csdn.net/loovelj/article/details/90274059
#vim /opt/Python-$PYTHON_VERSION/Modules/Setup
echo 'zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz' >> /opt/Python-$PYTHON_VERSION/Modules/Setup
echo -e "\n" >> /opt/Python-$PYTHON_VERSION/Modules/Setup

cd /opt/Python-$PYTHON_VERSION
./configure
make && make install
  • step3 查验安装信息
# python3 -V
Python 3.12.10

# whereis python3
python3: /usr/local/bin/python3
  • step4 手动安装 pip
  • step5 添加快捷指令 for python / pip
alias python="python3"
alias pip="pip3"

安装方式2(CENTOS)

yum -y install python3

python3 --version

安装方式3(Ubuntu)

# apt -y install python3

# python3 --version
Python 3.9.2

# whereis python3
python3: /usr/bin/python3 /usr/bin/python3.9 /usr/lib/python3 /usr/lib/python3.9 /etc/python3 /etc/python3.9 /usr/local/lib/python3.9 /usr/share/python3

# alias python=python3
  • 推荐文献

安装方式4(基于Ubuntu 24 的 Docker 环境)

此节解决在基于 Ubuntu 24 作为基础镜像 的 Docker 环境中 Python 环境的安装方式(仅供参考)

  • Dockerfile
# OS: Ubuntu 24.04
FROM swr.cn-north-4.myhuaweicloud.com/xxx/eclipse-temurin:17-noble

COPY ./target/*.jar /app.jar
COPY ./target/classes/xxx/ /xxx/

# install : python + pip (前置操作: 更新 apt 源)
RUN sed -i 's#http[s]*://[^/]*#http://mirrors.aliyun.com#g' /etc/apt/sources.list \
  && apt-get update \
  && apt-get -y install vim \
  && apt-get -y install --no-install-recommends python3 python3-pip python3-venv \
  && python3 -m venv $HOME/.venv \
  && . $HOME/.venv/bin/activate \ # 注:Linux 中 高版本 Python (3.5以上),必须在虚拟环境下方可正常安装所需依赖包
  && pip install -i https://mirrors.aliyun.com/pypi/simple/ can cantools
#   && echo "alias python=python3" >> ~/.bashrc \ # Java程序的子进程调用中试验:未此行命令未生效;但开发者独自登录 docker 容器内,有生效
#   && echo '. $HOME/.venv/bin/activate' >> ~/.bashrc \ # Java程序的子进程调用中试验:未此行命令未生效;但开发者独自登录 docker 容器内,有生效
#   && echo 'export PYTHON=$HOME/.venv/bin/python' >> /etc/profile \ # Java程序的子进程调用中试验:未此行命令未生效;但开发者独自登录 docker 容器内,有生效

#  && echo '. /etc/profile' > $HOME/app.sh \ # Java程序的子进程调用中试验:未测通,有衍生问题未解决掉
#  && echo 'java ${JAVA_OPTS:-} -jar app.jar > /dev/null 2>&1 &' >> $HOME/app.sh \  # Java程序的子进程调用中试验:未测通,有衍生问题未解决掉
#  && echo 'java ${JAVA_OPTS:-} -jar app.jar' >> $HOME/app.sh \  # Java程序的子进程调用中试验:未测通,有衍生问题未解决掉
#  && chmod +x $HOME/app.sh \  # Java程序的子进程调用中试验:未测通,有衍生问题未解决掉
#  && chown 777 $HOME/app.sh  # Java程序的子进程调用中试验:未测通,有衍生问题未解决掉


EXPOSE 8080

# ENTRYPOINT exec sh $HOME/app.sh # Java程序的子进程调用中试验:未测通,有衍生问题未解决掉
ENTRYPOINT exec java ${JAVA_OPTS:-} -DPYTHON=$HOME/.venv/bin/python -jar app.jar # 通过 Java 获取 JVM 参数( System.getProperty("PYTHON") ) 方式获取 【 Python 可执行文件的绝对路径】的值
  • Demo : Java 程序中调用 Python
@Slf4j
public class XxxxGenerator implements IGenerator<XxxxSequenceDto> {
    //python jvm 变量 (`-DPYTHON=$HOME/.venv/bin/python`)
    public static String PYTHON_VM_PARAM = "PYTHON";//System.getProperty(PYTHON_VM_PARAM)
    //python 环境变量名称 //eg: "export PYTHON=$HOME/.venv/bin/python" , pythonEnv="$HOME/.venv/bin/python"
    public static String PYTHON_ENV_PARAM = "PYTHON";//;System.getenv(PYTHON_ENV_PARAM);
    private static String PYTHON_COMMAND ;
    //默认的 python 命令
    private static String PYTHON_COMMAND_DEFAULT = "python";
	
	//...

    static {
        PYTHON_COMMAND = loadPythonCommand();
        log.info("PYTHON_COMMAND:{}, PYTHON_VM:{}, PYTHON_ENV:{}", PYTHON_COMMAND, System.getProperty(PYTHON_VM_PARAM), System.getenv(PYTHON_ENV_PARAM) );
		
		//...
    }

    /**
     * 加载 python 命令的可执行程序的路径
     * @note
     *   Linux 中,尤其是 高版本 Python(3.x) ,为避免 Java 通过 `Runtime.getRuntime().exec(args)` 方式 调用 Python 命令时,报找不到 可执行程序(`Python` 命令)\
     *   ————建议: java 程序中使用的 `python` 命令的可执行程序路径,使用【绝对路径】
     * @return
     */
    private static String loadPythonCommand(){
        String pythonVm = System.getProperty(PYTHON_VM_PARAM);
        String pythonEnv = System.getenv(PYTHON_ENV_PARAM);
        String pythonCommand = pythonVm != null?pythonVm : pythonEnv;
        pythonCommand = pythonCommand != null?pythonCommand : PYTHON_COMMAND_DEFAULT;
        return pythonCommand;
    }


    /**
     * CAN ASC LOG 转 BLF
     * @param ascLogFilePath
     * @param blfFilePath
     */
    protected void convertToBlf(File ascLogFilePath, File blfFilePath){
        //CanAsclogBlfConverterScriptPath = "/D:/Workspace/CodeRepositories/xxx-platform/xxx-sdk/xxx-sdk-java/target/classes/bin/can-asclog-blf-converter.py"
        //String CanAsclogBlfConverterScriptPath = CanAscLogGenerator.class.getClassLoader().getResource("bin/can-asclog-blf-converter.py").getPath();

        String canAscLogBlfConverterScriptPath = XxxxGenerator.scriptFilePath;//python 业务脚本的文件路径, eg: "D:\tmp\xxx-sdk\can-asclog-blf-converter.py"

        //String [] args = new String [] {"python", "..\\bin\\can-asclog-blf-converter.py", "-i", ascLogFilePath, "-o", blfFilePath};// ascLogFilePath="/tmp/xxx-sdk/can-1.asc" , blfFilePath="/tmp/xxx-sdk/can-1.blf"
        String [] args = new String [] { PYTHON_COMMAND, canAscLogBlfConverterScriptPath, "-i", ascLogFilePath.getPath(), "-o", blfFilePath.getPath()};
        log.info("args: {} {} {} {} {} {}", args);
        Process process = null;
        Long startTime = System.currentTimeMillis();
        try {
            process = Runtime.getRuntime().exec(args);
            Long endTime = System.currentTimeMillis();
            log.info("Success to convert can asc log file to blf file!ascLogFile:{}, blfFile:{}, timeConsuming:{}ms, pid:{}", ascLogFilePath, blfFilePath, endTime - startTime, process.pid());
        } catch (IOException exception) {
            log.error("Fail to convert can asc log file to blf file!ascLogFile:{}, blfFile:{}, exception:", ascLogFilePath, blfFilePath,  exception);
            throw new RuntimeException(exception);
        }

        //读取 python 脚本的标准输出
        // ---- input stream ----
        List<String> processOutputs = new ArrayList<>();
        try(
            InputStream processInputStream = process.getInputStream();
            BufferedReader processReader = new BufferedReader( new InputStreamReader( processInputStream ));
        ) {
            Long readProcessStartTime = System.currentTimeMillis();
            String processLine = null;
            while( (processLine = processReader.readLine()) != null ) {
                processOutputs.add( processLine );
            }
            process.waitFor();
            Long readProcessEndTime = System.currentTimeMillis();
            log.info("Success to read the can asc log to blf file's process standard output!timeConsuming:{}ms", readProcessEndTime - readProcessStartTime );
            log.info("processOutputs(System.out):{}", JSON.toJSONString( processOutputs ));
        } catch (IOException exception) {
            log.error("Fail to get input stream!IOException:", exception);
            throw new RuntimeException(exception);
        } catch (InterruptedException exception) {
            log.error("Fail to wait for the process!InterruptedException:{}", exception);
            throw new RuntimeException(exception);
        }

        // ---- error stream ----
        List<String> processErrors = new ArrayList<>();
        try(
            InputStream processInputStream = process.getErrorStream();
            BufferedReader processReader = new BufferedReader( new InputStreamReader( processInputStream ));
        ) {
            Long readProcessStartTime = System.currentTimeMillis();
            String processLine = null;
            while( (processLine = processReader.readLine()) != null ) {
                processErrors.add( processLine );
            }
            process.waitFor();
            Long readProcessEndTime = System.currentTimeMillis();
            log.error("Success to read the can asc log to blf file's process standard output!timeConsuming:{}ms", readProcessEndTime - readProcessStartTime );
            log.error("processOutputs(System.err):{}", JSON.toJSONString( processOutputs ));
        } catch (IOException exception) {
            log.error("Fail to get input stream!IOException:", exception);
            throw new RuntimeException(exception);
        } catch (InterruptedException exception) {
            log.error("Fail to wait for the process!InterruptedException:{}", exception);
            throw new RuntimeException(exception);
        }
        if( processErrors.size() > 0 ) {
            throw new RuntimeException( "convert to blf failed!\nerrors:" + JSON.toJSONString(processErrors) );
        }
    }
}
  • 【特别注意】
  • Linux 中,尤其是 高版本 Python(3.x) ,为避免 Java 通过 Runtime.getRuntime().exec(args) 方式 调用 Python 命令时,报找不到 可执行程序(Python 命令)

强烈建议: java 程序中使用的 python 命令的可执行程序路径,使用【绝对路径】

  • 推荐文献

1.3.1 查看安装位置

  • Windows CMD (不支持 Power Shell)
C:\Users\xxx> where python
C:\Users\xxx\AppData\Local\Programs\Python\Python310\python.exe
C:\Users\xxx\AppData\Local\Microsoft\WindowsApps\python.exe

  • Linux
root@xxxbackend-service-xxx-xxx:/# which python3
/usr/bin/python3
 
root@xxxbackend-service-xxx-xxx:/# whereis python3
python3: /usr/bin/python3 /usr/lib/python3 /etc/python3 /usr/share/python3

[Linux] 常用命令之【whereis/which】 - 博客园/千千寰宇

1.3.2 查看版本

  • 方式1 命令行
python --version
python3 --version

或

python -V
python3 -V
  • 方式2 利用 sys 模块
import sys
print(sys.version);
# 或  print(sys.version_info)

  • 方式3 利用 platform 模块
import platform
print(platform.python_version())

1.3.3 退出 command 模式

>>> exit();
xx@yyyy:~$ 

1.3.4 Python 安装包源

  • 官方安装包源
curl -o /tmp/python.tgz https://www.python.org/ftp/python/3.12.10/Python-3.12.10.tgz
  • 第三方安装包源(阿里云)

PYTHON_VERSION=3.12.10
curl -o /opt/python.tgz https://mirrors.aliyun.com/python-release/source/Python-$PYTHON_VERSION.tgz

1.4 Python的发展历程

  • Python 是由 Guido van Rossum 在八十年代末和九十年代初,在荷兰国家数学和计算机科学研究所设计出来的。
  • Python 本身也是由诸多其他语言发展而来的,这包括 ABC、Modula-3、C、C++、Algol-68、SmallTalk、Unix shell 和其他的脚本语言等等。
  • 像 Perl 语言一样,Python 源代码同样遵循 GPL(GNU General Public License)协议。
  • 现在 Python 是由一个核心开发团队在维护,Guido van Rossum 仍然占据着至关重要的作用,指导其进展。
  • Python 2.0 于 2000 年 10 月 16 日发布,增加了实现完整的垃圾回收,并且支持 Unicode。
  • Python 2.7 被确定为最后一个 Python 2.x 版本,它除了支持 Python 2.x 语法外,还支持部分 Python 3.1 语法。
  • Python 3.0 于 2008 年 12 月 3 日发布,此版不完全兼容之前的 Python 源代码。不过,很多新特性后来也被移植到旧的Python 2.6/2.7版本。
  • Python 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。

1.5 Python的语言特点

  1. 易于学习:Python有相对较少的关键字,结构简单,和一个明确定义的语法,学习起来更加简单。
  2. 易于阅读:Python代码定义的更清晰。
  3. 易于维护:Python的成功在于它的源代码是相当容易维护的。
  4. 一个广泛的标准库:Python的最大的优势之一是丰富的库,跨平台的,在UNIX,Windows和Macintosh兼容很好。
  5. 互动模式:互动模式的支持,您可以从终端输入执行代码并获得结果的语言,互动的测试和调试代码片断。
  6. 可移植:基于其开放源代码的特性,Python已经被移植(也就是使其工作)到许多平台。
  7. 可扩展:如果你需要一段运行很快的关键代码,或者是想要编写一些不愿开放的算法,你可以使用C或C++完成那部分程序,然后从你的Python程序中调用。
  8. 数据库:Python提供所有主要的商业数据库的接口。
  9. GUI编程:Python支持GUI可以创建和移植到许多系统调用。
  10. 可嵌入: 你可以将Python嵌入到C/C++程序,让你的程序的用户获得"脚本化"的能力。

1.6 开发环境与工具

Python Command : 原始工具

python

VSCode : 支持Python插件/编程的IDE 【主流】

  • url
  • 定位

VSCode是一款由微软开发的跨平台免费源代码编辑器,支持语法高亮、代码自动补全、调试工具等功能。
它通过插件市场提供丰富的扩展功能,适合中小型项目开发者、Web开发者、数据科学家等使用

PyCharm : 专业的 Python 集成软件开发环境(IDE) 【主流】

  • Reference Document
  • 定位

PyCharm是一款由JetBrains开发的专业Python IDE,分为免费社区版和付费专业版。
它提供智能代码编辑、调试、版本控制等功能,特别适合大型项目开发、数据科学和Web开发。
社区版适合个人学习和小型项目,专业版则包含更多高级功能,适合企业级应用‌

Jupter Lab / Jupter NoteBook 【主流】

  • 定位

Jupyter Notebook适合数据科学家和机器学习开发者,提供了一个交互式计算平台,支持多种编程语言。
它便于数据分析和科学计算,支持通过邮件、GitHub等方式共享笔记,并集成了大数据工具如Apache Spark

  • JupyterLab: 用于交互式数据科学和可视化的集成开发环境(IDE)。
  • https://jupyter.org
  • 支持语言: Jupyter 支持超过 40 种编程语言,包括 Python、R、Julia 和 Scala。

Jupyter是它要服务的三种编程语言(Julia,Python、R)的缩写。

  • Julia 是一个面向科学计算的高性能动态高级程序设计语言。
  • Python 是一门编程语言,具有丰富强大的库。Python 也被称为胶水语言,因为它能够把用其他语言制作的各种模块(尤其是C/C++)很轻松地连在一起。
  • R是用于统计分析、绘图的语言和操作环境。
  • 共享笔记本 : 可以通过电子邮件、Dropbox、GitHub 和Jupyter Notebook Viewer与他人共享笔记本。
  • 交互式输出 : 您的代码可以产生丰富的交互式输出:HTML、图像、视频、LaTeX 和自定义 MIME 类型。
  • 大数据集成 : 利用 Python、R 和 Scala 中的大数据工具(例如 Apache Spark)。使用 pandas、scikit-learn、ggplot2 和 TensorFlow 探索相同的数据。
  • Jupter NoteBook

Jupyter Notebook是基于网页的用于交互计算的应用程序。其可被应用于全过程计算:开发、文档编写、运行代码和展示结果。
Jupyter Notebook 是用于创建和共享计算文档的原始 Web 应用程序。它提供简单、精简、以文档为中心的体验。

在没有Jupyter Notebook之前,在IT领域工作的程序员是这样工作的:
    首先,在普通的 Python shell 或者在IDE(集成开发环境)如Pycharm中写代码,
	然后,在word中写文档来说明他的项目。

这个过程很繁琐,通常是写完代码,再写文档的时候还要重头回顾一遍代码。
最麻烦的地方在于,有些数据分析的中间结果,还要重新跑代码,然后把结果弄到文档里给客户看。

有了Jupyter Notebook之后,程序员的世界突然美好了许多,因为Jupyter Notebook可以直接在代码旁写出叙述性文档,而不是另外编写单独的文档。
也就是,它可以能将代码、文档等这一切集中到一处,让用户一目了然。
  • JupyterLab : 下一代笔记本界面。

是最新的基于 Web 的交互式开发环境,适用于笔记本、代码和数据。
其灵活的界面允许用户配置和安排数据科学、科学计算、计算新闻和机器学习中的工作流程。
模块化设计允许扩展以扩展和丰富功能。

  • 推荐文献

Jupyter 的安装方法有3种:

  • 1、命令行安装 Jupyter Notebook : pip install jupyter
  • 2、VSCode 安装 Jupyter Notebook : Python插件 + Jupyter插件
  • 3、Anaconda 安装 Jupyter Notebook

版本环境管理 : Conda

包管理 : pip

2 Python3 基础语法

基础语法

编码

  • 默认情况下,Python 3 源码文件以 UTF-8 编码,所有字符串都是 unicode 字符串。

当然你也可以为源码文件指定不同的编码:

# -*- coding: cp-1252 -*-

或

#!/usr/bin/env python3.8
# -*- coding: utf-8 -*-

上述定义允许在源文件中使用 Windows-1252 字符集中的字符编码,对应适合语言为保加利亚语、白俄罗斯语、马其顿语、俄语、塞尔维亚语。

标识符

  • 第1个字符必须是字母表中字母或下划线 _ 。
  • 标识符的其他的部分由字母、数字和下划线组成。
  • 标识符对大小写敏感。

在 Python 3 中,可以用中文作为变量名,非 ASCII 标识符也是允许的了。

python保留字

  • 保留字即关键字,我们不能把它们用作任何标识符名称。
  • Python 的标准库提供了一个 keyword 模块,可以输出当前版本的所有关键字:
>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

注释

  • 单行注释 : 以 # 开头

示例

#!/usr/bin/python3
 
# 第一个注释
print ("Hello, Python!") # 第二个注释

out

Hello, Python!
  • 多行注释 : 可以用多个 # 号,还有 ''' 和 """
#!/usr/bin/python3
 
# 第一个注释
# 第二个注释
 
'''
第三注释
第四注释
'''
 
"""
第五注释
第六注释
"""
print ("Hello, Python!")

out

Hello, Python!

行与缩进

  • python最具特色的就是使用缩进来表示代码块,不需要使用大括号 {} 。

  • 缩进的空格数是可变的,但是同一个代码块的语句必须包含相同的缩进空格数。

示例

if True:
    print ("True")
else:
    print ("False")

以下代码最后一行语句缩进数的空格数不一致,会导致运行错误:

if True:
    print ("Answer")
    print ("True")
else:
    print ("Answer")
  print ("False")    # 缩进不一致,会导致运行错误

out

 File "test.py", line 6
    print ("False")    # 缩进不一致,会导致运行错误
                                      ^
IndentationError: unindent does not match any outer indentation level
缩进错误: 取消缩进不匹配任何外部缩进级别

多行语句

  • Python 通常是一行写完一条语句,但如果语句很长,我们可以使用反斜杠 \ 来实现多行语句。

例如:

total = item_one + \
        item_two + \
        item_three
  • 在 [], {}, 或 () 中的多行语句,不需要使用反斜杠 \。

例如:

total = ['item_one', 'item_two', 'item_three',
        'item_four', 'item_five']

变量:无类型、无需声明、使用前必须赋值、赋值后方才被创建 | 变量赋值

  • Python 中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。
  • 在 Python 中,变量就是变量,它没有类型,我们所说的"类型"是变量所指的内存中对象的类型。
  • 等号(=)用来给变量赋值。
  • 等号(=)运算符左边是一个变量名,等号(=)运算符右边是存储在变量中的值。

例如:

#!/usr/bin/python3

counter = 100          # 整型变量
miles   = 1000.0       # 浮点型变量
name    = "test"       # 字符串

print (counter)
print (miles)
print (name)

out

100
1000.0
test
  • 多个变量赋值
  • Python允许你同时为多个变量赋值。例如:
a = b = c = 1

以上实例,创建一个整型对象,值为 1,从后向前赋值,三个变量被赋予相同的数值。
您也可以为多个对象指定多个变量。例如:

a, b, c = 1, 2, "test"

以上实例,两个整型对象 1 和 2 的分配给变量 a 和 b,字符串对象 "test" 分配给变量 c。

标准数据类型

  • Python3 中常见的数据类型有:

  • Number(数字)

  • String(字符串)

  • bool(布尔类型)

  • List(列表)

  • Tuple(元组)

  • Set(集合)

  • Dictionary(字典)

  • Python3 的六个标准数据类型中:

  • 不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组);
  • 可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。
  • string、tuple 和 list 都属于 sequence(序列)。

空行

  • 函数之间或类的方法之间用空行分隔,表示一段新的代码的开始。

  • 类和函数入口之间也用一行空行分隔,以突出函数入口的开始。

  • 空行与代码缩进不同:

  • 空行并不是 Python 语法的一部分。
  • 书写时不插入空行,Python 解释器运行也不会出错。
  • 但是空行的作用在于分隔两段不同功能或含义的代码,便于日后代码的维护或重构。

记住:空行也是程序代码的一部分。

等待用户输入

执行下面的程序在按回车键后就会等待用户输入:

#!/usr/bin/python3
 
input("\n\n按下 enter 键后退出。\n")

以上代码中 ,\n\n 在结果输出前会输出两个新的空行。一旦用户按下 enter 键时,程序将退出。

同一行显示多条语句

  • Python 可以在同一行中使用多条语句,语句之间使用分号 ; 分割

demo

#!/usr/bin/python3
 
import sys; x = 'test'; sys.stdout.write(x + '\n')

使用脚本执行以上代码,输出结果为:

test

使用交互式命令行执行,输出结果为:

>>> import sys; x = 'test'; sys.stdout.write(x + '\n')
test
5

此处的 5 表示字符数,test 有 4 个字符,\n 表示一个字符,加起来 5 个字符。

多个语句构成代码组

  • 缩进相同的一组语句构成一个代码块,我们称之代码组。

  • 像if、while、def和class这样的复合语句,首行以关键字开始,以冒号( : )结束,该行之后的一行或多行代码构成代码组。

  • 我们将首行及后面的代码组称为一个子句(clause)。

if expression : 
   suite
elif expression : 
   suite 
else : 
   suite
  • print 默认输出是换行的,如果要实现不换行需要在变量末尾加上 end="":
#!/usr/bin/python3
 
x="a"
y="b"
# 换行输出
print( x )
print( y )
 
print('---------')
# 不换行输出
print( x, end=" " )
print( y, end=" " )
print()

out

a
b
---------
a b

f-string格式输出

  • f-string格式输出

在Python编程过程中,字符串格式化是一个常见的任务。无论是在输出数据、生成报告还是调试信息时,使用合适的字符串格式化方法显得尤为重要。
Python为此提供了多种字符串格式化的方法,其中最受欢迎的当属f格式输出(f-strings)。

f格式输出是Python 3.6引入的一种字符串格式化方法。
它以"f"或"F"开头,并允许在字符串中嵌入表达式。
通过使用大括号 {} 将变量或表达式包裹起来,你可以直接在字符串中引用它们。

yy = None;
if yy is None : 
  xx=45; print(f"hello, xx :{xx}")

out : hello, 45

f格式输出与其他字符串格式化方法相比,具有以下几个显著优势:

  • 可读性高:通过直观的语法,变量和表达式的插入显得非常自然,使得代码的可读性大大提升。
  • 效率高:f格式输出在性能上通常优于 %-formatting 和 str.format() 方法,尤其是在需要重复格式化的情况下。
  • 支持复杂表达式:你不仅可以插入变量,还可以在大括号内进行复杂的表达式计算和调用函数。
  • 样例:支持复杂表达式的示例
x = 5
y = 10
result = f"The sum of {x} and {y} is {x + y}."
print(result)  # 输出: The sum of 5 and 10 is 15.
  • 样例:格式化数字
pi = 3.14159265358979
formatted_pi = f"Pi is approximately {pi:.2f}."
print(formatted_pi)  # 输出: Pi is approximately 3.14.
  • 样例:列表与字典
# 列表
fruits = ["apple", "banana", "cherry"]
output = f"My favorite fruit is {fruits[1]}."
print(output)  # 输出: My favorite fruit is banana.

# 字段
person = {"name": "Bob", "age": 25}
output = f"{person['name']} is {person['age']} years old."
print(output)  # 输出: Bob is 25 years old.

import 与 from...import

  • import / from...import
  • 在 python 用 import 或者 from...import 来导入相应的模块。
  • 将整个模块(somemodule)导入,格式为: import somemodule
  • 从某个模块中导入某个函数,格式为: from somemodule import somefunction
  • 从某个模块中导入多个函数,格式为: from somemodule import firstfunc, secondfunc, thirdfunc
  • 将某个模块中的全部函数导入,格式为: from somemodule import *

详情参见 : Python import 和 from … import 的主要区别 - 菜鸟教程

  • 导入 sys 模块
import sys
print('================Python import mode==========================')
print ('命令行参数为:')
for i in sys.argv:
    print (i)
print ('\n python 路径为',sys.path)
  • 导入 sys 模块的 argv,path 成员
from sys import argv,path  #  导入特定的成员
 
print('================python from import===================================')
print('path:',path) # 因为已经导入path成员,所以此处引用时不需要加sys.path

命令行参数

  • 很多程序可以执行一些操作来查看一些基本信息,Python可以使用-h参数查看各参数帮助信息:
$ python -h
usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...
Options and arguments (and corresponding environment variables):
-c cmd : program passed in as string (terminates option list)
-d     : debug output from parser (also PYTHONDEBUG=x)
-E     : ignore environment variables (such as PYTHONPATH)
-h     : print this help message and exit

[ etc. ]

传递参数方式 x5

1 位置传参

# 位置传递实例:
def fun1(a,b,c):
  return a+b+c
 
print(fun1(1,2,3))

out

6

2 关键字传参

根据每个参数的名字写入函数参数

 # 关键字传递
 def fun2(a,b,c):
  return a+b+c
 
print(fun2(1,c=3,b=2))

out

6

3 参数默认值传参

给函数的输入参数设定一个默认值,如果该参数最终没有输入,则使用默认参数出入函数.

# 默认值传递
 def fun3(a,b=2,c=3):
  return a+b+c
 
print(fun3(a = 1))

out

6

4 包裹传参

在定义函数时,我们有时候并不知道调用的时候会传递多少个参数。这时候,包裹(packing)【位置参数】或者【关键字参数】来进行参数传递会非常有用。

def fun4(*name):
  print(type(name))
  print(name)
 
fun4([1,2,3])
fun4((1,2,3))
fun4(1,2,3)

在fun4的参数表中,所有的参数被name收集,根据位置合并成一个元组(tuple),这就是包裹位置传递。

<class ‘tuple’>
([1, 2, 3],)
<class ‘tuple’>
((1, 2, 3),)
<class ‘tuple’>
(1, 2, 3)

5 解包裹传递

def func1(a,b=1,*c,**d):
  print(a,b,c,d)  
 
 
l = [3,4]
dic = {'@':2,'#':3}
 
func1(1,2,l,dic)
print("---------**------------")
func1(1,2,*l,**dic)
func1(1,2,3,4,**dic)

out

1 2 ([3, 4], {‘@’: 2, ‘#’: 3}) {}
---------**------------
1 2 (3, 4) {‘@’: 2, ‘#’: 3}
1 2 (3, 4) {‘@’: 2, ‘#’: 3}

X 参考文献

拷贝模式:浅拷贝 & 深拷贝

深拷贝和浅拷贝

  • 浅拷贝:不拷贝子对象的内容,只是拷贝子对象的引用。
  • 深拷贝:会连子对象的内存也全部拷贝一份,对子对象的修改不会影响源对象。

Python 对象赋值的深拷贝与浅拷贝

  • 在 Python 中,对象赋值实际上是对象的引用。

当创建一个对象,然后把它赋值给另一个变量的时候,Python 并没有拷贝这个对象,而只是拷贝了这个对象的引用,我们称之为浅拷贝。
在 Python 中,为了使当进行赋值操作时,两个变量互补影响,可以使用 copy 模块中的 deepcopy 方法,称之为深拷贝。

Python 函数的参数传递: Python 函数的参数传递都是“引用传递”,不是“值传递”

  • 【函数的参数传递】,本质上就是:从实参到形参的【赋值操作】。

Python 中“一切皆对象”,所有的赋值操作都是“引用的赋值”。
所以,Python 中参数的传递都是“引用传递”,不是“值传递”。

  • 具体操作时分为两类:
  • 对“可变对象”进行“写操作”,直接作用于原对象本身。
  • 对“不可变对象”进行“写操作”,会产生一个新的“对象空间”,并用新的值填充这块空间。(起到其他语言的“值传递”效果,但不是“值传递”)
  • 可变对象有:

字典、列表、集合、自定义的对象等

  • 不可变对象有:

数字、字符串、元组、function 等

  • 为了更深入的了解参数传递的底层原理,我们需要讲解一下“浅拷贝和深拷贝”。

我们可以使用内置函数:copy(浅拷贝)、deepcopy(深拷贝)。

传递可变对象的引用

  • 传递参数是可变对象,实际传递的还是对象的引用。在函数体中不创建新的对象拷贝,而是可以直接修改所传递的对象。(这个和C语言中传递指针一样)

例如:列表、字典、自定义的其他可变对象等。

  • 示例
    ``python
    b = [10,20]

def f2(m):
print("m:",id(m)) #b 和 m 是同一个对象
m.append(30) #由于 m 是可变对象,不创建对象拷贝,直接修改这个对象b:

f2(b)
print("b:",id(b))
print(b)


> 执行结果:
```log
m: 45765960
b: 45765960
[10, 20, 30]

传递不可变对象的引用

  • 传递参数是不可变对象,实际传递的还是对象的引用。在”赋值操作”时,由于不可变对象无法修改,系统会新创建一个对象。

不会修改原传入参数,在对传入的不可变对象进行修改操作时,会新建一个新的对象。
例如:int、float、字符串、元组、布尔值

  • 示例
a = 100

def f1(n):
	print("n:",id(n)) # 传递进来的是 a 对象的地址
	n = n+200         # 由于 a 是不可变对象,因此创建新的对象 n
	print("n:",id(n)) # n 已经变成了新的对象
	print(n)

f1(a)
print("a:",id(a))

执行结果:

n: 1663816464
n: 46608592
300
a: 1663816464

显然,通过 id 值我们可以看到 n 和 a 一开始是同一个对象。给 n 赋值后,n 是新的对象。

传递【不可变对象】包含的【子对象是可变对象】的情况

  • 示例
# 不可变对象
a = 100

def f1(n):
    print("n:",id(n)) #传递进来的是 a 对象的地址
    n = n+200 #由于 a 是不可变对象,因此创建新的对象 n
    print("n:",id(n))
    #n 已经变成了新的对象
    # print(n)

f1(a)
print("a:",id(a))

out

a: 41611632
m: 41611632
(10, 20, [888, 6])
m: 41611632
(10, 20, [888, 6])
  • 示例
# 浅拷贝和深拷贝
import copy

def testCopy():
    '''测试浅拷贝'''
    a = [10, 20, [5, 6]]
    b = copy.copy(a)
    print("a", a)
    print("b", b)
    b.append(30)
    b[2].append(7)
    print("浅拷贝......")
    print("a", a)
    print("b", b)

def testDeepCopy():
    '''测试深拷贝'''
    a = [10, 20, [5, 6]]
    # 深拷贝
    b = copy.deepcopy(a)
    print("a", a)
    print("b", b)
    b.append(30)
    b[2].append(7)
    print("深拷贝......")
    print("a", a)
    print("b", b)

testCopy()

print("*************")

testDeepCopy()

out

a [10, 20, [5, 6]]
b [10, 20, [5, 6]]

浅拷贝…
a [10, 20, [5, 6, 7]]
b [10, 20, [5, 6, 7], 30]
“*************”
a [10, 20, [5, 6]]
b [10, 20, [5, 6]]

深拷贝…
a [10, 20, [5, 6]]
b [10, 20, [5, 6, 7], 30]

List对象的append()函数

  • 当 list 类型的对象进行 append 操作时,实际上追加的是该对象的引用。

对象的id()函数

  • id() 函数:返回对象的唯一标识,可以类比成该对象在内存中的地址。
>>> alist = []
>>> num = [2]
>>> alist.append( num )
>>> id( num ) == id( alist[0] )
True

如上例所示,当 num 发生变化时(前提是 id(num) 不发生变化),alist 的内容随之会发生变化。往往会带来意想不到的后果,想避免这种情况,可以采用深拷贝解决:
alist.append( copy.deepcopy( num ) )

numpy 模块的深拷贝与浅拷贝

Y 参考文献

Y FAQ for Python

Q: Python工程中,如何安装自己写的模块?

  • 要在 Python 中安装自己写的模块,有几种方法,具体取决于你的需求和模块的复杂度

方式1: setup.py + pip install + 本地模块

  1. 使用 pip 安装本地模块
    如果你想要用 pip 安装自己的模块,可以将模块打包成标准格式。假设你的模块结构如下:
my_module/
├── my_module/
│   ├── __init__.py
│   └── my_script.py
├── setup.py
└── README.md

setup.py 是打包的关键文件,内容如下

from setuptools import setup, find_packages

setup(
    name="my_module",            # 模块名
    version="0.1",               # 版本号
    packages=find_packages(),    # 自动查找子包
    install_requires=[],         # 依赖库
    description="My custom module",
    author="Your Name",
    author_email="your.email@example.com"
)

步骤:

  • 在模块的根目录下(即 setup.py 所在的目录),打开终端。
  • 运行以下命令:pip install .

这会将 my_module 安装到 Python 环境中,使其可以在任何地方导入。

  1. 使用 pip 本地链接安装

如果你在开发中不断修改模块,想要在更改后自动生效,可以使用 pip 的开发模式进行安装:

pip install -e .

此时安装的是模块的符号链接版本,修改源代码后无需重新安装。

重新安装的方式: (样例,如: 自定义的模块 autosar)

pip uninstall autosar
pip install .
  1. 手动复制文件

如果只是一个简单的 .py 文件,可以直接将其放入 Python 项目的目录中,或者复制到 Python 的 site-packages 目录下。

  1. 使用 PYTHONPATH

可以将模块所在的路径添加到 PYTHONPATH 环境变量中。例如:

export PYTHONPATH=$PYTHONPATH:/path/to/your/module

这样可以直接在代码中导入模块。

方式2: project.toml + pip install + 本地模块

  • 推荐文献/参考

Intro

最近打算构建一些开源工具套件,想着能不能把 ruff, darglint, mypy 这些 lint 工具全部 all in one 整合一下,化简配置流程,因此详细看了一下这些框架是怎么做 pyproject.toml 配置的。

在 Python 项目开发的历史长河中,我们经历了从 setup.py 到 requirements.txt,再到 setup.cfg 的变迁。

所以你可以看到到 python 会有各种各样的配置文件,属实有点头疼,各种工具链也到处配置,真的不让人省心...

而现在,pyproject.toml 的出现标志着 Python 项目管理进入了一个新的时代,本文会详细解读一下这个现代 Python 项目管理的核心配置文件。

为什么需要 pyproject.toml?

在传统的 Python 项目中,我们往往需要维护多个配置文件:

  • setup.py 用于项目打包
  • requirements.txt 管理依赖
  • setup.cfg 存放项目元数据
  • 各种工具的配置文件(.pylintrc、pytest.ini 等)

这种分散的配置方式带来了几个问题:

  1. 配置分散,难以统一管理
  2. 不同文件格式增加学习成本
  3. 工具配置可能存在冲突
  4. 项目结构不够清晰

pyproject.toml 的出现就是为了解决这些问题。它提供了一个集中的、标准化的配置方式,让项目管理变得更加简单和清晰。

pyproject.toml 的标准之路

PEP 518:奠定基础

2016 年,PEP 518 提案定义了 pyproject.toml 文件的基本结构和构建系统规范。这个提案主要解决了 Python 项目构建时的依赖问题,让构建过程变得更加可靠。

Link: https://peps.python.org/pep-0518/

PEP 621:统一项目元数据

2020 年,PEP 621 进一步规范化了项目元数据的格式,使得不同的构建后端都能以统一的方式处理项目信息。

Link: https://peps.python.org/pep-0621/

pyproject.toml 的核心结构

1. 构建系统配置

[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"

这部分定义了构建项目所需的工具和后端。

2. 项目元数据

[project]
name = "your-awesome-project"
version = "0.1.0"
description = "一个很棒的项目"
authors = [
    {name = "作者名", email = "author@example.com"}
]
dependencies = [
    "requests>=2.24.0",
    "pandas>=1.0.0"
]

这里包含了项目的基本信息和依赖要求。

3. 开发依赖和可选功能

[project.optional-dependencies]
dev = ["pytest", "black", "mypy"]
docs = ["sphinx", "sphinx-rtd-theme"]

你可以定义不同场景下需要的额外依赖。

4. 工具配置

[tool.black]
line-length = 88
target-version = ['py37']

[tool.isort]
profile = "black"

[tool.pytest.ini_options]
minversion = "6.0"
addopts = "-ra -q"

各种开发工具的配置都可以统一在这里管理。

现代化工具支持

现代 Python 项目管理工具都对 pyproject.toml 提供了很好的支持:

  1. Poetry:完全基于 pyproject.toml 的依赖管理工具
  2. PDM:新一代 Python 包管理器
  3. Hatch:现代化的项目管理工具
  4. Rye:新兴的 Python 项目管理工具

自定义配置信息

如果你有一些自己的配置信息,自己读取 pyproject.toml 也很简单,就像读取 json,yaml 一样,下面是一个示例代码:

import tomli  # For Python < 3.11
# For Python 3.11+, you can use: import tomllib

def read_pyproject_toml(file_path="pyproject.toml"):
    """
    读取并解析 pyproject.toml 文件

    Args:
        file_path (str): pyproject.toml 文件的路径

    Returns:
        dict: 解析后的 TOML 内容
    """
    try:
        with open(file_path, mode="rb") as fp:
            # 使用 rb (二进制读取模式) 来避免编码问题
            toml_dict = tomli.load(fp)
            return toml_dict
    except FileNotFoundError:
        print(f"错误: 找不到文件 '{file_path}'")
        return None
    except Exception as e:
        print(f"解析 TOML 文件时出错: {str(e)}")
        return None

def print_project_info(toml_dict):
    """
    打印项目主要信息

    Args:
        toml_dict (dict): 解析后的 TOML 字典
    """
    if not toml_dict:
        return

    # 打印项目基本信息
    if "project" in toml_dict:
        project = toml_dict["project"]
        print("项目信息:")
        print(f"名称: {project.get('name', '未指定')}")
        print(f"版本: {project.get('version', '未指定')}")
        print(f"描述: {project.get('description', '未指定')}")
        print(f"作者: {project.get('authors', ['未指定'])}")

        # 打印依赖信息
        if "dependencies" in project:
            print("\n依赖项:")
            for dep in project["dependencies"]:
                print(f"- {dep}")

    # 打印构建系统信息
    if "build-system" in toml_dict:
        build_system = toml_dict["build-system"]
        print("\n构建系统:")
        print(f"构建后端: {build_system.get('build-backend', '未指定')}")
        print(f"依赖项: {build_system.get('requires', [])}")

def main():
    # 读取并解析 TOML 文件
    toml_dict = read_pyproject_toml()

    if toml_dict:
        # 打印完整的解析结果
        print("完整的 TOML 内容:")
        print(toml_dict)
        print("\n" + "="*50 + "\n")

        # 打印格式化的项目信息
        print_project_info(toml_dict)

if __name__ == "__main__":
    main()

需要注意的是:

  • Python < 3.11 需要安装 tomli: pip install tomli
  • Python 3.11+ 可以直接使用内置的 tomllib

至此,大致就可以理解各种工具链是如何配置的自己的参数了,当然如何更好地配置,还是要看官方文档(虽然有些文档真的写的很烂,如 darglint)。

Y 推荐文献

  • Python
  • 菜鸟教程

X 参考文献

  • QPython OH : Qpython是一个轻量级的、成熟的python编程工具。它配有终端和简单的代码编辑器。它支持安装第三方库。目前,它支持Python 3.6.6,这还不算太老。
  • Aid Learning : 一款很酷的高端移动编程工具,可以直接在app Store中下载和安装。
  • 现代 Python 项目管理:pyproject.toml 完全指南 - Zhihu
posted @ 2024-09-11 10:54  千千寰宇  阅读(334)  评论(0)    收藏  举报