[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(集合)。
  • stringtuplelist 都属于 sequence(序列)。

数据类型的判别

  • 内置的 type() 函数可以用来查询变量所指的对象类型
>>> a, b, c, d = 20, 5.5, True, 4+3j
>>> print(type(a), type(b), type(c), type(d))
<class 'int'> <class 'float'> <class 'bool'> <class 'complex'>
  • 也可以用 isinstance 来判断:
>>> a = 111
>>> isinstance(a, int)
True
>>>
  • isinstancetype() 的区别在于:
  • type() : 不会认为子类是一种父类类型。
  • isinstance() : 会认为子类是一种父类类型。
>>> class A:
...     pass
... 
>>> class B(A):
...     pass
... 
>>> isinstance(A(), A)
True
>>> type(A()) == A 
True
>>> isinstance(B(), A)
True
>>> type(B()) == A
False
  • issubclass / is

案例:Python3 中,bool 是 int 的子类,True 和 False 可以和数字相加, True1、False0 会返回 True,但可以通过 is 来判断类型。

>>> issubclass(bool, int) 
True
>>> True==1
True
>>> False==0
True
>>> True+1
2
>>> False+1
1
>>> 1 is True
False
>>> 0 is False
False

删除引用

  • 您也可以使用del语句删除一些对象引用。
  • del语句的语法是:
del var1[,var2[,var3[....,varN]]]
  • 您可以通过使用del语句删除单个或多个对象。例如:
del var
del var_a, var_b

数值运算

>>> 5 + 4  # 加法
9
>>> 4.3 - 2 # 减法
2.3
>>> 3 * 7  # 乘法
21
>>> 2 / 4  # 除法,得到一个浮点数
0.5
>>> 2 // 4 # 除法,得到一个整数
0
>>> 17 % 3 # 取余
2
>>> 2 ** 5 # 乘方
32
  • 1、Python可以同时为多个变量赋值,如a, b = 1, 2。
  • 2、一个变量可以通过赋值指向不同类型的对象。
  • 3、数值的除法包含两个运算符:/ 返回一个浮点数,// 返回一个整数。
  • 4、在混合计算时,Python会把整型转换成为浮点数

数值类型的示例

int float complex
10 0.0 3.14j
100 15.20 45.j
-786 -21.9 9.322e-36j
080 32.3e+18 .876j
-0490 -90. -.6545+0J
-0x260 -32.54e100 3e+26J
0x69 70.2E-12 4.53e-7j
  • Python 还支持复数,复数由实数部分和虚数部分构成,可以用 a + bj,或者 complex(a,b) 表示, 复数的实部 a 和虚部 b 都是浮点型。

数字(Number)类型

  • python中数字有4种类型:int(整型)、float(浮点数)、bool(布尔值)、complex(复数)
  • int (整数), 如 1, 只有一种整数类型 int,表示为长整型,没有 python2 中的 Long。
  • bool (布尔), 如 True / False。
  • Python3 中,boolint子类TrueFalse 可以和数字相加, True1、False0 会返回 True,但可以通过 is 来判断类型。
  • Python2 中是没有布尔型的,它用数字 0 表示 False,用 1 表示 True。
  • float (浮点数), 如 1.23、3E-2
  • complex (复数) - 复数由实部和虚部组成,形式为 a + bj,其中 a 是实部,b 是虚部,j 表示虚数单位。如 1 + 2j、 1.1 + 2.2j
  • 当你指定一个值时,Number 对象就会被创建:
var1 = 1
var2 = 10

字符串(String)类型

  • Python中的字符串用单引号 ' 或双引号 " 括起来,同时使用反斜杠 \ 转义特殊字符。
  • Python 中单引号 ' 和双引号 " 使用完全相同。
  • 使用三引号('''""")可以指定一个多行字符串。
  • 转义符 \
  • 反斜杠\可以用来转义,使用 r 可以让反斜杠不发生转义。

r"this is a line with \n"\n 会显示,并不是换行。

  • 按字面意义级联字符串,如 "this " "is " "string" 会被自动转换为 this is string
  • 字符串可以用 + 运算符连接在一起,用 * 运算符重复。
  • Python 中的字符串有两种索引方式,从左往右以 0 开始,从右往左以 -1 开始。
  • Python 中的字符串不能被修改
  • 与 C 字符串不同的是,Python 字符串不能被改变。向一个索引位置赋值,比如 word[0] = 'm' 会导致错误。
  • Python 没有单独的字符类型,一个字符就是长度为 1 的字符串。

  • 字符串的截取/切片

  • str[start:end]
  • 其中, start(包含)是切片开始的索引,end(不包含)是切片结束的索引。
  • 索引值以 0 为开始值,-1 为从末尾的开始位置。
  • 字符串切片可以加上步长参数 step,语法格式:str[start:end:step]

word = '字符串'
sentence = "这是一个句子。"
paragraph = """这是一个段落,
可以由多行组成"""
  • Demo
#!/usr/bin/python3
 
str='123456789'
 
print(str)                 # 输出字符串
print(str[0:-1])           # 输出第一个到倒数第二个的所有字符
print(str[0])              # 输出字符串第一个字符
print(str[2:5])            # 输出从第三个开始到第六个的字符(不包含)
print(str[2:])             # 输出从第三个开始后的所有字符
print(str[1:5:2])          # 输出从第二个开始到第五个且每隔一个的字符(步长为2)
print(str * 2)             # 输出字符串两次
print(str + '你好')         # 连接字符串
 
print('------------------------------')
 
print('hello\nworld')      # 使用反斜杠(\)+n转义特殊字符
print(r'hello\nworld')     # 在字符串前面添加一个 r,表示原始字符串,不会发生转义

这里的 r 指 raw,即 raw string,会自动将反斜杠转义,例如:

>>> print('\n')       # 输出空行

>>> print(r'\n')      # 输出 \n
\n
>>>

以上代码的输出:

123456789
12345678
1
345
3456789
24
123456789123456789
123456789你好
------------------------------
hello
world
hello\nworld

布尔(bool)类型

  • 布尔类型只有两个值:True 和 False。

  • Python 中,TrueFalse 都是关键字,表示布尔值。

  • 布尔类型可以用来控制程序的流程,比如判断某个条件是否成立,或者在某个条件满足时执行某段代码。

  • boolint 的子类。

因此,布尔值可以被看作整数来使用,其中 True 等价于 1。
Python 3 支持 bool 类型

Python3 中,bool 是 int 的子类,True 和 False 可以和数字相加, True1、False0 会返回 True,但可以通过 is 来判断类型。

>>> issubclass(bool, int) 
True
>>> True==1
True
>>> False==0
True
>>> True+1
2
>>> False+1
1
>>> 1 is True
False
>>> 0 is False
False

在 Python2 中是没有布尔型的,它用数字 0 表示 False,用 1 表示 True

  • 布尔类型可以和其他数据类型进行比较

比如,数字、字符串等。在比较时,Python 会将 True 视为 1,False 视为 0。

  • 布尔类型可以和逻辑运算符一起使用,包括 and、or 和 not。

这些运算符可以用来组合多个布尔表达式,生成一个新的布尔值。

  • 布尔类型也可以被转换成其他数据类型

比如整数、浮点数和字符串。
在转换时,True 会被转换成 1,False 会被转换成 0。

  • 可以使用 bool() 函数将其他类型的值转换为布尔值

这些值在转换为布尔值时为 False:

  • None、False、零 (0、0.0、0j)、空序列(如 ''、()、[])和空映射(如 {})。
    其他所有值转换为布尔值时均为 True。

在 Python 中,所有非零的数字和非空的字符串、列表、元组等数据类型都被视为 True;
只有 0、空字符串、空列表、空元组等被视为 False。因此,在进行布尔类型转换时,需要注意数据类型的真假性。

  • demo
# 布尔类型的值和类型
a = True
b = False
print(type(a))  # <class 'bool'>
print(type(b))  # <class 'bool'>

# 布尔类型的整数表现
print(int(True))   # 1
print(int(False))  # 0

# 使用 bool() 函数进行转换
print(bool(0))         # False
print(bool(42))        # True
print(bool(''))        # False
print(bool('Python'))  # True
print(bool([]))        # False
print(bool([1, 2, 3])) # True

# 布尔逻辑运算
print(True and False)  # False
print(True or False)   # True
print(not True)        # False

# 布尔比较运算
print(5 > 3)  # True
print(2 == 2) # True
print(7 < 4)  # False

# 布尔值在控制流中的应用
if True:
    print("This will always print")
    
if not False:
    print("This will also always print")
    
x = 10
if x:
    print("x is non-zero and thus True in a boolean context")

元组(Tuple)类型

  • 元组(tuple)与列表类似,不同之处在于元组的元素不能修改。元组写在小括号 () 里,元素之间用逗号隔开。
  • 元组中的元素类型也可以不相同:
#!/usr/bin/python3

tuple = ( 'abcd', 786 , 2.23, 'runoob', 70.2  )
tinytuple = (123, 'runoob')

print (tuple)             # 输出完整元组
print (tuple[0])          # 输出元组的第一个元素
print (tuple[1:3])        # 输出从第二个元素开始到第三个元素
print (tuple[2:])         # 输出从第三个元素开始的所有元素
print (tinytuple * 2)     # 输出两次元组
print (tuple + tinytuple) # 连接元组

output

('abcd', 786, 2.23, 'runoob', 70.2)
abcd
(786, 2.23)
(2.23, 'runoob', 70.2)
(123, 'runoob', 123, 'runoob')
('abcd', 786, 2.23, 'runoob', 70.2, 123, 'runoob')
  • 元组与字符串类似,可以被索引且下标索引从0开始,-1 为从末尾开始的位置。也可以进行截取(看上面,这里不再赘述)。

  • demo

>>> tup = (1, 2, 3, 4, 5, 6)
>>> print(tup[0])
1
>>> print(tup[1:5])
(2, 3, 4, 5)
>>> tup[0] = 11  # 修改元组元素的操作是非法的
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>>
  • 虽然tuple的元素不可改变,但它可以包含可变的对象,比如list列表。

构造包含 0 个或 1 个元素的元组比较特殊,所以有一些额外的语法规则:

tup1 = ()    # 空元组
tup2 = (20,) # 一个元素,需要在元素后添加逗号
  • 如果你想创建只有一个元素的元组,需要注意在元素后面添加一个逗号,以区分它是一个元组而不是一个普通的值

这是因为在没有逗号的情况下,Python会将括号解释为数学运算中的括号,而不是元组的表示。
如果不添加逗号,如下所示,它将被解释为一个普通的值而不是元组:

not_a_tuple = (42)

这样的话,not_a_tuple 将是整数类型而不是元组类型。
string、list 和 tuple 都属于 sequence(序列)。

列表/数组(List)类型

  • List(列表) 是 Python 中使用最频繁的数据类型。

  • 列表可以完成大多数集合类的数据结构实现。列表中元素的类型可以不相同,它支持数字,字符串甚至可以包含列表(所谓嵌套)。

  • 列表是写在方括号 [] 之间、用逗号,分隔开的元素列表。

  • 字符串一样,列表同样可以被索引截取,列表被截取后返回一个包含所需元素的新列表。

  • 列表截取的语法格式:

变量[头下标:尾下标]
  • 索引值以 0 为开始值,-1 为从末尾的开始位置

  • 加号 + 是列表连接运算符,星号 * 是重复操作。

demo

#!/usr/bin/python3

list = [ 'abcd', 786 , 2.23, 'runoob', 70.2 ]  # 定义一个列表
tinylist = [123, 'runoob']

print (list)            # 打印整个列表
print (list[0])         # 打印列表的第一个元素
print (list[1:3])       # 打印列表第二到第四个元素(不包含第四个元素)
print (list[2:])        # 打印列表从第三个元素开始到末尾
print (tinylist * 2)    # 打印tinylist列表两次
print (list + tinylist)  # 打印两个列表拼接在一起的结果

output

['abcd', 786, 2.23, 'runoob', 70.2]
abcd
[786, 2.23]
[2.23, 'runoob', 70.2]
[123, 'runoob', 123, 'runoob']
['abcd', 786, 2.23, 'runoob', 70.2, 123, 'runoob']
  • 与Python字符串不一样的是,列表中的元素是可改变/修改
>>> a = [1, 2, 3, 4, 5, 6]
>>> a[0] = 9
>>> a[2:5] = [13, 14, 15]
>>> a
[9, 2, 13, 14, 15, 6]
>>> a[2:5] = []   # 将对应的元素值设置为 [] 
>>> a
[9, 2, 6]
  • List 内置了有很多方法,如 append()、pop() 等等

  • Python 列表截取可以接收第3个参数,参数作用是截取的步长

demo : 以下实例在索引 1 到索引 4 的位置并设置为步长为 2(间隔一个位置)来截取字符串

如果第三个参数为负数表示逆向读取

以下实例用于翻转字符串:

def reverseWords(input): 
      
    # 通过空格将字符串分隔符,把各个单词分隔为列表
    inputWords = input.split(" ") 
  
    # 翻转字符串
    # 假设列表 list = [1,2,3,4],  
    # list[0]=1, list[1]=2 ,而 -1 表示最后一个元素 list[-1]=4 ( 与 list[3]=4 一样) 
    # inputWords[-1::-1] 有三个参数
    # 第一个参数 -1 表示最后一个元素
    # 第二个参数为空,表示移动到列表末尾
    # 第三个参数为步长,-1 表示逆向
    inputWords=inputWords[-1::-1] 
  
    # 重新组合字符串
    output = ' '.join(inputWords) 
      
    return output 
  
if __name__ == "__main__": 
    input = 'I like test'
    rw = reverseWords(input) 
    print(rw)

output

test like I

集合(Set)类型

  • Python 中的集合Set)是一种无序可变的数据类型,用于存储唯一的元素。

  • 集合中的元素不会重复,并且可以进行交集并集差集等常见的集合操作

  • 在 Python 中,集合使用大括号 {} 表示,元素之间用逗号 , 分隔。

  • 另外,也可以使用 set() 函数创建集合。

注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。

  • 创建格式:
parame = {value01,value02,...}

或者

set(value)
  • demo
#!/usr/bin/python3

sites = {'Google', 'Taobao', 'Tencent', 'Facebook', 'Zhihu', 'Baidu'}

print(sites)   # 输出集合,重复的元素被自动去掉

# 成员测试
if 'Tencent' in sites :
    print('Tencent 在集合中')
else :
    print('Tencent 不在集合中')


# set可以进行集合运算
a = set('abracadabra')
b = set('alacazam')

print(a)
print( len(a) )         # 获取 a set 的元素个数

print(a - b)     # a 和 b 的差集

print(a | b)     # a 和 b 的并集

print(a & b)     # a 和 b 的交集

print(a ^ b)     # a 和 b 中不同时存在的元素

output

{'Zhihu', 'Baidu', 'Taobao', 'Tencent', 'Google', 'Facebook'}
Tencent 在集合中
{'b', 'c', 'a', 'r', 'd'}
5
{'r', 'b', 'd'}
{'b', 'c', 'a', 'z', 'm', 'r', 'l', 'd'}
{'c', 'a'}
{'z', 'b', 'm', 'r', 'l', 'd'}

字典(Dictionary)类型

  • 字典(dictionary)是Python中另一个非常有用的内置数据类型。
  • 列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取。
  • 字典是一种映射类型,字典用 { } 标识,它是一个无序的 键(key) : 值(value) 的集合。
  • 键(key)必须使用不可变类型。
  • 在同一个字典中,键(key)必须是唯一的。
#!/usr/bin/python3

dict = {}
dict['one'] = "1 - 教程"
dict[2]     = "2 - 工具"

tinydict = {'name': 'test','code':1, 'site': 'www.test.com'}


print (dict['one'])       # 输出键为 'one' 的值
print (dict[2])           # 输出键为 2 的值
print (tinydict)          # 输出完整的字典
print (tinydict.keys())   # 输出所有键
print (tinydict.values()) # 输出所有值

out

1 - 教程
2 - 工具
{'name': 'test', 'code': 1, 'site': 'www.test.com'}
dict_keys(['name', 'code', 'site'])
dict_values(['test', 1, 'www.test.com'])
  • 构造函数 dict() 可以直接从键值对序列中构建字典如下:
>>> dict([('Test', 1), ('Google', 2), ('Taobao', 3)])
{'Test': 1, 'Google': 2, 'Taobao': 3}

>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}

>>> dict(Test=1, Google=2, Taobao=3)
{'Test': 1, 'Google': 2, 'Taobao': 3}

{x: x**2 for x in (2, 4, 6)} 该代码使用的是字典推导式
更多推导式内容可以参考:Python 推导式 - 菜鸟教程

  • 另外,字典类型也有一些内置的函数,例如 clear()、keys()、values() 等。

  • 注意:

  • 1、字典是一种映射类型,它的元素是键值对。
  • 2、字典的关键字必须为不可变类型,且不能重复。
  • 3、创建空字典使用 { }

二进制序列(bytes)类型

  • 在 Python3 中,bytes 类型表示的是不可变的二进制序列(byte sequence)。
  • 字符串类型不同的是,bytes 类型中的元素是整数值0255 之间的整数),而不是 Unicode 字符。
  • bytes 类型通常用于处理二进制数据

比如,图像文件、音频文件、视频文件等等。
在网络编程中,也经常使用 bytes 类型来传输二进制数据。

  • 创建 bytes 对象的方式有多种,最常见的方式是使用 b 前缀:

  • 也可以使用 bytes() 函数将其他类型的对象转换为 bytes 类型。b

bytes() 函数的第1个参数是要转换的对象,第2个参数是编码方式,如果省略第二个参数,则默认使用 UTF-8 编码

x = bytes("hello", encoding="utf-8")
  • 与字符串类型类似,bytes 类型也支持许多操作和方法,如切片、拼接、查找、替换等等。同时,由于 bytes 类型是不可变的,因此在进行修改操作时需要创建一个新的 bytes 对象。

例如:

x = b"hello"
y = x[1:3]  # 切片操作,得到 b"el"
z = x + b"world"  # 拼接操作,得到 b"helloworld"

其中 ord() 函数用于将字符转换为相应的整数值。

Python数据类型转换

  • 有时候,我们需要对数据内置的类型进行转换,数据类型的转换,你只需要将数据类型作为函数名即可。

Python3 数据类型转换 - 菜鸟教程 会具体介绍。

有时候,我们需要对数据内置的类型进行转换,数据类型的转换,一般情况下你只需要将数据类型作为函数名即可。

  • Python 数据类型转换可以分为两种:

隐式类型转换 - 自动完成
显式类型转换 - 需要使用类型函数来转换

隐式类型转换

  • 隐式类型转换
    在隐式类型转换中,Python 会自动将一种数据类型转换为另一种数据类型,不需要我们去干预。

  • "较高数据类型"、"较低数据类型"

"较高数据类型"和"较低数据类型"是在隐式类型转换中用于描述数据精度的概念。
精度可以理解为数据类型能够表示的信息量或详细程度。
在Python中,数据类型的"高"和"低"主要根据它们的精度来判断。
这里的"较高"数据类型指的是能够表示更多信息(或更精确信息)的数据类型,而"较低"的数据类型则表示的信息较少。
具体来说,比如浮点数就比整数"高",因为浮点数不仅可以表示整数,还可以表示小数。

所以在下述例子中,整数就会被自动转换为浮点数,以保证信息不丢失。
以下实例中,我们对两种不同类型的数据进行运算,较低数据类型(整数)就会转换为较高数据类型(浮点数)以避免数据丢失。

num_int = 123
num_flo = 1.23

num_new = num_int + num_flo

print("num_int 数据类型为:",type(num_int))
print("num_flo 数据类型为:",type(num_flo))

print("num_new 值为:",num_new)
print("num_new 数据类型为:",type(num_new))

out

num_int 数据类型为: <class 'int'>
num_flo 数据类型为: <class 'float'>
num_new: 值为: 124.23
num_new 数据类型为: <class 'float'>

代码解析:

实例中我们对两个不同数据类型的变量 num_int 和 num_flo 进行相加运算,并存储在变量 num_new 中。
然后查看三个变量的数据类型。
在输出结果中,我们看到 num_int 是 整型(integer) , num_flo 是 浮点型(float)。
同样,新的变量 num_new 是 浮点型(float),这是因为 Python 会将较小的数据类型转换为较大的数据类型,以避免数据丢失。

我们再看一个实例,整型数据与字符串类型的数据进行相加:

num_int = 123
num_str = "456"

print("num_int 数据类型为:",type(num_int))
print("num_str 数据类型为:",type(num_str))

print(num_int+num_str)

以上实例输出结果为:

num_int 数据类型为: <class 'int'>
num_str 数据类型为: <class 'str'>
Traceback (most recent call last):
  File "/runoob-test/test.py", line 7, in <module>
    print(num_int+num_str)
TypeError: unsupported operand type(s) for +: 'int' and 'str'

从输出中可以看出,整型字符串类型运算结果会报错,输出 TypeError。 Python 在这种情况下无法使用隐式转换

但是,Python 为这些类型的情况提供了一种解决方案,称为显式转换

显式类型转换

在显式类型转换中,用户将对象的数据类型转换为所需的数据类型。 我们使用 int()、float()、str() 等预定义函数来执行显式类型转换。

  • int() 强制转换为整型:
x = int(1)   # x 输出结果为 1
y = int(2.8) # y 输出结果为 2
z = int("3") # z 输出结果为 3
  • float() 强制转换为浮点型:
x = float(1)     # x 输出结果为 1.0
y = float(2.8)   # y 输出结果为 2.8
z = float("3")   # z 输出结果为 3.0
w = float("4.2") # w 输出结果为 4.2
  • str() 强制转换为字符串类型:
x = str("s1") # x 输出结果为 's1'
y = str(2)    # y 输出结果为 '2'
z = str(3.0)  # z 输出结果为 '3.0'

整型字符串类型进行运算,就可以用强制类型转换来完成:

num_int = 123
num_str = "456"

print("num_int 数据类型为:",type(num_int))
print("类型转换前,num_str 数据类型为:",type(num_str))

num_str = int(num_str)    # 强制转换为整型
print("类型转换后,num_str 数据类型为:",type(num_str))

num_sum = num_int + num_str

print("num_int 与 num_str 相加结果为:",num_sum)
print("sum 数据类型为:",type(num_sum))

out

num_int 数据类型为: <class 'int'>
类型转换前,num_str 数据类型为: <class 'str'>
类型转换后,num_str 数据类型为: <class 'int'>
num_int 与 num_str 相加结果为: 579
sum 数据类型为: <class 'int'>

以下几个内置的函数可以执行数据类型之间的转换。这些函数返回一个新的对象,表示转换的值。

函数 描述
[int(x ,base]) 将x转换为一个整数
float(x) 将x转换到一个浮点数
[complex(real ,imag]) 创建一个复数
str(x) 将对象 x 转换为字符串
repr(x) 将对象 x 转换为表达式字符串
eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s) 将序列 s 转换为一个元组
list(s) 将序列 s 转换为一个列表
set(s) 转换为可变集合
dict(d) 创建一个字典。d 必须是一个 (key, value)元组序列。
frozenset(s) 转换为不可变集合
chr(x) 将一个整数转换为一个字符
ord(x) 将一个字符转换为它的整数值
hex(x) 将一个整数转换为一个十六进制字符串
oct(x) 将一个整数转换为一个八进制字符串

空行

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

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

  • 空行代码缩进不同:

  • 空行并不是 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.pyrequirements.txt,再到 setup.cfg 的变迁。

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

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

为什么需要 pyproject.toml?

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

  • setup.py 用于项目打包
  • requirements.txt 管理依赖
  • setup.cfg 存放项目元数据
  • 各种工具的配置文件(.pylintrcpytest.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  千千寰宇  阅读(244)  评论(0)    收藏  举报