导言
The CUDA Execution Model: how the CUDA architecture handles the execution of code in parallel.
这篇将聚焦于CUDA的基础知识,基本概念,
TODO:[5] please fix all in free time
重复了和另一篇
The default program entry function is main
, but can be changed in two situations:
#define xxx main
in header file to replace the name which maybe ignored by silly search bar in VSCODE.-exxx
compile flag;
)取决于上下文。if
, while
, for
)、复合语句({}
) 不需要分号。#define
, #include
):不需要分号,因为它们不是 C++ 语法层面的内容。}
不需要分号,但声明类或结构体时 }
后要加分号。总结来说,分号用来结束语句,包括声明、表达式和执行体等,但当你定义一个复合结构(如函数定义、控制语句)时,不需要分号来结束复合结构的定义。
1 | int getKthAncestor(int node, int k) { |
根据C++的作用域规则,内层的局部变量会覆盖外层的同名变量。因此,在第二行的语句中,node引用的是函数参数中的node,而不是你想要的之前定义的node。
为了避免这个问题,你可以修改代码,避免重复定义变量名。例如,可以将第二行的变量名改为newNode或其他不同的名称,以避免与函数参数名冲突。
运算符性质:
https://en.cppreference.com/w/cpp/language/types
https://en.cppreference.com/w/cpp/types/integer
1 | //返回与平台相关的数值类型的极值 |
1 | extern |
static 作⽤:控制变量的存储⽅式和作用范围(可⻅性)。
int MyClass::staticVariable = 10;
当const修饰基本数据类型时,可以将其放置在类型说明符的前面或后面,效果是一样的。const关键字用于声明一个常量,即其值在声明后不可修改。
1 | const int constantValue1 = 10; // const在类型说明符前 |
当const关键字位于指针变量或引用变量的左侧时,它用于修饰指针所指向的变量,即指针指向的内容为常量。当const关键字位于指针变量或引用变量的右侧时,它用于修饰指针或引用本身,即指针或引用本身是常量。
修饰指针指向的变量, 它指向的值不能修改:
1 | int x = 5; |
修饰指针本身 ,它不能再指向别的变量,但指向(变量)的值可以修改。:
1 | const int y = 10; |
const int *const p3;
//指向整形常量 的 常量指针 。它既不能再指向别的常量,指向的值也不能修改。
在C++, explicit 是一个关键字,用于修饰单参数构造函数,用于禁止隐式类型转换。
当一个构造函数被声明为 explicit 时,它指示编译器在使用该构造函数进行类型转换时只能使用显式调用,而不允许隐式的类型转换发生。
通过使用 explicit 关键字,可以防止一些意外的类型转换,提高代码的清晰性和安全性。它通常用于防止不必要的类型转换,特别是在单参数构造函数可能引起歧义或产生意外结果的情况下。
#include_next
的作用是b.cpp
想使用stdlib.h
, 那么在代码的目录下创建stdlib.h
,并在该文件里#include_next "stdlib.h"
防止递归引用。#define PI 3.14159
,在代码中将PI替换为3.14159。const:
const int MAX_VALUE = 100;
,声明一个名为MAX_VALUE的常量。typedef:
typedef int Age
;,为int类型创建了一个别名Age。inline:
inline int add(int a, int b) { return a + b; }
,声明了一个内联函数add。define主要用于宏定义,const用于声明常量,typedef用于创建类型别名,inline用于内联函数的声明。
为了避免同一个文件被include多次,C/C++中有两种方式,一种是#ifndef方式,一种是#pragma once方式。在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两者仍然还是有一些细微的区别。
1 |
|
namespace 会影响 typedef
的作用范围,但不会直接限制 #define
宏的作用范围。
1 | //值传递 |
引用传递和指针传递的区别:
指针传递和引用传递的使用情景:
虽然理论上可以通过类似void f(bool x = true)
来实现默认值。
1 | // 函数声明 |
1 | template<typename T> |
1 |
|
VA_LIST 是在C语言中解决变参问题的一组宏,变参问题是指参数的个数不定,可以是传入一个参数也可以是多个;可变参数中的每个参数的类型可以不同,也可以相同;可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。
系统提供了vprintf系列格式化字符串的函数,用于编程人员封装自己的I/O函数。
1 | int vprintf / vscanf (const char * format, va_list ap); // 从标准输入/输出格式化字符串 |
使用结构体
1 | struct RowAndCol { int row;int col; }; |
在 C++ 中,左值(lvalue) 和 右值(rvalue) 是两个重要的概念,用来描述表达式的值和内存的关系。它们帮助开发者理解变量的生命周期、赋值和对象管理,特别是在现代 C++ 中引入了右值引用后,优化了移动语义和资源管理。
左值(lvalue,locatable value) 是指在内存中有明确地址、可持久存在的对象,可以对其进行赋值操作。通俗地说,左值是能够取地址的值,可以出现在赋值操作符的左边。
特点:
&
运算符)。右值(rvalue,readable value) 是没有明确地址、临时存在的对象,不能对其进行赋值操作。它们通常是字面值常量或表达式的结果。右值只能出现在赋值操作符的右边,表示一个临时对象或数据。
特点:
&
获取右值的地址)。C++11 引入了 右值引用,即通过 &&
符号表示。这使得右值也能通过引用进行操作,特别是在实现移动语义(move semantics)和避免不必要的拷贝时非常有用。右值引用允许我们通过右值管理资源,避免性能上的损失。
通常,左值是表示持久存在的对象,可以通过取地址符 &
获取其地址,而右值是临时的、短暂存在的值,不能直接获取其地址。理解这两者对于编写高效的 C++ 代码和使用现代特性(如右值引用和移动语义)非常重要。
&&
)是 C++11 引入的新特性,用来优化资源管理和避免不必要的拷贝操作。在C++98/03中我们只能对普通数组和POD(plain old data,简单来说就是可以用memcpy复制的对象)类型可以使用列表初始化,如下:
1 | //数组的初始化列表: |
在C++11中初始化列表被适用性被放大,可以作用于任何类型对象的初始化。如下:
1 | X x1 = X{1,2}; |
聚合类型可以进行直接列表初始化
聚合类型包括
对于一个聚合类型,使用列表初始化相当于使用std::initializer_list
对其中的相同类型T
的每个元素分别赋值处理,类似下面示例代码;
1 | struct CustomVec { |
⼩贺 C++ ⼋股⽂ PDF 的作者,电⼦书的内容整理于公众号「herongwei」
https://shaojiemike.notion.site/C-11-a94be53ca5a94d34b8c6972339e7538a
解释型语言没有严格编译汇编过程,由解释器将代码块按需要变运行边翻译给机器执行。因此解释型语言一度存在运行效率底,重复解释的问题。但是通过对解释器的优化!可以提高解释型语言的运行效率。
Python 与大多数解释型语言一样,确实是将源代码编译为一组虚拟机指令,并且 Python 解释器是针对相应的虚拟机实现的。这种中间格式被称为 “字节码”。
Python 以 .pyc 结尾的 “ 字节码(bytecode)” 文件(二进制文件),一般位于__pycache__ 的子目录中,可以避免每次运行 Python 时去重新解析源代码。
1 | python -m py_compile file.py # 生成单个pyc文件 |
pyo文件是源代码文件经过优化编译后生成的文件,是pyc文件的优化版本。编译时需要使用-O和-OO选项来生成pyo文件。在Python3.5之后,不再使用.pyo文件名,而是生成文件名类似“test.opt-n.pyc的文件。
1 | python -O -m py_compile test.py |
CPython 使用一个基于栈的虚拟机。(你可以 “推入” 一个东西到栈 “顶”,或者,从栈 “顶” 上 “弹出” 一个东西来)。
CPython 使用三种类型的栈:
运行流程区别
python的传统运行执行模式:录入的源代码转换为字节码,之后字节码在python虚拟机中运行。代码自动被编译,之后再解释成机器码在CPU中执行。
c编译器直接把c源代码编译成机器码。过程比python执行过程少了字节码生成和虚拟机执行字节码过程。所以自然比python快。
1 | list.append('Google') ## 使用 append() 添加元素 |
setup安装包的过程,请看pip package一文。
命名空间(namespace)可以基本理解成每个文件是一个,通过import
来使用
触发 __init__.py
__init__.py
文件。如果没有这个文件,Python 会认为这个目录不是一个包,因此 import
语句会失败。__init__.py
负责初始化这个包,可以定义一些包级别的变量、函数或导入包的其他子模块。行为:
__init__.py
文件只会在第一次导入时被执行一次。如果模块已经被导入到当前的命名空间,再次 import
不会重新执行 __init__.py
,除非你强制重新加载(比如用 importlib.reload()
)。import
的执行会触发模块的初始化,类似于 C++ 中构造函数的概念,但不是在对象级别,而是在模块级别。1 | # example/__init__.py |
1 | import example |
if __name__ == "__main__"
这种写法通常出现在模块中,它的作用是控制模块的执行流程。程序结束时的清理行为(类似析构函数的操作)
在 Python 中,并没有像 C++ 那样显式的析构函数。模块或对象的清理一般通过以下方式实现:
__del__
方法进行资源清理。这个机制类似于 C++ 的析构函数,但触发时机取决于 Python 的垃圾回收机制。1 | class MyClass: |
atexit
模块来注册一个函数,确保在程序结束时执行。示例:使用 atexit
实现模块级别的清理操作
1 | import atexit |
输出:
1 | Program is running |
atexit
模块允许你注册多个函数,它们会在解释器关闭之前按注册顺序依次执行。__init__.py
文件。这相当于模块的 “构造” 过程。__del__
方法来管理对象的生命周期。通常情况下,当对象不再被引用时,会自动触发清理。atexit
模块来执行程序结束时的资源清理操作。你可以在模块中注册一些函数,确保在程序退出时执行清理任务。@
能在最小改变函数的情况下,包装新的功能。^1
1 | def use_logging(func): |
单下划线、双下划线、头尾双下划线说明:
__foo__
: 定义的是特殊方法,一般是系统定义名字 ,类似 init() 之类的。_foo
: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *__foo
: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。*
和 **
分别解包可迭代对象和字典。**
用于将传入的关键字参数打包成一个字典;**
则用于将字典解包为关键字参数。开启 Python 的调试模式:
通过设置环境变量启用 Python 的调试信息,这有助于捕获异常和详细的堆栈信息。
1 | export PYTHONMALLOC=debug |
使用 faulthandler
模块:
Python 提供了一个 faulthandler
模块,可以用来捕获段错误并打印堆栈信息。你可以在程序的开头添加以下代码来启用它:
1 | import faulthandler |
这将会在段错误发生时输出堆栈跟踪。
查看 Python 调试输出:
启动 Python 程序时,通过 faulthandler
打印堆栈信息,或通过 GDB 调试 Python 解释器。如果 Python 解释器发生崩溃,faulthandler
会帮助你定位错误。
函数的单元测试
traceback.print_stack()
1 | from viztracer import VizTracer |
ic.format(*args)
获得ic打印的文本ic.disable()
and ic.enable()
ic.configureOutput(prefix='Debug | ')
1 | from icecream import ic |
如果你只想捕获标准错误的输出,并将其保存到日志文件,可以使用以下命令:
1
python3.8 setup.py build bdist_wheel 1>&2 | tee compile.log
或将 `stderr` 和 `stdout` 单独重定向:
1
python3.8 setup.py build bdist_wheel 2>compile.log
定位 Python 中 setup.py
脚本运行缓慢的 热点,可以通过多种方式进行性能分析,具体步骤取决于你想了解的性能细节。以下是几种常见的方法来定位性能瓶颈。
cProfile
进行性能分析cProfile
是 Python 标准库中用于进行性能分析的工具。你可以用它来跟踪 setup.py
执行时的函数调用并找到性能瓶颈。
cProfile + snakeviz + gprof2dot
1 | ./gprof2dot.py -f pstats Diff.status | dot -Tpng -o ./output/Diff.png |
1.1 使用 cProfile
分析 setup.py
你可以通过 cProfile
运行 setup.py
并生成分析报告:
1 | python -m cProfile -o setup.prof setup.py install |
这将运行 setup.py
并将性能分析结果保存到 setup.prof
文件中。
1.2 可视化分析报告
使用 pstats
或者第三方工具 snakeviz
来分析 setup.prof
:
使用 pstats
来查看分析结果:
1 | python -m pstats setup.prof |
然后,你可以在 pstats
交互式界面中输入命令,比如:
sort cumtime
按总耗时排序。stats
查看函数调用的分析结果。安装 snakeviz
来生成Web图形化报告:
1 | pip install snakeviz |
运行 snakeviz
来可视化分析结果:
1 | snakeviz setup.prof # deploy to 127.0.0.1:8080 |
这样可以生成一个图形化的界面,显示每个函数的执行时间以及调用关系,让你更直观地看到性能瓶颈。
使用 gprof2dot 生成调用关系图片:
安装 gprof2dot 工具:pip install gprof2dot
使用 gprof2dot 将 cProfile 生成的 output.prof 转换为 .dot 文件:gprof2dot -f pstats output.prof | dot -Tsvg -o output.svg
这里的 -f pstats 表示输入的格式是 cProfile 生成的 pstats 文件。这个命令会将结果转换为 SVG 格式的火焰图,保存为 output.svg。
打开生成的 SVG 文件,查看火焰图。
生成火焰图: flameprof
python flameprof.py input.prof > output.svg
生成火焰图(有详细文件路径): flamegraph
flameprof --format=log requests.prof | xxx_path/flamegraph.pl > requests-flamegraph.svg
line_profiler
进行逐行性能分析如果你想深入了解 setup.py
的某个函数或一组函数的逐行性能,可以使用 line_profiler
工具来分析代码的逐行执行时间。
3.1 安装 line_profiler
1 | pip install line_profiler |
3.2 添加装饰器
首先,在 setup.py
中找到你想要分析的函数,添加 @profile
装饰器(在 line_profiler
中的分析模式下使用):
1 |
|
3.3 运行 line_profiler
你可以使用 kernprof.py
来运行 setup.py
并生成逐行性能报告:
1 | kernprof -l -v setup.py install |
这将运行 setup.py
并生成一份逐行性能分析报告,显示每一行代码的耗时。
Py-Spy
进行实时性能分析(推荐!!!)Py-Spy
是一个 Python 的取样分析器,它可以在不修改代码的情况下对 Python 程序进行性能分析,并生成实时的性能报告。
4.1 安装 Py-Spy
1 | pip install py-spy |
4.2 运行 Py-Spy
对 setup.py
进行分析
你可以在执行 setup.py
的同时运行 Py-Spy
进行取样分析:
1 | py-spy top -- python setup.py install |
这会生成一个实时的报告,类似于 top
命令,显示当前正在运行的 Python 函数以及其消耗的 CPU 时间。
4.3 生成火焰图
如果你希望生成一个更直观的火焰图,可以使用 py-spy
生成火焰图文件:
1 | py-spy record -o profile.svg -- python setup.py install |
然后你可以打开 profile.svg
文件,查看一个交互式的火焰图,清晰展示函数调用的时间分布。
strace
分析系统调用如果 setup.py
涉及大量的 I/O 操作(比如读写文件或安装依赖包),可能是这些操作导致了性能瓶颈。你可以使用 strace
来分析 setup.py
的系统调用,找到 I/O 操作的瓶颈。
1 | strace -tt -T -o strace.log python setup.py install |
-tt
选项会显示每个系统调用的时间戳。-T
会显示每个系统调用耗时。-o
将结果输出到 strace.log
文件中。通过查看 strace.log
,你可以找出系统调用中哪些操作耗时过长。
cProfile
或 Py-Spy
进行函数级别的性能分析,找出执行慢的函数。line_profiler
来分析慢的部分。strace
来检查系统调用。time
在脚本中插入计时代码,快速定位长时间的执行步骤。这些工具可以帮助你定位和修复 setup.py
运行缓慢的热点。
1 | python3 -m venv name |
任意变量使用pickle
1 | # 使用二进制 |
可以序列化的使用json
1 | import json |
多个变量
1 | # 将多个变量组织成字典或列表 |
[C++ Basic] STL Data Structure
for(auto x : range).
for(auto && x : range)
for(const auto & x : range)
.使用begin end
1 | vector<int>& nums1 |
以下是整理和改正后的迭代器笔记。
定义:随机访问迭代器是一种迭代器类型,允许在常数时间内访问序列中的任何元素,并支持灵活的迭代器操作。
运算支持:
+
和 -
运算符,允许轻松地在迭代器位置上进行移动。[]
,使其用法与指针类似。it
,可以通过 *(it + i)
或 it[i]
语法访问第 i
个元素。使用场景:
vector
和 deque
都提供随机访问迭代器。std::sort
、std::nth_element
)要求输入的迭代器必须是随机访问迭代器,以便快速定位和排序。概述:在 C++ 中,容器一般提供正向迭代器(begin()
到 end()
)和反向迭代器(rbegin()
到 rend()
),二者在遍历方向上相反。
转换:正向迭代器和反向迭代器可以相互转换,但类型不同,需要显式转换。
正向迭代器到反向迭代器:可以将一个正向迭代器转换为反向迭代器。
1 | Iterator it; // 假设 it 是正向迭代器 |
反向迭代器到正向迭代器:反向迭代器的 base()
成员函数可以返回一个指向反向迭代器当前元素的下一个位置的正向迭代器。
1 | std::reverse_iterator<Iterator> rit; |
注意:
rit.base()
指向的并不是 rit
当前元素本身,而是 rit
指向元素的下一个位置。C++ 提供了 rbegin()
和 rend()
来支持容器的反向遍历:
rbegin()
返回一个反向迭代器,指向容器的最后一个元素。rend()
返回一个反向迭代器,指向容器反向遍历时的“结束位置”,即第一个元素之前的一个位置。++it
而非 --it
,因为反向迭代器的递增操作相当于在正向迭代器上进行递减操作。1 | for (auto it = collection.rbegin(); it != collection.rend(); ++it) { |
std::prev
函数接受两个参数:一个是指向迭代器的参数,另一个是整数偏移量。它返回从指定迭代器开始向前移动指定偏移量后的迭代器。std::next
函数接受两个参数:一个是指向迭代器的参数,另一个是整数偏移量。它返回从指定迭代器开始向后移动指定偏移量后的迭代器。1 | auto prevIt = std::prev(it); |
bitset类型存储二进制数位。
1 | std::bitset<16> foo; |
将数转化为其二进制的字符串表示
1 | int i = 3; |
1 |
|
1 |
|
1 | string vowel = "AEIOUaeiou"; |
1 | std::string s0 ("Initial string"); |
读取空格分割的
1 | stringstream txt(s); |
顺序容器包括vector、deque、list、forward_list、array、string,
关联容器包括set、map,
关联容器和顺序容器有着根本的不同:关联容器中的元素是按关键字来保存和访问的。与之相对,顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的。
链表,或者数组(如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1
,右孩子就是 i * 2 + 2
。)
链式结构如下,注意左右孩子节点
1 | struct TreeNode { |
深度遍历: 前/中/后序遍历。
注意:这里前中后,其实指的就是中间节点/根节点的遍历顺序
堆(Heap)是计算机科学中一类特殊的数据结构的统称。
堆通常是一个可以被看做一棵完全二叉树的数组对象。
堆满足下列性质:
堆中某个节点的值总是不大于或不小于其父节点的值。
堆总是一棵完全二叉树。
make_heap()
将区间内的元素转化为heap.
push_heap()
对heap增加一个元素.
pop_heap()
对heap取出下一个元素.
sort_heap()
对heap转化为一个已排序群集.
1 |
|
特性 | map | unordered_map |
---|---|---|
元素排序 | 严格弱序 | 无 |
常见实现 | 平衡树或红黑树 | 哈希表 |
查找时间 | O(log(n)) | 平均 O(1),最坏 O(n)(哈希冲突) |
插入时间 | O(log(n)) + 重新平衡 | 同查找时间 |
删除时间 | O(log(n)) + 重新平衡 | 同查找时间 |
需要比较器 | 只需 < 运算符 |
只需 == 运算符 |
需要哈希函数 | 不需要 | 需要 |
常见用例 | 当无法提供良好哈希函数或哈希 | 在大多数其他情况下。当顺序不重要时 |
函数太慢,或者需要有序时 |
map的value是int,默认为0。可以直接++
1 |
|
1 | // insert 不能覆盖元素,已经存在会失败 |
1 | mymap.erase ('c'); // erasing by key |
1 | //unordered_map 类模板中,还提供有 at() 成员方法,和使用 [ ] 运算符一样,at() 成员方法也需要根据指定的键,才能从容器中找到该键对应的值; |
常用于 一个值是否存在 的相关问题
set
(关键字即值,即只保存关键字的容器);使用红黑树,自动排序,关键字唯一。multiset
(关键字可重复出现的set);unordered_set
(用哈希函数组织的set);unordered_multiset
(哈希组织的set,关键字可以重复出现)。默认红黑树,使用std::less
作为比较器, 升序序列。
存放数据类型 | 排序规则 |
---|---|
整数、浮点数等 | 按从小到大的顺序排列 |
字符串 | 按字母表顺序排列 |
指针 | 按地址升序排列 |
指向某元素的指针 | 按指针地址递增的顺序排列 |
类(自定义) | 可以自定义排序规则 |
1 | // 自定义比较器,按降序排列 |
1 | //增改 |
并查集的基本操作
UnionFind(int n)
:每个元素初始化为自己的父节点。int find(int x)
:查找某个元素的根节点,并进行路径压缩以优化后续查找。int find(int x)
:将两个元素所在的集合合并为一个集合。核心是
C++ 中的容器适配器 stack
、queue
和 priority_queue
依赖不同的基础容器来实现特定的数据结构行为。每种容器适配器都有特定的成员函数要求,默认选择的基础容器是为了更好地满足这些要求。
容器适配器 | 基础容器筛选条件 | 默认使用的基础容器 |
---|---|---|
stack | 基础容器需包含以下成员函数: | deque |
- empty() |
||
- size() |
||
- back() |
||
- push_back() |
||
- pop_back() |
||
满足条件的基础容器有 vector 、deque 、list 。 |
||
queue | 基础容器需包含以下成员函数: | deque |
- empty() |
||
- size() |
||
- front() |
||
- back() |
||
- push_back() |
||
- pop_front() |
||
满足条件的基础容器有 deque 、list 。 |
||
priority_queue | 基础容器需包含以下成员函数: | vector |
- empty() |
||
- size() |
||
- front() |
||
- push_back() |
||
- pop_back() |
||
满足条件的基础容器有 vector 、deque 。 |
堆栈,先进先出
1 | stack<int> minStack; |
注意pop仅用于从堆栈中删除元素,并且没有返回值, 一般用法如下
1 | top_value = stIn.top(); |
1 |
|
deque 容器也擅长在序列尾部添加或删除元素(时间复杂度为O(1)),而不擅长在序列中间添加或删除元素。
1 |
|
1 |
|
1 | //降序队列(默认less<>), map/set默认也是使用less,但是是升序序列 |
一般是题目要求自己实现链表,而不是使用STL提供的链表list。
1 | // 单链表 |
STL list 容器,又称双向链表容器,即该容器的底层是以双向链表的形式实现的。
find()
语法,经常使用unorder_map<key, list<xxx>::iterator> listMap
保存元素位置来加速查找。for (it = list.begin(); it != list.end(); it++) if (it->key == key) break;
1 | //插入 |
1 | int array[2][3] = { |
1 |
|
vector是变长的连续存储:
1 | //创建一个vector,元素个数为nSize |
1 | //改变大小,预分配空间,增加 vector 的容量(capacity),但 size 保持不变。 |
vector 也支持中间insert元素,但是性能远差于list。
1 | void push_back(const T& x) //向量尾部增加一个元素X |
1 | iterator erase(iterator it) :删除向量中迭代器指向元素 |
1 | void swap(vector&) :交换两个同类型向量的数据 |
1 | reference at(int pos) :返回pos位置元素的引用 |
返回表示
1 | vector<int> func() { |
1 |
|
static_cast
用于良性类型转换,一般不会导致意外发生,风险很低。
hash <K>
模板专用的算法取决于实现,但是如果它们遵循 C++14 标准的话,需要满足一些具体的要求。这些要求如下:
[^1]: How to use unordered_set with custom types?
https://www.runoob.com/w3cnote/cpp-vector-container-analysis.html
【C++容器】数组和vector、array三者区别和联系
https://blog.51cto.com/liangchaoxi/4056308
https://blog.csdn.net/y601500359/article/details/105297918
————————————————
版权声明:本文为CSDN博主「stitching」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40250056/article/details/114681940
————————————————
版权声明:本文为CSDN博主「FishBear_move_on」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/haluoluo211/article/details/80877558
————————————————
版权声明:本文为CSDN博主「SOC罗三炮」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/luolaihua2018/article/details/109406092
————————————————
版权声明:本文为CSDN博主「鱼思故渊」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yusiguyuan/article/details/40950735
java 21 SDK
seems not contain Java Control Panel (javacpl.exe
), you need to install Java SE Development Kit 8u381 which include JDK 1.8
and JRE 1.8
https://www.topcoder.com
to allowed website (Attention: https)ContestAppletProd.jnlp
127.0.0.1
proxy and HTTP TUNE 1
to connect to server暂无
暂无
1 | len(day) |
strings, lists, tuples
1 | # Correct: |
1 | try: |
调参需要测试间隔值
1 | for i in range(1, 101, 3): |
enumerate
函数结合 for
循环遍历 list,以修改 list 中的元素。enumerate
函数返回一个包含元组的迭代器,其中每个元组包含当前遍历元素的索引和值。在 for 循环中,我们通过索引 i
修改了列表中的元素。1 | # 对于 二维list appDataDict |
itertools — 为高效循环而创建迭代器的函数
1 | for a,b,c in permutations((a,b,c)): |
x = round(x,3)
# 保留小数点后三位
1 | %c 格式化字符及其ASCII码 |
1 | print("My name is %s and weight is %d kg!" % ('Zara', 21)) |
' '.join(pass_list)
and pass_list.split(" ")
对齐"\n".join(["%-10s" % item for item in List_A])
1 | text = "Hello, world!" |
Python2.6 开始,通过 {}
和 :
来代替以前的 %
1 | >>>"{} {}".format("hello", "world") # 不设置指定位置,按默认顺序 |
数字处理
1 | print("{:.2f}".format(3.1415926)) # 保留小数点后两位 |
https://www.runoob.com/python/python-lists.html
1 | #创建元组 |
1 | 'a': 1, 'b': 2, 'b': '3'} tinydict = { |
empty dict
1 | a= {} |
1 | a_dict = {'color': 'blue'} |
1 | del tinydict['Name'] # 删除键是'Name'的条目 |
1 | tinydict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'} |
无序不重复序列
1 | a= set() # 空set |
1 | thisset.add("Facebook") |
1 | s.remove( x ) |
1 | setL=set(listV) |
1 | my_set = {'Geeks', 'for', 'geeks'} |
https://blog.csdn.net/weixin_63719049/article/details/125680242
1 | ^ 匹配字符串的开头 |
1 | re* 匹配0个或多个的表达式。 |
1 | # find should use \ to represent the (6|12|3) |
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;
而re.search匹配整个字符串,直到找到一个匹配。
从字符串的起始位置匹配
1 | re.match(pattern, string, flags=0) |
多个标志可以通过按位 OR(|)
它们来指定。如 re.I | re.M
被设置成 I 和 M 标志:
1 | re.I 使匹配对大小写不敏感 |
1 | matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I) |
打印部分内容
1 | matchObj.group() : Cats are smarter than dogs |
返回元组,可以指定开始,与结束位置。
1 | result = re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10') |
1 |
|
暂无
暂无
https://blog.csdn.net/weixin_39594191/article/details/111611346