【通过Cpython3.9源码看看python字符串对象的创建】

news2024/10/5 12:51:08

在这里插入图片描述

CPython源码解析之PyUnicode_New函数实现

简介

PyUnicode_New是Python源码中用于创建Unicode字符串对象的函数,定义在UnicodeObject.c文件中。该函数接受一个长度参数size和最大字符值参数maxchar(根据传入的最大字符值 maxchar 确定新创建的字符串对象所需的存储类型和大小),并返回一个新的Unicode字符串对象。

该函数根据maxchar的值判断Unicode字符串对象的编码类型**(字符串对象有三种可能的存储格式:1 字节(byte)、2 字节(UCS-2)和 4 字节(UCS-4))**,并根据size和字符大小分配内存。同时,如果size为0,则会返回预先分配好的空字符串对象unicode_empty,从而进行一些优化。

在函数实现中,还会根据字符大小和maxchar的值来设置对象的一些属性(如kindchar_size等),同时进行内存分配和初始化等操作。

函数实现

函数实现的主要流程如下:

PyObject *PyUnicode_New(Py_ssize_t size, Py_UCS4 maxchar)
{
    PyObject *obj;
    PyCompactUnicodeObject *unicode;
    void *data;
    enum PyUnicode_Kind kind;
    int is_sharing, is_ascii;
    Py_ssize_t char_size;
    Py_ssize_t struct_size;

    /* Optimization for empty strings */
    if (size == 0 && unicode_empty != NULL) {
        Py_INCREF(unicode_empty);
        return unicode_empty;
    }

    is_ascii = 0;
    is_sharing = 0;
    struct_size = sizeof(PyCompactUnicodeObject);
    if (maxchar < 128) {
        kind = PyUnicode_1BYTE_KIND;
        char_size = 1;
        is_ascii = 1;
        struct_size = sizeof(PyASCIIObject);
    }
    else if (maxchar < 256) {
        kind = PyUnicode_1BYTE_KIND;
        char_size = 1;
    }
    else if (maxchar < 65536) {
        kind = PyUnicode_2BYTE_KIND;
        char_size = 2;
        if (sizeof(wchar_t) == 2)
            is_sharing = 1;
    }
    else {
        if (maxchar > MAX_UNICODE) {
            PyErr_SetString(PyExc_SystemError,
                            "invalid maximum character passed to PyUnicode_New");
            return NULL;
        }
        kind = PyUnicode_4BYTE_KIND;
        char_size = 4;
        if (sizeof(wchar_t) == 4)
            is_sharing = 1;
    }

    /* Ensure we won't overflow the size. */
    if (size < 0) {
        PyErr_SetString(PyExc_SystemError,
                        "Negative size passed to PyUnicode_New");
        return NULL;
    }
    if (size > ((PY_SSIZE_T_MAX - struct_size) / char_size - 1))
        return PyErr_NoMemory();

    /* Duplicated allocation code from _PyObject_New() instead of a call to
     * PyObject_New() so we are able to allocate space for the object and
     * it's data buffer.
     */
    obj = (PyObject *) PyObject_MALLOC(struct_size + (size + 1) * char_size);
    if (obj == NULL)
        return PyErr_NoMemory();
    obj = PyObject_INIT(obj, &PyUnicode_Type);
    if (obj == NULL)
        return NULL;

    unicode = (PyCompactUnicodeObject *)obj;
    if (is_ascii)
        data = ((PyASCIIObject*)obj) + 1;

  1. 如果 maxchar 小于 128,表明字符串中所有字符都是 ASCII 字符,使用 PyUnicode_1BYTE_KIND 类型,每个字符占用 1 字节。此外,设置 is_ascii 为 1,并将 struct_size 设置为 PyASCIIObject 的大小。
  2. 如果 maxchar 小于 256,表明字符串中的所有字符都可以用一个字节表示,使用 PyUnicode_1BYTE_KIND 类型,每个字符占用 1 字节。
  3. 如果 maxchar 小于 65536,表明字符串中的字符可以用两个字节表示(UCS-2 编码),使用 PyUnicode_2BYTE_KIND 类型,每个字符占用 2 字节。同时,如果系统的 wchar_t 大小为 2 字节,设置 is_sharing 为 1,表示字符串对象和系统宽字符(wchar_t)可以共享内存。
  4. 如果 maxchar 大于等于 65536 且小于等于 MAX_UNICODE,表明字符串中的字符需要 4 个字节表示(UCS-4 编码),使用 PyUnicode_4BYTE_KIND 类型,每个字符占用 4 字节。同时,如果系统的 wchar_t 大小为 4 字节,设置 is_sharing 为 1,表示字符串对象和系统宽字符(wchar_t)可以共享内存。

如果 maxchar 大于 MAX_UNICODE,则抛出一个系统错误,因为这是一个无效的最大字符值。

判断是否为空字符串

在函数中首先对空字符串进行了判断,如果size等于0并且全局变量unicode_empty不为空,则返回全局变量unicode_emptyunicode_empty是一个预先分配好的空字符串对象,用于避免重复创建空字符串对象,从而提高程序效率。

    /* Optimization for empty strings */
    if (size == 0 && unicode_empty != NULL) {
        Py_INCREF(unicode_empty);
        return unicode_empty;
    }

确定编码类型和字符大小

接下来是根据maxchar的值判断Unicode字符串对象的编码类型和字符大小。如果maxchar小于128,则说明所有字符都是ASCII字符,可以使用ASCII编码类型,并且字符大小为1字节。否则,如果maxchar小于256,则仍然使用1字节编码类型。如果maxchar小于65536,则使用2字节编码类型,并根据wchar_t的大小来判断是否需要共享缓冲区(即是否需要在对象之后分配缓冲区)。如果maxchar大于65536,则使用4字节编码类型。

    is_ascii = 0;
    is_sharing = 0;
    struct_size = sizeof(PyCompactUnicodeObject);
    if (maxchar < 128) {
        kind = PyUnicode_1BYTE_KIND;
        char_size = 1;
        is_ascii = 1;
        struct_size = sizeof(PyASCIIObject);
    }
    else if (maxchar < 256) {
        kind = PyUnicode_1BYTE_KIND;
        char_size = 1;
    }
    else if (maxchar < 65536) {
        kind = PyUnicode_2BYTE_KIND;
        char_size = 2;
        if (sizeof(wchar_t) == 2)
            is_sharing = 1;
    }
    else {
        if (maxchar > MAX_UNICODE) {
            PyErr_SetString(PyExc_SystemError,
                            "invalid maximum character passed to PyUnicode_New");
            return NULL;
        }
        kind = PyUnicode_4BYTE_KIND;
        char_size = 4;
        if (sizeof(wchar_t) == 4)
            is_sharing = 1;
    }

检查长度是否有效

接下来是对字符串长度的检查。如果size小于0或者内存分配大小超过PY_SSIZE_T_MAX,则返回异常对象。

    /* Ensure we won't overflow the size. */
    if (size < 0) {
        PyErr_SetString(PyExc_SystemError,
                        "Negative size passed to PyUnicode_New");
        return NULL;
    }
    if (size > ((PY_SSIZE_T_MAX - struct_size) / char_size - 1))
        return PyErr_NoMemory();

分配内存和初始化对象

如果没有异常,则调用PyObject_MALLOC函数分配内存,并使用PyObject_INIT函数初始化对象。PyObject_INIT函数与PyObject_New类似,但它可以分配额外的空间来存储数据缓冲区。在函数中,还会设置对象的一些属性(如_PyUnicode_LENGTH_PyUnicode_HASH等),并根据编码类型和字符大小分配数据缓冲区。如果使用ASCII编码类型,则缓冲区在对象之后分配;否则,缓冲区直接跟随对象分配。

详细分析下:

代码直接使用 PyObject_MALLOC 函数分配内存,而不是调用 PyObject_New 函数。这样做的原因是为了同时分配字符串对象及其数据缓冲区所需的内存。分配的内存大小为 struct_size(字符串对象的结构大小)加上所需的字符存储空间大小((size + 1) * char_size,其中 size 是字符串大小,char_size 是每个字符所需的字节数)。额外的 +1 是为了在数据缓冲区末尾预留一个空字节,用于存储空字符终止符。

如果内存分配失败,将返回内存不足的错误。成功分配内存后,使用 PyObject_INIT 函数初始化字符串对象,并将其类型设置为 PyUnicode_Type

接着,将 unicode 指针指向分配的内存空间,并根据字符串是否为 ASCII 类型确定数据缓冲区的位置。如果 is_ascii 为真,数据缓冲区紧跟在 PyASCIIObject 结构之后;否则,数据缓冲区紧跟在 PyCompactUnicodeObject 结构之后。将数据缓冲区的起始地址赋值给 data

然后就是设置了字符串对象(unicode)的各种属性:

  1. 设置字符串长度(_PyUnicode_LENGTH)为 size
  2. 初始化字符串的哈希值(_PyUnicode_HASH)为 -1(表示尚未计算哈希值)。
  3. 设置字符串对象的状态(_PyUnicode_STATE):
    • interned:表示字符串对象是否已被驻留(interned),初始值设为 0(表示未被驻留)。
    • kind:设置字符串的类型,即字符的存储方式(1字节、2字节或4字节)。
    • compact:设置为 1,表示使用紧凑的内存布局。
    • ready:设置为 1,表示字符串对象已准备好使用。
    • ascii:设置为 is_ascii 的值,表示字符串是否为 ASCII 字符串。
    obj = (PyObject *) PyObject_MALLOC(struct_size + (size + 1) * char_size);
    if (obj == NULL)
        return PyErr_NoMemory();
    obj = PyObject_INIT(obj, &PyUnicode_Type);
    if (obj == NULL)
        return NULL;

    unicode = (PyCompactUnicodeObject *)obj;
    if (is_ascii)
        data = ((PyASCIIObject*)obj) + 1;
    else
        data = unicode + 1;
    _PyUnicode_LENGTH(unicode) = size;
    _PyUnicode_HASH(unicode) = -1;
    _PyUnicode_STATE(unicode).interned = 0;
    _PyUnicode_STATE(unicode).kind = kind;
    _PyUnicode_STATE(unicode).compact = 1;
    _PyUnicode_STATE(unicode).ready = 1;
    _PyUnicode_STATE(unicode).ascii = is_ascii;

设置缓冲区

最后是根据编码类型和字符大小设置缓冲区。如果使用ASCII编码类型,则缓冲区的末尾需要添加一个空字符。如果使用1字节编码类型,则需要设置缓冲区的长度。如果使用2字节或4字节编码类型,则不需要设置长度。

  • 如果是 ASCII 字符串,将数据缓冲区的最后一个字节设置为 0(空字符终止符),并将 _PyUnicode_WSTR 设置为 NULL。
  • 如果是 1 字节非 ASCII 字符串,将数据缓冲区的最后一个字节设置为 0(空字符终止符),将 _PyUnicode_WSTR 设置为 NULL,将 _PyUnicode_WSTR_LENGTH 设置为 0,将 utf8 设置为 NULL,将 utf8_length 设置为 0。
  • 对于其他情况(2 字节或 4 字节 Unicode 字符串):
    • utf8 设置为 NULL,将 utf8_length 设置为 0。
    • 将数据缓冲区的最后一个字符设置为 0(空字符终止符)。
    • 如果 is_sharing 为真(表示 wchar_t 与字符串存储方式相同),将 _PyUnicode_WSTR_LENGTH 设置为 size,将 _PyUnicode_WSTR 设置为数据缓冲区的起始地址(data)。
    • 否则,将 _PyUnicode_WSTR_LENGTH 设置为 0,将 _PyUnicode_WSTR 设置为 NULL。
if (is_ascii) {
    ((char*)data)[size] = 0;
    _PyUnicode_WSTR(unicode) = NULL;
}
else if (kind == PyUnicode_1BYTE_KIND) {
    ((char*)data)[size] = 0;
    _PyUnicode_WSTR(unicode) = NULL;
    _PyUnicode_WSTR_LENGTH(unicode) = 0;
    unicode->utf8 = NULL;
    unicode->utf8_length = 0;
}
else {
    unicode->utf8 = NULL;
    unicode->utf8_length = 0;
    if (kind == PyUnicode_2BYTE_KIND)
        ((Py_UCS2*)data)[size] = 0;
    else /* kind == PyUnicode_4BYTE_KIND */
        ((Py_UCS4*)data)[size] = 0;
    if (is_sharing) {
        _PyUnicode_WSTR_LENGTH(unicode) = size;
        _PyUnicode_WSTR(unicode) = (wchar_t *)data;
    }
    else {
        _PyUnicode_WSTR_LENGTH(unicode) = 0;
        _PyUnicode_WSTR(unicode) = NULL;
    }
}

返回对象

最后,对对象进行一些检查,然后返回对象。在调试模式下,使用 unicode_fill_invalid 函数填充无效的 Unicode 字符串。最后,使用断言(assert)确保字符串对象的一致性。返回创建的字符串对象 obj

#ifdef Py_DEBUG
    unicode_fill_invalid((PyObject*)unicode, 0);
#endif
    assert(_PyUnicode_CheckConsistency((PyObject*)unicode, 0));
    return obj;
}

s1 = "Hello world!"    # ASCII编码类型
s2 = "你好,世界!"   # 3字节UTF-8编码类型
s3 = "🐍👍"           # 4字节UTF-8编码类型

# 创建ASCII编码类型的Unicode字符串对象
u1 = PyUnicode_New(len(s1), 127)

# 创建3字节UTF-8编码类型的Unicode字符串对象
u2 = PyUnicode_New(len(s2), 65535)

创建4字节UTF-8编码类型的Unicode字符串对象
u3 = PyUnicode_New(len(s3), 1114111)

在ASCII编码类型的Unicode字符串对象中添加数据
for i, c in enumerate(s1):
	PyUnicode_WRITE(u1, i, c)3字节UTF-8编码类型的Unicode字符串对象中添加数据
for i, c in enumerate(s2):
	PyUnicode_WRITE(u2, i, c)4字节UTF-8编码类型的Unicode字符串对象中添加数据
for i, c in enumerate(s3):
	PyUnicode_WRITE(u3, i, c)

输出Unicode字符串对象的值
print(PyUnicode_AsWideCharString(u1, NULL)) # Hello world!
print(PyUnicode_AsWideCharString(u2, NULL)) # 你好,世界!
print(PyUnicode_AsWideCharString(u3, NULL)) # 🐍👍

释放Unicode字符串对象的内存
Py_DECREF(u1)
Py_DECREF(u2)
Py_DECREF(u3)

上面的示例演示了如何使用PyUnicode_New函数创建不同编码类型的Unicode字符串对象,并使用PyUnicode_WRITE函数向对象中添加数据,最后使用PyUnicode_AsWideCharString函数输出Unicode字符串对象的值,并使用Py_DECREF函数释放Unicode字符串对象的内存。

需要注意的是,Python中有许多其他的字符串类型,如字节串(bytes)、字节数组(bytearray)和字符串(str)等。其中,字符串类型是Unicode字符串类型,它使用UTF-8编码类型存储Unicode字符。与PyUnicode_New函数对应的是PyUnicode_FromString函数,它可以从字符串中创建Unicode字符串对象。

补充说明

在Python中,字符串有两种类型,一种是字节串(bytes)类型,另一种是字符串(str)类型。字节串类型是一个字节序列,它以字节为单位存储数据。而字符串类型是一个Unicode字符序列,它以Unicode字符为单位存储数据,并使用UTF-8编码类型存储Unicode字符。在Python 3.x中,字符串类型是默认的字符串类型,而字节串类型则需要使用b前缀表示。例如:

# 字符串类型
s1 = "Hello, world!"

# 字节串类型
s2 = b"Hello, world!"

PyUnicode_New函数是用于创建Unicode字符串对象的函数,可以指定字符串的长度和最大字符范围来创建不同类型的Unicode字符串对象。而PyUnicode_FromString函数则是从字符串中创建Unicode字符串对象的函数,它会自动检测字符串的编码类型,并创建对应的Unicode字符串对象。例如:

# 创建ASCII编码类型的Unicode字符串对象
u1 = PyUnicode_FromString("Hello, world!")

# 创建UTF-8编码类型的Unicode字符串对象
u2 = PyUnicode_FromString("你好,世界!")

# 创建UTF-16编码类型的Unicode字符串对象
u3 = PyUnicode_FromString("\u4f60\u597d\uff0c\u4e16\u754c\uff01")

PyUnicode_FromString函数会自动检测字符串的编码类型,并根据需要创建相应的Unicode字符串对象。例如,在上面的示例中,第一个字符串是使用ASCII编码类型的,因此创建的是ASCII编码类型的Unicode字符串对象;第二个字符串是使用UTF-8编码类型的,因此创建的是UTF-8编码类型的Unicode字符串对象;第三个字符串是使用UTF-16编码类型的,因此创建的是UTF-16编码类型的Unicode字符串对象。

需要注意的是,如果从字节串类型创建Unicode字符串对象,需要使用PyUnicode_Decode函数进行解码,以将字节串转换为Unicode字符串。例如:

# 创建UTF-8编码类型的字节串对象
b = b"\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c\xef\xbc\x81"

# 将字节串对象解码为UTF-8编码类型的Unicode字符串对象
u = PyUnicode_Decode(b, strlen(b), "utf-8", "strict")

上面的示例中,我们首先创建了一个UTF-8编码类型的字节串对象,然后使用PyUnicode_Decode函数将其解码为UTF-8编码类型的Unicode字符串对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/417498.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

百度工程师的软件质量与测试随笔

作者 | 百度移动生态质效工程师们 导读 在降本增效、以chatGPT为代表的大模型技术横空出世的背景下&#xff0c;对软件质量和软件测试的领域也带来了巨大冲击&#xff0c;也使得软件质量工作者开始变得焦虑&#xff0c;主要体现在&#xff1a;公司对软件质量从业者的不重视加剧…

SQL Server的执行计划(Execution Plans)

执行计划一、背景二、显示和保存执行计划三、显示估计的执行计划四、显示实际执行计划五、以 XML 格式保存执行计划六、比较和分析执行计划6.1、比较执行计划6.2、分析实际执行计划总结一、背景 为了能够执行查询&#xff0c;SQL Server 数据库引擎必须分析该语句&#xff0c;…

21100颗星的Locust性能测试工具到底有多牛!

一句话&#xff1a;用普通的Python编写可扩展的负载测试&#xff0c;就够了&#xff0c;懂得自然懂&#xff01; Locust是一个易于使用、可编写脚本和可扩展的性能测试工具。你在常规的Python代码中定义你的用户的行为&#xff0c;而不是受制于一个UI或领域特定的语言&#xff…

HTB-Obscurity

HTB-Obscurity信息收集8080端口立足www-data -> robertrobert -> rootsudo 注入hash捕获信息收集 8080端口 ”如果攻击者不知道你在使用什么软件&#xff0c;你就不会被黑客攻击!“&#xff0c;目标对web的指纹做了某些处理。 “‘SuperSecureServer.py’ in the secre…

【从零开始学Skynet】基础篇(六):MySql数据库安装操作

游戏服务端的另一项重要功能是保存玩家数据&#xff0c;Skynet提供了操作MySQL数据库、MongoDB数据库的模块。1、数据库安装 首先安装Mysql服务器&#xff0c;打开终端输入如下指令&#xff1a; sudo apt-get install mysql-server 按下回车&#xff0c;输入密码后开始安装&a…

秒杀架构(二) -- nginx实现限流

限流&#xff08;Rate Limitting&#xff09;是服务降级的一种方式&#xff0c;通过限制系统的输入和输出流量以达到保护系统的目的。比如我们的网站暴露在公网环境中&#xff0c;除了用户的正常访问&#xff0c;网络爬虫、恶意攻击或者大促等突发流量都可能都会对系统造成压力…

OpenCV按指定大小分割图像并保存详细讲解

这几天在忙着整理自己的数据集&#xff0c;使用工业级相机拍了好多高清照片&#xff0c;但是模型训练的时候需要使用512*512像素点大小的图像&#xff0c;而且我的模型设计的时候就已经规定好了训练样本大小。 那就分割呗&#xff0c;把拍的照片按512*512分割一小块一小块的&am…

easyx

普通的画线图什么的 首先我们需要安装一个easyx的图形库&#xff0c;然后把头文件搞出来 #include <stdio.h> #include <easyx.h>//easyx画线啥啥的图形库 #include <graphics.h> #include <math.h> #include <conio.h>//键盘操作的头文件 设…

2023年mathorcupD题航空安全风险分析和飞行技术评估思路分析

2023年mathorcupD题航空安全风险分析和飞行技术评估思路分析 飞行安全是民航运输业赖以生存和发展的基础。随着我国民航业的快 速发展&#xff0c;针对飞行安全问题的研究显得越来越重要。2022 年 3 月 21 日&#xff0c;“3.21” 空难的发生终结了中国民航安全飞行 1 亿零 59…

Android中级——性能优化

性能优化布局优化UI渲染机制避免Overdraw优化布局层级利用<include\>重用Layout使用<ViewStub\>实现View的延迟加载Hierarchy View内存优化获取内存信息ProfilerTraceViewMAT&#xff08;Memory Analyzer Tool&#xff09;dumpsys布局优化 UI渲染机制 画面流畅需…

透过Gartner最新报告,认识“超级边缘”

当下&#xff0c;酝酿能量的超级边缘。最近&#xff0c;我们在谈视频化狂飙、谈AIGC颠覆、谈算力动能不足&#xff0c;很少谈及边缘。但“边缘”恰恰与这一切相关&#xff0c;且越发密不可分&#xff0c;它是未来技术发展的极大影响因子。 “到2025年&#xff0c;超过70%的组织…

Segment Anything Model

论文翻译&#xff1a; 图1&#xff1a;我们旨在通过引入三个相互关联的组件来构建分割的基础模型&#xff1a;即时分割任务、支持数据注释并通过即时工程将零样本传输到一系列任务的分割模型&#xff08;SAM&#xff09;&#xff0c;以及用于收集SA-1B的数据引擎&#xff0c;SA…

MappingGenerator PRO 2023.3 Visual Studio 2019-2022

您的私人编码助手 MappingGenerator 最初是作为 AutoMapper 的设计时替代品创建的。现在它正在演变为编码助手&#xff0c;您可以将最平凡的编码任务委派给它&#xff1a; 生成映射生成显式转换实施克隆生成投影表达式脚手架方法调用脚手架对象创建清理方法调用方便ILogger的使…

探讨Hive是否转为MapReduce程序

目录 前提条件 数据准备 探讨HQL是否转为MapReduce程序执行 1.设置hive.fetch.task.conversionnone 2.设置hive.fetch.task.conversionminimal 3.设置hive.fetch.task.conversionmore 前提条件 Linux环境下安装好Hive&#xff0c;这里测试使用版本为&#xff1a;Hive2.3.…

【结构型模式】适配者模式

文章目录优秀借鉴1、简介2、结构3、实现方式3.1、案例引入3.2、类适配器3.3、对象适配器3.4、接口适配器4、区别对比5、适配者模式优缺点6、应用场景优秀借鉴 黑马程序员Java设计模式详解-适配器模式概述适配器设计模式&#xff08;封装器模式&#xff09;一文彻底弄懂适配器模…

页眉怎么添加【节】,设置不同章节不同页眉

文章目录前言添加【节】&#xff0c;设置不同内容总结前言 大家写文档或者论文的时候可能会需要&#xff1a;不同章节页眉展示不同的内容 然而&#xff0c;在双击页眉进行编辑的时候却发现几个章节的页眉一起被修改了&#xff1a; 会出现文章与页眉不同步的情况&#xff0c…

idea使用Junit

文章目录 idea使用JunitJunit配置常用注解常用于测试的断言方法后续idea使用Junit 对项目使用Junit主要有两个步骤: 添加Junit依赖,即添加Junit jar包使用JunitJunit配置 方法一:idea自带的快捷方法 对要测试的类的方法,在该类中,右键鼠标呼出菜单,选择Generate,快捷…

简单的回顾Linux

linux命令ls会显示出文件的颜色, 系统约定的默认颜色含义如下: 白色&#xff1a;表示普通文件 蓝色&#xff1a;表示目录 绿色&#xff1a;表示可执行文件 红色&#xff1a;表示压缩文件 浅蓝色&#xff1a;链接文件 主要是使用ln命令建立的文件 红色闪烁&#xff1a;表示链接的…

Java实现打印杨辉三角形,向左、右偏的平行四边形这三个图形代码程序

目录 前言 一、打印杨辉三角形 1.1运行流程&#xff08;思想&#xff09; 1.2代码段 1.3运行截图 二、向左偏的平行四边形 1.1运行流程&#xff08;思想&#xff09; 1.2代码段 1.3运行截图 三、向右偏的平行四边形 1.1运行流程&#xff08;思想&#xff09; 1.2代…

inplace-operation-error 【已解决】

最近在搞CT医学图像分割模型的领域泛化优化&#xff0c;结果就出现了报错&#xff1a; 关于这个问题stackoverflow上有非常多的讨论&#xff0c;可以过去围观&#xff1a; 指路&#xff1a;中文版stackoverflow - 堆栈内存溢出 (stackoom.com) Stack Overflow - Where Develo…