🤖 作者:包瑞清(richie bao): lastmod: 2024-10-29T13:29:24+08:00

5.1 代码块:缩进和花括号{}

在编程语言中,代码块(code block)是指一组被视为一个整体的语句集合,通常在一个控制结构或函数/方法中一起执行。代码块有助于组织代码结构(将代码按逻辑组织,使得程序逻辑清晰,易于理解和维护),并且可以控制程序的执行流(如条件语句、循环语句和异常处理等控制结构中以代码块控制程序的执行流),并用于限定变量的作用域(局部变量只在所在的代码块内有效,外部无法访问)。在 Python 语言中代码块以强制缩进表示代码块的开始和结束,其缩进是 Python 语法的一部分,必须保持一致,通常为四个空格,所有处于同一缩进级别的代码视为同一代码块。而 C/C++ 和 C# 是由花括号{},显示的代码块标识符确定代码块的范围。{}不会影响代码的执行顺序,而是将相关语句组合为一个执行单位,通常为各种的控制结构、类和方法/函数等。虽然缩进不是 C/C++ 和 C# 代码块的标识,但通常也使用缩进来提高代码的可读性。在所有的语言中都可以嵌套代码块,即在一个代码块中再定义另一个代码块,缩进或{}都能标识嵌套关系。对 Python、C/C++ 和 C# 的代码块语法比较如表。

语言 代码块的定义方式 缩进规范 代码块作用域标识符
Python 使用缩进定义代码块 强制使用一致的缩进(通常为4个空格) 无花括号,依赖缩进
C/C++、C# 使用花括号{}定义代码块 自由缩进(通常用4个空格或制表符),主要为了提高代码的可读性 使用{}

5.2 控制结构

控制结构 说明 Py C C++ C#
条件语句

if条件语句

条件语句在编程语言中用于根据某个条件的真假来决定程序执行的路径,其通常会判断布尔表达式的值来选择不同的代码块。在 Python 语言中,条件语句关键字包括ifelifelse;而在 C 系列语言中为ifelse ifelse。其中的差异在于elifelse if。通过关键字的组合可以构建不同分支方式,主要有if结构、if-else if (elif)结构和if-else if(elif)-else结构等,基本语法如表。

结构 Py C, C++, C#

if 结构

  if condition:
    # 如果条件为真(True),执行的代码
  
  if (condition) {
    // 如果条件为真(true),执行的代码
}
  

if-else if (elif)结构

  if condition:
    # 如果条件为真(True),执行的代码
else:
    # 如果条件为假(False),执行的代码
  
  if (condition) {
    // 如果条件为真(true),执行的代码
} else {
    // /如果条件为假(false),执行的代码
}
  

if-else if(elif)-else结构

  if condition1:
    # 如果 condition1 为真(True),执行的代码
elif condition2:
    # 如果 condition2 为真(True),执行的代码
else:
    # 如果前面所有条件都为假(False),执行的代码
  
  if (condition1) {
    // 如果 condition1 为真(true),执行的代码
} else if (condition2) {
    // 如果 condition2 为真(true),执行的代码
} else {
    // 如果前面所有条件都为假(false),执行的代码
}
  
  • if结构
  x = 10
if x > 0:
    print(f"{x}: Positive")
  
  🡮
10: Positive
  
  • if-else结构
  x = -10
if x > 0:
    print(f"{x}: Positive")
else:
    print(f"{x}: Negative")
  
  🡮
-10: Negative
  
  • if-elif-else结构
  x = 0
if x > 0:
    print(f"{x}: Positive")
elif x == 0:
    print(f"{x}: Zero")
else:
    print(f"{x}: Negative")
  
  🡮
0: Zero
  
  • if 结构
  #include <stdio.h>

int main() {
	int x = 10;
	if (x > 0) {
		printf("%d: Positive", x);
	}

	return 0;
}
  
  🡮
10: Positive
  
  • if-else结构
  #include <stdio.h>

int main() {
	int x = -10;
	if (x > 0) {
		printf("%d: Positive", x);
	}
	else {
		printf("%d: Negative", x);
	}
	return 0;
}
  
  🡮
-10: Negative
  
  • if-else if-else结构
  #include <stdio.h>

int main() {
	int x = 0;
	if (x > 0) {
		printf("%d: Positive", x);
	}
	else if (x == 0) {
		printf("%d: Zero", x);
	}
	else {
		printf("%d: Negative", x);
	}
	return 0;
}
  
  🡮
0: Zero
  
  • if 结构
  #include <iostream>
#include <format>


int main() {
	int x = 10;
	if (x > 0) {
		std::cout << std::format("{}: Positive", x);
	}

	return 0;
}
  
  🡮
10: Positive
  
  • if-else结构
  #include <iostream>
#include <format>


int main() {
	int x = -10;
	if (x > 0) {
		std::cout << std::format("{}: Positive", x);
	}
	else {
		std::cout << std::format("{}: Negative", x);
	}

	return 0;
}
  
  🡮
-10: Negative
  
  • if-else if-else结构
  #include <iostream>
#include <format>

int main() {
	int x = 0;
	if (x > 0) {
		std::cout << std::format("{}: Positive", x);
	}
	else if(x==0){
		std::cout << std::format("{}: Zero", x);
	}
	else {
		std::cout << std::format("{}: Negative", x);
	}

	return 0;
}
  
  🡮
0: Zero
  
  • if结构
  using System;

class Program
{

    static void Main()
    {
        int x = 10;
        if (x > 0)
        {
            Console.WriteLine($"{x}: Positive");
        }
    }
}
  
  🡮
10: Positive
  
  • if-else结构
  using System;

class Program
{

    static void Main()
    {
        int x = -10;
        if (x > 0)
        {
            Console.WriteLine($"{x}: Positive");
        }
        else
        {
            Console.WriteLine($"{x}: Negative");
        }
    }
}
  
  🡮
-10: Negative
  
  • if-else if-else结构
  using System;

class Program
{

    static void Main()
    {
        int x = 0;
        if (x > 0)
        {
            Console.WriteLine($"{x}: Positive");
        }
        else if (x == 0)
        {
            Console.WriteLine($"{x}: Zero");
        }
        else
        {
            Console.WriteLine($"{x}: Negative");
        }
    }
}
  
  🡮
0: Zero
  

条件运算符(三元运算符)

条件运算符用于根据条件选择一个值,是if-else if (elif)结构的简化版本,可以用于较为简单的判断条件,使得语句更为简洁。Python 和 C 系列语言条件运算符的基本语法如表。

Py C,C++,C#
  value = expression1 if condition else expression2
  
  condition ? expression1 : expression2
  
  a, b = 5, 10
max_value = a if a > b else b
print(f"Max value: {max_value}")
  
  🡮
Max value: 10
  
  #include <stdio.h>

int main() {
	int a = 5, b = 10;
	int max = (a > b) ? a : b;
	printf("Max value: %d", max);

	return 0;
}
  
  🡮
Max value: 10
  
  #include <iostream>
#include <format>

int main() {
	int a = 5, b = 10;
	int max = (a > b) ? a : b;
	std::cout << std::format("Max value: {}", max);

	return 0;
}
  
  🡮
Max value: 10
  
  using System;

class Program
{

    static void Main()
    {
        int a = 5, b = 10;
        int max = (a > b) ? a : b;
        Console.WriteLine($"Max value: {max}");
    }
}
  
  🡮
Max value: 10
  

switchmatch

Python 中的match-case和 C 系列语言中的switch-case用于根据表达式的值跳转到不同的case。当有多个条件判断时,switch/match语句使得代码更加简洁。每个case对应一个常量值,程序根据表达式的值匹配相应的case,如果没有匹配的case,则执行default/_分支。其语法如表。

Py C、C++、C#
  match expression:
    case pattern1:
        # 如果表达式匹配 pattern1 代码块
    case pattern2:
        # 如果表达式匹配 pattern2 代码块
    case _:
        # 默认情况(匹配任何)
  
  switch (expression) {
    case constant1:
        // 匹配常量 constant1
        break;
    case constant2:
        // 匹配常量 constant2
        break;
    ...
    default:
        // 不匹配的代码块
        break;
}
  

各类语言的case标签所能支持的类型不同,Python 使用match语句支持多种任意类型的模式匹配,包括复杂数据结构;C/C++ 的switch语句支持整型(int)、字符型(char)、枚举类型(enum)等基本类型。C++ 并拓展了constexpr的常量类型;C# 支持整数、字符、字符串、枚举类型,且支持模式匹配和switch表达式,如表。

语言 支持的 case标签类型
Py 任意类型(常量、对象、序列、字典、类实例等)
C 整数类型、字符常量、枚举类型
C++ 整数类型、字符常量、枚举类型、constexpr 常量
C# 整数类型、字符常量、字符串、枚举类型、模式匹配
  • 基本的match语句
  day = 3
match day:
    case 1:
        print("Monday")
    case 2:
        print("Tuesday")
    case 3:
        print("Wednesday")
    case _:
        print("Invalid day")
  
  🡮
Wednesday
  

+ 匹配——解构

match可以匹配复杂的结构,如元组、列表和字典等。

解构元组:

  person = ("Alice", 30)

match person:
    case ("John", age):
        print(f"Name is John, Age is {age}")
    case ("Alice", age):
        print(f"Name is Alice, Age is {age}")
    case _:
        print("Unkwon person")
  
  🡮
Name is Alice, Age is 30
  

解构字典:

  person={"name":"Alice","age":30}
match person:
    case {"name":name,"age":age}:
        print(f"Name: {name},Age: {age}")
    case _:
        print("Unknown person")
  
  🡮
Name: Alice,Age: 30
  

+ 匹配——类型

match可以匹配数据类型。

  def handle_value(value):
    match value:
        case int():
            print(f"Integer: {value}")
        case str():
            print(f"String: {value}")
        case list():
            print(f"List: {value}")
        case _:
            print("Unkown type")

handle_value(98)
handle_value("World!")
handle_value([10,20])
  
  🡮
Integer: 98
String: World!
List: [10, 20]
  
  • 基本的switch语句
  #include <stdio.h>

int main() {
	int day = 3;
	switch (day) {
		case 1:
			printf("Monday\n");
			break;
		case 2:
			printf("Tuesday\n");
			break;
		case 3:
			printf("Wednsday\n");
			break;
		default:
			printf("Invalid day\n");
			break;
	}

	return 0;
}
  
  🡮
Wednsday
  

+ switch 的穿透现象

如果没有使用 breakswitch会发生“穿透”(fall-through)现象,继续执行后面的case,直至遇到break,或者执行到switch的末尾。

  #include <stdio.h>

int main() {
	int day = 2;
	switch (day) {
		case 1:
			printf("Monday\n");
		case 2:
			printf("Tuesday\n");
		case 3:
			printf("Wednsday\n");
			break;
		default:
			printf("Invalid day\n");
			break;
	}

	return 0;
}
  
  🡮
Tuesday
Wednsday
  

+ switch 的枚举类型(enum

  #include <stdio.h>

enum Day{Monday=1,Tuesday,Wednesday};

int main() {
	int day = 3;
	
	switch (day) {
		case 1:
			printf("Monday\n");
			break;
		case 2:
			printf("Tuesday\n");
			break;
		case 3:
			printf("Wednesday\n");
			break;
		default:
			printf("Invalid day\n");
			break;
	}
	
	return 0;
}
  
  🡮
Wednesday
  
  • 基本的switch语句
  #include <iostream>
#include <format>

int main() {
	int day = 3;
	switch (day) {
		case 1:
			std::cout << "Monday" << std::endl;
			break;
		case 2:
			std::cout << "Tuesday" << std::endl;
			break;
		case 3:
			std::cout << "Wednesday" << std::endl;
			break;
		default:
			std::cout << "Invalid day" << std::endl;
			break;
	}

	return 0;
}
  
  🡮
Wednesday
  

+ switch 的穿透现象

  #include <iostream>
#include <format>

int main() {
	int day = 2;
	switch (day) {
		case 1:
			std::cout << "Monday" << std::endl;
		case 2:
			std::cout << "Tuesday" << std::endl;
		case 3:
			std::cout << "Wednesday" << std::endl;
			break;
		default:
			std::cout << "Invalid day" << std::endl;
			break;
	}

	return 0;
}
  
  🡮
Tuesday
Wednesday
  

+ switch 的枚举类型(enum

  #include <iostream>

enum Day {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};

int main() {
	Day day = Wednesday;

	switch (day) {
		case Monday:
			std::cout << "Start of the week\n";
			break;
		case Wednesday:
			std::cout << "Midweek\n";
			break;
		case Friday:
			std::cout << "Almost weekend\nj";
			break;
		default:
			std::cout << "Weekend\n";
			break;
	}

	return 0;
}
  
  🡮
Midweek
  

+ switchconstexpr类型

在 C++11 及更高版本中,constexpr引入了编译期常量的概念,为在编译过程中得到计数结果的常量表达式。switchcase标签必须是编译期常量,而constexpr提供了的方法确保在编译期求值。

  #include <iostream>

constexpr int getDayValue(int day) {
	return day + 1;
}

int main() {
	constexpr int day = getDayValue(2);

	switch (day) {
	case 1:
		std::cout << "Monday\n";
		break;
	case 2:
		std::cout << "Tuesday\n";
		break;
	case 3:
		std::cout << "Wednesday\n";
		break;
	default:
		std::cout << "Invalid day\n";
		break;
	}
	
	return 0;
}
  
  🡮
Wednesday
  
  • 基本的switch语句
  using System;

class Program
{

    static void Main()
    {
        int day = 3;
        switch (day)
        {
            case 1:
                Console.WriteLine("Monday");
                break;
            case 2:
                Console.WriteLine("Tuesday");
                break;
            case 3:
                Console.WriteLine("Wednesday");
                break;
            default:
                Console.WriteLine("Invalid day");
                break;
        }
    }
}
  
  🡮
Wednesday
  

+ switch 的枚举类型(enum

  using System;

enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }


class Program
{

    static void Main()
    {
        Day day=Day.Wednesday;

        switch (day)
        {
            case Day.Monday:
                Console.WriteLine("Start of the week");
                break;
            case Day.Wednesday:
                Console.WriteLine("Midweek");
                break;
            case Day.Friday:
                Console.WriteLine("Almost weekend");
                break;
            default:
                Console.WriteLine("Weekend");
                break;
        }
    }
}
  
  🡮
Midweek
  

+ switch 的表达式

C# 8.0 引入了 switch表达式,使得switch可以作为表达式而不仅仅是语句。switch表达式更加简洁,且每个case使用=>表达式形式。

  using System;

class Program
{

    static void Main()
    {
        int day = 3;
        string dayName = day switch
        {
            1 => "Monday",
            2 => "Tuesday",
            3 => "Wednesday",
            _ => "Invalid day"
        };
        Console.WriteLine(dayName);
    }
}
  
  🡮
Wednesday
  

+ switch 的模式匹配

在 C# 9.0 中,switch语句支持模式匹配,可以根据条件进行匹配,甚至可以将case条件与类型检查结合使用。

  using System;

class Program
{

    static void Main()
    {
        object value = 3.14;

        string result = value switch
        {
            int i when i > 0 => $"Positive integer: {i}",
            int i => $"Negative integer: {i}",
            double d => $"Double: {d}",
            string s => $"String: {s}",
            _ => "Unknown type"
        };
        Console.WriteLine(result);
    }
}
  
  🡮
Double: 3.14
  

循环语句

for 循环

Python、C、C++ 和 C# 中,for循环语句的基本功能类似,用于多次重复的执行代码块。不同语言在语法和一些特性上有所差异,特别是在迭代方式,数据类型和简洁性上,表中列出了各自实现的基本语法。

类型 Py C C++ C#
基本形式(返回“索引值”形式) for variable in range(start, stop, step): for (initialization; condition; increment) { } for (initialization; condition; increment) { } for (initialization; condition; increment) { }
返回元素形式 for item in collection:(for-in)结构 / for (auto element : container) { } foreach (var item in collection) { }
  • for的基本用法(for-in)
  numbers = [10,20,30,40,50]
for i in numbers:
    print(f"{i}, ",end="")
  
  🡮
10, 20, 30, 40, 50,
  
  • range()函数生成数值序列。
  for i in range(1,6,1):
    print(f"{i}, ", end="")
  
  🡮
1, 2, 3, 4, 5, 
  
  • for循环遍历列表
  lst = [10,20,30,40,50]
for i in range(len(lst)):
    print(f"Element {i}: {lst[i]}; ",end="")
  
  🡮
Element 0: 10; Element 1: 20; Element 2: 30; Element 3: 40; Element 4: 50; 
  
  • for循环遍历字典

配合字典的keys()values()items()方法循环字典。如果直接循环列表,则为循环其键。

  score = {"Henry": 99, "Oliver": 86, "Emily": 91, "Lily": 76}

# 循环键
for k in score:
    print(f"{k}:{score[k]}; ", end="")

print("\n")

for k in score.keys():
    print(f"{k}:{score[k]}; ", end="")

print("\n")

# 循环值
for v in score.values():
    print(f"{v}; ", end="")

print("\n")

# 循环键值对
for k, v in score.items():
    print(f"{k}:{v}; ", end="")
  
  🡮
Henry:99; Oliver:86; Emily:91; Lily:76;

Henry:99; Oliver:86; Emily:91; Lily:76;

99; 86; 91; 76;

Henry:99; Oliver:86; Emily:91; Lily:76; P
  
  • 无限for循环

Python 中常用while循环来实现。下述示例使用了iter(int,1)的方法实现。

  for _ in iter(int,1):
    print("Infinite loop!")
	break
  
  🡮
Infinite loop!
  
  • 嵌套for循环
  for i in range(1,4,1):
    for j in range(1,4,1):
        print(f"{i} x {j} = {i*j}\t", end="")
    print("\n")
  
  🡮
1 x 1 = 1       1 x 2 = 2       1 x 3 = 3

2 x 1 = 2       2 x 2 = 4       2 x 3 = 6

3 x 1 = 3       3 x 2 = 6       3 x 3 = 9
  
  • continuebreak

continue是在满足条件下跳过当前迭代循环体内的其余部分,进入下一次迭代;而break语句是完全退出循环。下述结果中没有数字5,和到数字8(不含自身)终止说明了这一点。

  for i in range(1, 11, 1):
    if i == 5:
        continue
    if i == 8:
        break
    print(f"{i}, ", end="")
  
  🡮
1, 2, 3, 4, 6, 7, P
  
  • for循环下使用else子句

Python 的for循环支持else子句,else部分会在循环正常完成后执行;如果循环被break终止,则else部分将不会执行。

  for i in range(5):
    if i == 3:
        break
    print(f"{i}, ", end="")
else:
    print("Loop ends normally.")
  
  🡮
0, 1, 2, 
  
  • for的基本用法
  #include <stdio.h>

int main() {
	for (int i = 1; i <= 5; i++) {
		printf("%d, ", i);
	}
	
	return 0;
}
  
  🡮
1, 2, 3, 4, 5,
  
  • for循环遍历数组
  #include <stdio.h>

int main() {
	int arr[] = { 10,20,30,40,50 };
	int length = sizeof(arr) / sizeof(arr[0]);

	for (int i = 0; i < length; i++) {
		printf("Element %d: %d; ", i, arr[i]);
	}
	
	return 0;
}
  
  🡮
Element 0: 10; Element 1: 20; Element 2: 30; Element 3: 40; Element 4: 50;
  
  • 无限for循环

如果省略了条件部分,那么for循环会一直持续下去,因此通常需要使用break语句来退出循环。

  #include <stdio.h>

int main() {

	for (;;) {
		printf("This will print forever!");
		break;
	}
	
	return 0;
}
  
  🡮
This will print forever!
  
  • 嵌套for循环
  #include <stdio.h>

int main() {
	for (int i = 1; i <= 3; i++) {
		for (int j = 1; j <= 3; j++) {
			printf("%d x %d = %d\t", i, j, i * j);
		}
		printf("\n");
	}

	return 0;
}
  
  🡮
1 x 1 = 1       1 x 2 = 2       1 x 3 = 3
2 x 1 = 2       2 x 2 = 4       2 x 3 = 6
3 x 1 = 3       3 x 2 = 6       3 x 3 = 9
  
  • continuebreak

for 循环中,continue语句用于跳过当前循环迭代的剩余部分,直接进入下一次迭代。可以用来在满足特定条件下跳过某些代码,从而灵活控制循环流程。例如下述示例过滤特定条件的元素,当为小于0的整数值时,跳过printf()代码行而直接进入下一次迭代,即仅打印输出大于和等于0的整数。

  #include <stdio.h>

int main() {
	int numbers[] = { 7,0,-3,6,-12,5,9 };
	int length = sizeof(numbers) / sizeof(numbers[0]);

	for (int i = 0; i < length; i++) {
		if (numbers[i] < 0) {
			continue; // 跳过非正数
		}
		printf("%d, ", numbers[i]);
	}

	return 0;
}
  
  🡮
7, 0, 6, 5, 9,
  

continue是在满足条件下跳过当前迭代循环体内的其余部分,进入下一次迭代;而break语句是完全退出循环。下述结果中没有数字5,和到数字8(不含自身)终止说明了这一点。

  #include <stdio.h>

int main() {
	for (int i = 1; i <= 10; i++) {
		if (i == 5) {
			continue;
		}
		if (i == 8) {
			break;
		}
		printf("%d, ", i);
	}

	return 0;
}
  
  🡮
1, 2, 3, 4, 6, 7,
  
  • for的基本用法
  #include <iostream>
#include <format>

int main() {
	for (int i = 1; i <= 5; i++) {
		std::cout << std::format("{}, ", i);
	}
	
	return 0;
}
  
  🡮
1, 2, 3, 4, 5,
  
  • for循环遍历数组
  #include <iostream>
#include <format>

int main() {
	int arr[] = { 10,20,30,40,50 };
	int length = sizeof(arr) / sizeof(arr[0]);

	for (int i = 0; i < length; i++) {
		std::cout << std::format("Element {}: {}", i, arr[i]);
	}
	
	return 0;
}
  
  🡮
Element 0: 10Element 1: 20Element 2: 30Element 3: 40Element 4: 50
  
  • Range-Based(基于范围)for循环语句

C++ 11 引入了 Range-Based for 循环,用于遍历容器(如数组、std::vector等),该语句使循环代码更简洁。但是需要注意直接对容器内的元素循环时,并不返回元素对应的索引。同时因为为可循环访问的任何内容,可以优先考虑使用auto关键字,或者直接指定容器元素的数据类型。

  #include <iostream>
#include <format>
#include <vector>

int main() {
	std::vector<int> numbers = { 10,20,30,40,50 };
	for (auto num : numbers) {
		std::cout << std::format("{}, ", num);
	}
	
	return 0;
}
  
  🡮
10, 20, 30, 40, 50,
  

可以在 Range-Based for 循环中使用引用类型修改容器内的元素。

引用(Reference),使用符号 & 来声明,为一种轻量的别名机制。引用可以通过为变量创建别名,使得对引用的操作直接影响原始变量

  #include <iostream>
#include <format>
#include <vector>

int main() {
	std::vector<int> numbers = { 10,20,30,40,50 };
	for (auto &num : numbers) {
		num *= 2;
	}

	for (auto num : numbers) {
		std::cout << std::format("{}, ", num);
	}
		
	return 0;
}
  
  🡮
20, 40, 60, 80, 100,
  
  • 无限for循环

如果省略了条件部分,那么for循环会一直持续下去,因此通常需要使用break语句来退出循环。

  #include <iostream>
#include <format>

int main() {
	for (;;) {
		std::cout << "This will print forever!" << std::endl;
		break; // 使用 break 语句退出循环
	}
	
		
	return 0;
}
  
  🡮
This will print forever!
  
  • 嵌套for循环
  #include <iostream>
#include <format>

int main() {
	for (int i = 1; i <= 3; i++) {
		for (int j = 1; j <= 3; j++) {
			std::cout << std::format("{} x {} = {}\t", i, j, i * j);
		}
		std::cout << "\n";
	}
		
	return 0;
}
  
  🡮
1 x 1 = 1       1 x 2 = 2       1 x 3 = 3
2 x 1 = 2       2 x 2 = 4       2 x 3 = 6
3 x 1 = 3       3 x 2 = 6       3 x 3 = 9
  
  • continuebreak

continue是在满足条件下跳过当前迭代循环体内的其余部分,进入下一次迭代;而break语句是完全退出循环。下述结果中没有数字5,和到数字8(不含自身)终止说明了这一点。

  #include <iostream>
#include <format>

int main() {
	for (int i = 1; i <= 10; i++) {
		if (i == 5) {
			continue;
		}
		if (i == 8) {
			break;
		}
		std::cout << std::format("{}, ", i);
	}
	return 0;
}
  
  🡮
1, 2, 3, 4, 6, 7,
  
  • for的基本用法
  using System;

class Program
{

    static void Main()
    {
        for (int i = 1; i <= 5; i++)
        {
            Console.Write($"{i}, ");
        }
    }
}
  
  🡮
1, 2, 3, 4, 5,
  
  • for循环遍历数组
  using System;

class Program
{
    static void Main()
    {
        int[] arr = new int[] { 10, 20, 30, 40, 50 };
        for (int i = 0; i < arr.Length; i++)
        {
            Console.Write($"Element {i}: {arr[i]}");
        }
    }
}
  
  🡮
Element 0: 10Element 1: 20Element 2: 30Element 3: 40Element 4: 50
  
  • foreach循环
  using System;
using System.Collections.Generic;

class Program
{

    static void Main()
    {
        List<int> numbers = [ 10, 20, 30, 40, 50 ];
        foreach (var num in numbers)
        {
            Console.Write($"{num}, ");
        }
    }
}
  
  🡮
10, 20, 30, 40, 50,
  
  • 无限for循环

如果省略了条件部分,那么for循环会一直持续下去,因此通常需要使用break语句来退出循环。

  using System;

class Program
{

    static void Main()
    {
        for (; ; )
        {
            Console.WriteLine("Infinite loop!");
            break;
        }
    }
}
  
  🡮
Infinite loop!
  
  • 嵌套for循环
  using System;

class Program
{

    static void Main()
    {
        for (int i = 1; i <= 3; i++)
        {
            for (int j = 1; j <= 3; j++)
            {
                Console.Write($"{i} x {j} = {i * j}\t");
            }
            Console.WriteLine();
        }
    }
}
  
  🡮
1 x 1 = 1       1 x 2 = 2       1 x 3 = 3
2 x 1 = 2       2 x 2 = 4       2 x 3 = 6
3 x 1 = 3       3 x 2 = 6       3 x 3 = 9
  
  • continuebreak

continue是在满足条件下跳过当前迭代循环体内的其余部分,进入下一次迭代;而break语句是完全退出循环。下述结果中没有数字5,和到数字8(不含自身)终止说明了这一点。

  using System;
using System.Runtime.CompilerServices;

class Program
{

    static void Main()
    {
        for (int i = 1; i <= 10; i++)
        {
            if (i == 5)
            {
                continue;
            }
            if (i == 8)
            {
                break;
            }
            Console.Write($"{i}, ");
        }
    }
}
  
  🡮
1, 2, 3, 4, 6, 7,
  

whiledo-while循环

while循环用于条件为真时重复执行代码块,适合在循环次数不确定的情况下使用,当满足某个条件时才停止循环。while循环通常包括三种情况,条件控制循环,无限循环和do-while的后测试循环。语法如表。

语言 基本语法(条件控制循环) 无限循环 do-while(后测试循环)
Py while condition: while True: 不支持do-while,但可以通过while Truebreak实现
C while (condition) { } while (1) { } do { } while (condition);
C++ while (condition) { } while (true) { } do { } while (condition);
C# while (condition) { } while (true) { } do { } while (condition);

如果将条件设置为永远为真,则可以创建一个无限循环。在使用无限while循环时,要明确添加break语句,当满足某一指定条件时跳出循环,避免程序无限运行。C/C++和C#支持do-while循环,确保循环体至少执行一次,Python不支持do-while,但可以通过while Truebreak实现。

  • while的基本用法
  i = 1

while i <= 5:
    print(f"{i}, ", end="")
    i += 1
  
  🡮
1, 2, 3, 4, 5, 
  
  • 无限while循环
  i = 0

while True:  # 无限循环
    print(f"{i}, ", end="")
    i += 1

    if i == 5:
        break  # 当 i 等于 5 时退出循环
  
  🡮
0, 1, 2, 3, 4, 
  
  • 模拟do-while循环
  counter = 1

while True:
    print(f"{counter}, ", end="")
    counter += 1
    if counter > 5:
        break
  
  🡮
1, 2, 3, 4, 5, 
  
  • while的基本用法
  #include <stdio.h>

int main() {
	int i = 1;
	while (i <= 5) {
		printf("%d, ", i);
		i++;
	}
	return 0;
}
  
  🡮
1, 2, 3, 4, 5,
  
  • 无限while循环
  #include <stdio.h>

int main() {
	int i = 0;
	
	while (1) { // 无限循环
		printf("%d, ", i);
		i++;
		if (i == 5) {
			break; // 当 i 等于 5 时退出循环
		}
	}
	return 0;
}
  
  🡮
0, 1, 2, 3, 4,
  
  • do-while循环
  #include <stdio.h>

int main() {
	int counter = 1;

	do {
		printf("%d, ", counter);
		counter++;
	} while (counter <= 5);

	return 0;
}
  
  🡮
1, 2, 3, 4, 5,
  
  • while的基本用法
  #include <iostream>
#include <format>

int main() {
	int i = 1;

	while (i <= 5) {
		std::cout << std::format("{}, ", i);
		i++;
	}

	return 0;
}
  
  🡮
1, 2, 3, 4, 5,
  
  • 无限while循环
  #include <iostream>
#include <format>

int main() {
	int i = 0;

	while (true) { // 无限循环
		std::cout << std::format("{}, ", i);
		i++;

		if (i == 5) {
			break; // 当 i 等于 5 时退出循环
		}
	}

	return 0;
}
  
  🡮
0, 1, 2, 3, 4,
  
  • do-while循环
  #include <iostream>
#include <format>

int main() {
	int counter = 1;

	do {
		std::cout << std::format("{}, ", counter);
		counter++;
	} while (counter <= 5);

	return 0;
}
  
  🡮
1, 2, 3, 4, 5,
  
  • while的基本用法
  using System;

class Program
{

    static void Main()
    {
        int i = 1;

        while (i <= 5)
        {
            Console.Write($"{i}, ");
            i++;
        }
    }
}
  
  🡮
1, 2, 3, 4, 5,
  
  • 无限while循环
  using System;

class Program
{

    static void Main()
    {
        int i = 0;

        while (true) // 无限循环
        {
            Console.Write($"{i}, ");
            i++;

            if (i == 5)
            {
                break; // 当 i 等于 5 时退出循环
            }
        }
    }
}
  
  🡮
0, 1, 2, 3, 4,
  
  • do-while循环
  using System;

class Program
{

    static void Main()
    {
        int counter = 1;

        do
        {
            Console.Write($"{counter}, ");
            counter++;
        } while (counter <= 5);
        
    }
}
  
  🡮
1, 2, 3, 4, 5,
  

异常处理

异常(Exception)是指程序在运行过程中出现的错误或意外情况,包括运行时错误(如除零错误、数组越界、空指针等),资源问题(如文件未找到、网络或数据库连接失败等),数据问题(如无效的输入数据、数据格式错误等)等由程序执行时错误条件引发的情况。异常处理是编程语言中重要的机制,用于捕获、报告和处理这些错误(如重试、记录日志、向用户显示错误信息等),以确保程序的稳定性和可维护性。异常处理机制通常包括抛出异常(throwing exception),捕获异常(catching exception)和处理异常(handling exception)。即当程序检查到错误条件时,抛出异常(通常在try块中);进而程序的控制流转移到异常处理块(通常为exceptcatch块);在异常处理块中处理捕获到的异常,可以采取恢复或报告错误信息等方式。

特性 Python C C++ C#
异常处理机制 内置tryexceptelsefinally关键字 无内置异常处理机制,但可以通过函数返回值,或setjmp/longjmp等内置函数或宏实现 内置trycatchthrow关键字 内置trycatchthrowfinally关键字
自定义异常 通过继承Exception类实现 通过返回值或错误代码 通过继承std::exception实现 通过继承Exception类实现
多重捕获异常 支持多个except 手动判断不同的错误码 支持多个catch 支持多个catch
清理机制 finally 无内置清理机制,需要手动清理 RAII 机制 finally
异常传播 异常会传播到调用栈上 手动处理错误码 异常会传播到调用栈上 异常会传播到调用栈上
性能 异常处理较慢,性能开销较大 无异常处理机制,性能较高 异常处理较慢,但支持优化 异常处理有性能开销,但优化较好

Python 使用tryexceptelsefinally关键字进行异常处理。其语法如下,

  try:
    # 尝试执行的代码(可能包含引发异常的代码)
except 异常类型:
    # 发生异常时执行的代码(当 try 代码块中的代码引发异常,跳转到 except 当前代码块执行相应的处理)(可包含多个 except 代码块,处理不同的异常)
else:
    # 没有异常时执行的代码(可选)
finally:
    # 无论是否发生异常都会执行的代码,通常用于清理资源(可选)
  
  • 基本的异常处理

Python 内置的异常层次结构如附1。

  try:
    x = int(input("Enter a number: "))
    y = 10 / x
except ValueError:
    print("Invalid input. Please enter a valid integer.")
except ZeroDivisionError:
    print("Cannot divide by zero!")
else:
    print("Division successful. Result:", y)
finally:
    print("Execution finished.")
  
  🡮
Enter a number: five
Invalid input. Please enter a valid integer.
Execution finished.

Enter a number: 0
Cannot divide by zero!
Execution finished.

Enter a number: 5
Division successful. Result: 2.0
Execution finished.
  
  • 捕获多个异常

在基本的异常处理示例中,使用了两个except块来捕捉异常,可以使用except(ExceptionType-1,ExceptionType-2,...,ExceptionType-n )将多个except块合并到一个exxcept下来捕获异常。

  try:
    x = int(input("Enter a number: "))
    y = 10 / x
    print("Division successful. Result:", y)
except (ValueError, ZeroDivisionError) as e:
    print(f"An error occure: {e}.")
  
  🡮
Enter a number: five
An error occure: invalid literal for int() with base 10: 'five'.

Enter a number: 0
An error occure: division by zero.

Enter a number: 5
Division successful. Result: 2.0
  
  • 触发异常

raise可以强制触发指定的异常。raise唯一的参数就是触发的异常。

  x=-5
if x<0:
    raise ValueError("Only non-negative numbers are allowed.")
  
  🡮
[Exception Thrown]
Only non-negative numbers are allowed.
  

通过raise触发异常,并在except下打印该异常实例参数。

  try:
    raise Exception("spam", "eggs")
except Exception as inst:
    print(type(inst))  # 为异常实例
    print(inst.args)  # 存储在 inst.args 中的参数
    print(inst)  # __str__ 许直接打印参数,但可能在异常子类中被覆盖
    x, y = inst.args  # 序列解包参数
    print("x =", x)
    print("y =", y)
  
  🡮
<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs
  

如果只想判断是否触发了异常,但并不打算处理该异常,则可以使用更简单的 raise 语句重新触发异常。

  try:
    raise NameError("HiThere")
except NameError:
    print("An exception flew by!")
    raise
  
  🡮
An exception flew by!
  
  • 自定义异常类

可以通过继承Exception类自定义异常。通常异常命名以Error结尾,类似标准异常的命名。

  class CustomError(Exception):
    pass


try:
    raise CustomError("A custom error occurred.")
except CustomError as e:
    print(e)
  
  🡮
A custom error occurred.
  

可以定义__str__()类,附加状态信息或者方法。

  class AlreadyGotOneError(Exception):
    def __str__(self):
        return "So you got an exception..."

    pass  # 自定义异常


def grail():
    raise AlreadyGotOneError  # 引发自定义异常


try:
    grail()
except AlreadyGotOneError as ago_e:
    print(ago_e)
    print("got exception!")
  
  🡮
So you got an exception...
got exception!
  

在 C 语言中没有原生的异常处理机制,但可以通过函数返回值或 C 语言标准库中提供的方法实现。

  • 返回错误码

通过函数返回值来表示错误或异常,例如下述示例中函数返回 0 表示成功运行,而返回非零值表示发生了异常。

  #include <stdio.h>

int divide(int a, int b, int* result) {
	if (b == 0) {
		return -1; //  Return error code for division by zero
	}
	*result = a / b;
	return 0; // Success
}

int main() {
	int a = 10, b = 0, result;
	if (divide(a, b, &result) != 0) {
		printf("Error: Division by zero~\n");
	}
	else {
		printf("Result: %d\n", result);
	}

	return 0;
}
  
  🡮
Error: Division by zero~
  
  • setjmplongjmp

setjmplongjmp是 C 语言标准库中提供的一对函数,用于在程序中实现非局部跳转,允许在某个函数中保存当前执行的状态(即程序计数器和栈指针等信息),然后从另一个函数中恢复并跳转回这个保存的状态。主要用于错误或异常处理。setjmp用于保存当前的执行状态。在调用setjmp时,会记录当前的堆栈信息,并将其存储到jmp_buf类型的结构中。jmp_buf是一个数据结构,用于保存堆栈信息和程序计数器。如果直接调用setjmp,则返回值 0。如果通过longjmp跳转回setjmp所在的位置,则返回一个非零值。longjmp即用于恢复并跳转到之前使用setjmp保存的执行状态,从而实现非局部跳转。

  #include <stdio.h>
#include <setjmp.h>

jmp_buf buf;

void functionError() {
	printf("An error occurred!\n");
	longjmp(buf, 1); // 跳转回设置点(保存状态)
}


int main() {
	if (setjmp(buf)) { //  初次调用 setjmp 返回 0
		// longjmp 后执行
		printf("Recovered from functionError\n");
	}
	else {
		functionError(); // 调用会触发错误的函数
		printf("This line will not be executed\n");
	}

	return 0;
}
  
  🡮
An error occurred!
Recovered from functionError
  

另外, <errno.h>是 C 语言标准库中的头文件,定义了与错误代码相关的宏和变量,用于表示程序运行时的错误状态,其包括了一个全局的整数变量errno,这个变量表示最近一次函数调用的错误代码,常和库函数fopenmalloc等配合使用。而<assert.h>assert宏用于检查表达式是否为真,如果为假则输出错误信息并终止程序,适合在调试阶段使用。

C++ 具有内置的异常处理,通过trycatchthrow关键字结构化的方法实现异常处理机制。

  • 基本语法

可能抛出异常的代码放置于try代码块中;catch块则捕获并处理这个异常;throw则用于在发生错误时抛出异常。C++ 标准库提供了一系列异常类,大多数都继承自std::exception,常用的有:

  • std::exception:多有异常的基类。
  • std::runtime_error:表示运行时错误。
  • std::logic_error:表示逻辑错误。
  • std::out_of_range:表示超出范围的错误。
  • std::invalid_argument:表示无效参数的错误。
  #include <iostream>
#include <format>
#include <stdexcept> // 用于标准异常

int divide(int a, int b) {
	if (b == 0) {
		throw std::runtime_error("Division by zero"); // 抛出异常
	}
	return a / b;
}

int main() {
	try {
		int result = divide(10, 0);
		std::cout << std::format("Result: {}\n", result);
	}
	catch (const std::runtime_error& e) {
		std::cerr << std::format("Error: {}\n", e.what()); // 捕获并处理异常
	}

	return 0;
}
  
  🡮
Error: Division by zero
  

std::cerr 是一个用于显示错误消息的标准输出流,是 iostream 库的一部分,通常用于向控制台输出错误或调试信息。std::cerr 与通常缓冲的 std::cout 不同,其没有缓冲,意味着每个 std::cerr 输出都会立即出现在控制台中,而无需等待换行符或手动刷新缓冲区。

  • 捕获多个异常

可以为不同的异常类型定义多个 catch块。C++ 会从上到下检查每个catch块,并匹配相应的异常类型进行处理。

  #include <iostream>
#include <format>
#include <stdexcept> 

int divide(int a, int b) {
	if (b == 0) throw std::runtime_error("Division by zero"); 
	if (a < 0 || b < 0) throw std::invalid_argument("Negative values not allowed");	
	return a / b;
}

int main() {
	try {
		int result = divide(-10, 2);
		std::cout << std::format("Result: {}\n", result);
	}
	catch (const std::runtime_error& e) {
		std::cerr << std::format("Error: {}\n", e.what()); 
	}
	catch (const std::invalid_argument& e) {
		std::cerr << std::format("Invalid argument: {}\n", e.what());
	}

	return 0;
}
  
  🡮
Invalid argument: Negative values not allowed
  
  • 捕获所有异常

可以使用catch(...)捕获所有异常。

  #include <iostream>
#include <stdexcept> 


int main() {
	try {
		throw std::runtime_error("Any exception"); ;
	}
	catch (...) {
		std::cerr << "An unexpected error occurred.\n";
	}

	return 0;
}
  
  🡮
An unexpected error occurred.
  
  • 自定义异常类

自定义异常类通常继承自std::exception,并重载what()方法提供错误信息。

  #include <iostream>
#include <format>
#include <exception>

class MyException : public std::exception {
public:
	const char* what() const noexcept override {
		return "My custom exception";
	}
};


int main() {
	try {
		throw MyException();
	}
	catch (const MyException& e) {
		std::cerr << std::format("Caught exception: {}\n",e.what());
	}

	return 0;
}
  
  🡮
Caught exception: My custom exception
  
  • noexcept关键字

noexcept用于声明一个函数不会抛出异常。一方面通过明确标记可以防止无意抛出异常,并提醒调用者该函数不会发生异常,使得代码更具可预测性;同时,标准库中的某些容器可以利用noexcept的信息在内存重新分配时避免不必要的拷贝等操作,从而使得编译器可以对其进行更好的优化。

  #include <iostream>
#include <format>
#include <exception>

void safeFunction() noexcept {
	
}

void riskyFunction() {
	throw std::runtime_error("Something went wrong");
}

int main() {
	try {
		std::cout << std::format("safeFunction is noexcept: {}\n", noexcept(safeFunction()));
		std::cout << std::format("riskyFunction is noexcept: {}\n", noexcept(riskyFunction()));
		safeFunction();		
	}
	catch (...) {
		std::cout << "Exception caught\n";
	}

	return 0;
}
  
  🡮
safeFunction is noexcept: true
riskyFunction is noexcept: false
  

C# 使用trycatchfinallythrow等关键字进行异常处理。其中try包括可能触发异常的代码;catch捕获并处理try块内抛出的异常;无论是否抛出异常,finally为在trycatch之后要执行的代码;throw用于引发异常,要么是新的异常,要么是重新抛出原来的异常。

  • 基本的异常处理

C# 提供了丰富的内置异常类,常用的包括:

  • Exception:所有异常的基类。
  • ArgumentNullException:传递给方法的参数为null
  • InvalidOperationException:对象当前无效。
  • NullReferenceException:尝试访问空引用时触发。
  • IndexOutOfRangeException:索引超出数组或集合的范围。
  • FormatException: 格式错误,例如无法将字符串解析为数值。
  using System;

class Program
{
    static int Divide(int a, int b)
    {
        if (b == 0)
        {
             throw new DivideByZeroException();
        }
        return a / b;
    } 

    static void Main()
    {
        try
        {
            int result = Divide(10, 0);
            Console.WriteLine($"Result: {result}");
        }
        catch(DivideByZeroException ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }finally
        {
            Console.WriteLine("Execution completed");
        }
        
    }
}
  
  🡮
Error: Attempted to divide by zero.
Execution completed
  
  • 捕获多个异常

try-catch结构中可以使用多个catch来捕获多个异常。如果一个异常发生时,C# 会从上到下依次检查,并被第一个匹配的catch块捕获。

  using System;

class Program
{
    static void Main()
    {
        try
        {
            Console.Write("Enter a number: ");
            int x = int.Parse(Console.ReadLine());
            double y = 10 / x;
            Console.WriteLine($"Division successful. Result: {y}");
        }catch(FormatException ex)
        {
            Console.WriteLine($"An error occurred: Invalid number format. {ex.Message}");
        }catch(DivideByZeroException ex)
        {
            Console.WriteLine($"An error occured: Division by zero is not allowed. {ex.Message}");
        }
    }
}
  
  🡮
Enter a number: five
An error occurred: Invalid number format. The input string 'five' was not in a correct format.

Enter a number: 0
An error occured: Division by zero is not allowed. Attempted to divide by zero.

Enter a number: 5
Division successful. Result: 2
  

int.Parse() 是一个用于将数字的字符串表示形式转换为整数的方法。

  • throw关键字

throw用于显示抛出异常。在catch块中,可以使用throw重新抛出异常,以便在上层处理。

  using System;

class Program
{
    static void ValiddateAge(int age)
    {
        if (age < 18)
        {
            throw new ArgumentException("Age must be 18 or oder.");
        }
    }
    static void Main()
    {
        try
        {
            ValiddateAge(10);
        }catch (ArgumentException ex)
        {
            Console.WriteLine($"Caught exception: {ex.Message}");
            throw; // 重新抛出异常
        }
    }
}
  
  🡮
Caught exception: Age must be 18 or oder.
  
  • 自定义异常类

可以通过继承系统内置的Exception,并定义不同的构造函数来创建自定义异常。自定义异常可以帮助更具体地描述代码中出现的错误,并便于捕获和处理特定类型的异常。

  using System;

public class InvalidAgeException : Exception
{
    // 默认构造函数
    public InvalidAgeException(): base("Invalid age provided.")
    {

    }

    // 接受自定义消息的构造函数
    public InvalidAgeException(string message) : base(message)
    {

    }

    // 接受自定义消息和内部异常的构造函数
    public InvalidAgeException(string message, Exception innerException) : base(message, innerException)
    {

    }
}

public class Person
{
    public int Age
    {
        get;
        set;
    }

    public void SetAge(int age)
    {
        if (age<0 || age > 150)
        {
            throw new InvalidAgeException("Age must between 0 and 150.");
        }
        Age = age;
    }
}


class Program
{
    static void Main()
    {
        var person = new Person();

        try
        {
            person.SetAge(300);
        }catch(InvalidAgeException ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}
  
  🡮
Error: Age must between 0 and 150.
  

base 关键字用于访问基类的成员(如方法、属性、构造函数等),通常在派生类(子类)中使用,以引用和调用基类的功能。

上述示例中使用了ExceptioninnerException属性,用于保存导致当前异常的原始异常,特别适用于当一个异常由另一个异常触发时的情景。当捕获到一个异常,但将其包装成一个新的、更具描述性或有意义的异常重新抛出,其原始异常作为innerException传递,保留了异常路径,可以错误/异常跟踪。

  using System;

class Program
{
    static void Main()
    {
        try
        {
            try
            {
                throw new FileNotFoundException("File not found.");
            }
            catch (Exception ex)
            {
                throw new Exception("Failed to process file.", ex);
            }
        }catch (Exception ex)
        {
            Console.WriteLine("Exception: " + ex.Message);

            if (ex.InnerException != null)
            {
                Console.WriteLine("Inner Exception: " + ex.InnerException.Message);
            }
        }
    }
}
  
  🡮
Exception: Failed to process file.
Inner Exception: File not found.
  
  • 异常过滤器when

when关键字允许在捕获异常时指定额外的条件,并仅当条件为真时才会处理异常。

  using System;
using System.IO;

class Program
{
    static void Main()
    {
        try
        {
            File.ReadAllText("importantfile.txt");
        }catch(FileNotFoundException ex) when (Path.GetFileName(ex.FileName) == "importantfile.txt")
        {
            Console.WriteLine("Important file is missing. Please check!");
        }catch(FileNotFoundException ex)
        {
            Console.WriteLine($"File not found: {ex.FileName}");    
        }
    }
}
  
  🡮
Important file is missing. Please check!
  

5.3 Python 的推导式

推导式(Comprehensions)是在 Python 中对序列执行操作,或者通过过滤和转换元素生成新集合/可迭代对象(如列表、集合或字典)的一种方式,可以提高代码的可读性和执行效率。在 C/C++ 和 C# 等语言中,不具有类似 Python 中的推导式,但可以通过循环或支持函数式编程结构的库来实现类似的功能,但也往往缺少了 Python 中推导式语法简洁的特征。因此,推导式是一种表达式而非控制结构。将推导式置于该部分解释是因为推导式包含了隐式的循环和条件判断。

类型 列表推导式 字典推导式 集合推导式 生成器推导式 嵌套推导式

基本语法:[expression for item in iterable]

包含条件if[expression for item in iterable if condition == True]

包含条件if-else[expression1 if condition == True else expression2 for item in iterable]

  squares_lst = [x**2 for x in range(10)]
print(squares_lst)

even_squares_lst = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares_lst)

evenSquares_oddCubic_lst = [x**2 if x % 2 == 0 else x**3 for x in range(10)]
print(evenSquares_oddCubic_lst)
  
  🡮
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
[0, 4, 16, 36, 64]
[0, 1, 4, 27, 16, 125, 36, 343, 64, 729]
  

基本语法:{key_expression: value_expression for item in iterable}

包含条件if{key_expression: value_expression for item in iterable if condition == True}

包含条件if-else{key_expression: (value_expression1 if condition == True else value_expression2) for item in iterable}

  squares_dict = {x + 1: (x + 1) ** 2 for x in range(5)}
print(squares_dict)

even_squares_dict = {x + 1: (x + 1) ** 2 for x in range(10) if x % 2 == 0}
print(even_squares_dict)

evenSquares_oddCubic_dict = {
    x + 1: ((x + 1) ** 2 if x % 2 == 0 else (x + 1) ** 3) for x in range(10)
}
print(evenSquares_oddCubic_dict)
  
  🡮
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
{1: 1, 3: 9, 5: 25, 7: 49, 9: 81}
{1: 1, 2: 8, 3: 9, 4: 64, 5: 25, 6: 216, 7: 49, 8: 512, 9: 81, 10: 1000}
  

集合推导式类似于列表推导式。

基本语法:{expression for item in iterable}

包含条件if{expression for item in iterable if condition == True}

包含条件if-else{expression1 if condition == True else expression2 for item in iterable}

  lst = [0, 1, 2, 2, 3, 3, 4, 5, 6]

squares_set = {x**2 for x in lst}
print(squares_set)

even_squares_set = {x**2 for x in lst if x % 2 == 0}
print(even_squares_set)

evenSquares_oddCubic_set = {x**2 if x % 2 == 0 else x**3 for x in lst}
print(evenSquares_oddCubic_set)
  
  🡮
{0, 1, 4, 36, 9, 16, 25}
{0, 16, 4, 36}
{0, 1, 4, 36, 16, 27, 125}
  

生成器推导式与列表推导式类似,不过返回的是一个生成器对象。这种方式在处理大量数据时更节省内存。

基本语法:(expression for item in iterable)

包含条件if(expression for item in iterable if condition == True)

包含条件if-else(expression1 if condition == True else expression2 for item in iterable)

  squares_gen = (x**2 for x in range(10))
print(squares_gen)

even_squares_gen = (x**2 for x in range(10) if x % 2 == 0)
print(even_squares_gen)

evenSquares_oddCubic_gen = (x**2 if x % 2 == 0 else x**3 for x in range(10))
print(evenSquares_oddCubic_gen)
print(list(evenSquares_oddCubic_gen))
  
  🡮
<generator object <genexpr> at 0x000001FB1B215700>
<generator object <genexpr> at 0x000001FB1B214FB0>
<generator object <genexpr> at 0x000001FB1B214EE0>
[0, 1, 4, 27, 16, 125, 36, 343, 64, 729]
  

推导式不仅可以嵌套for循环,还可以进行多层嵌套,以列表推导式为例。

  # 生成一个二维列表
pairs = [(x, y) for x in range(3) for y in range(2)]
print(pairs)

# 扁平化一个二维列表
nested_lst = [[1, 2], [3, 4], [5, 6]]
flattened = [item for sublist in nested_lst for item in sublist]
print(flattened)
  
  🡮
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
[1, 2, 3, 4, 5, 6]