接前面的文章:

Python基础入门教学

  • 2 Python的基础知识
    • 2.15 文件和异常
      • 2.15.4 存储数据
        • 2.15.4.1 使用json.dump()和json.load()
        • 2.15.4.2 保存和读取用户生成的数据
        • 2.15.4.3 重构
    • 2.16 测试代码
      • 2.16.1 测试函数
        • 2.16.1.1 单元测试和测试用例
        • 2.16.1.2 可通过的测试
        • 2.16.1.3 不能通过的测试
        • 2.16.1.4 测试未通过时怎么办
        • 2.16.1.5 添加新测试

2 Python的基础知识

2.15 文件和异常

2.15.4 存储数据

很多程序都要求用户输入某种信息,如让用户存储游戏首选项或提供要可视化的数据。不管专注的是什么,程序都把用户提供的信息存储在列表和字典等数据结构中。用户关闭程序时,我们几乎总是要保存他们提供的信息;一种简单的方式是使用模块json来存储数据。
模块json让我们能够将简单的Python数据结构转储到文件中,并在程序再次运行时加载该文件中的数据。我们还可以使用json在Python程序之间分享数据。更重要的是,JSON数据格式并非Python专用的,这让我们能够将以JSON格式存储的数据与使用其他编程语言的人分享。这是一种轻便格式,很有用,也易于学习。

  • 注意:JSON(JavaScript Object Notation)格式最初是为JavaScript开发的,但随后成了一种常见格式,被包括Python在内的众多语言采用。

2.15.4.1 使用json.dump()和json.load()

我们来编写一个存储一组数字的简短程序,再编写一个将这些数字读取到内存中的程序。第一个程序将使用json.dump()来存储这组数字,而第二个程序将使用json.load()。
函数json.dump()接受两个实参:要存储的数据以及可用于存储数据的文件对象。下面演示了如何使用json.dump()来存储数字列表:
number_writer.py

import json
numbers = [2, 3, 5, 7, 11, 13]
filename = 'number.json' ❶
with open(filename, 'w') as f_obj: ❶json.dump(numbers,f_obj)❸

我们先导入模块json,再创建一个数字列表。在❶处,我们指定了要将该数字列表存储到其中的文件的名称。通常使用文件扩展名.json来指出文件存储的数据为JSON格式。接下来,我们以写入模式打开这个文件,让json能够将数据写入其中(见❷)。在❸处,我们使用函数json.dump()将数字列表存储到文件numbers.json中。
这个程序没有输出,但我们可以打开文件numbers.json,看看其内容。数据的存储格式与Python中一样:

[2, 3, 5, 7, 11, 13]

下面再编写一个程序,使用json.load()将这个列表读取到内存中:
number_reader.py

import json
filename = 'number.json' ❶
with open(filename) as f_obj: ❷numbers = json.load(f_obj) ❸
print(numbers)

在❶处,我们确保读取的是前面写入的文件。这次我们以读取方式打开这个文件,因为Python只需读取这个文件(见❷)。在❸处,我们使用函数json.load()加载存储在numbers.json中的信息,并将其存储到变量numbers中。最后,我们打印恢复的数字列表,看看它是否与number_writer.py中创建的数字列表相同:

[2, 3, 5, 7, 11, 13]

这是一种在程序之间共享数据的简单方式。

2.15.4.2 保存和读取用户生成的数据

对于用户生成的数据,使用json保存它们大有裨益,因为如果不以某种方式进行存储,等程序停止运行时用户的信息将丢失。下面来看一个这样的例子:用户首次运行程序时被提示输入自己的名字,这样再次运行程序时就记住他了。
我们先来存储用户的名字:
remember_me.py

import json
username = input("Whit is your name? ") ❶
filename = 'username.json'
with open(filename, 'w') as f_obj:json.dump(username, f_obj) ❷print("We'll remember you when you come back, "+username+"!") ❸

在❶处,我们提示输入用户名,并将其存储在一个变量中。接下来,我们调用json.dump(),并将用户名和一个文件对象传递给它,从而将用户名存储到文件中(见❷)。然后,我们打印一条消息,指出我们存储了他输入的信息(见❸):

Whit is your name? shirley
We'll remember you when you come back, shirley!

现在再编写一个程序,向其名字被存储的用户发出问候:
greet_user.py

import json
filename = 'username.json'
with open(filename) as f_obj:username = json.load(f_obj) ❶print("Welcome back,"+username+"!") ❷

在❶处,我们使用json.load()将存储在username.json中的信息读取到变量username中。恢复用户名后,我们就可以欢迎用户回来了(见❷):

Welcome back,shirley!

我们需要将这两个程序合并到一个程序(remember_me.py)中。这个程序运行时,我们将尝试从文件username.json中获取用户名,因此我们首先编写一个尝试恢复用户名的try代码块。如果这个文件不存在,我们就在except代码块中提示用户输入用户名,并将其存储在username.json中,以便程序再次运行时能够获取它:
remember_me.py

import json
# 如果以前存储了用户名,就加载它
# 否则,就提示用户输入用户名并存储它
filename = 'username.json'
try:with open(filename) as f_obj: ❶username = json.load(f_obj) ❷
except FileNotFoundError: ❸username = input("Whit is your name? ") ❹with open(filename, 'w') as f_obj: ❺json.dump(username, f_obj)print("We'll remember you when you come back, "+username+"!")
else:print("Welcome back,"+username+"!")

这里没有任何新代码,只是将前两个示例的代码合并到了一个程序中。在❶处,我们尝试打开文件username.json。如果这个文件存在,就将其中的用户名读取到内存中(见❷),再执行else代码块,即打印一条欢迎用户回来的消息。用户首次运行这个程序时,文件username.json不存在,将引发FileNotFoundError异常(见❸),因此Python将执行except代码块:提示用户输入其用户名(见❹),再使用json.dump()存储该用户名,并打印一句问候语(见❺)。
无论执行的是except代码块还是else代码块,都将显示用户名和合适的问候语。如果这个程序是首次运行,输出将如下:

Whit is your name? shirley
We'll remember you when you come back, shirley!

否则,输出将如下:

Welcome back,shirley!

这是程序之前至少运行了一次时的输出。

2.15.4.3 重构

我们经常会遇到这样的情况:代码能够正确地运行,但可做进一步的改进——将代码划分为一系列完成具体工作的函数。这样的过程被称为重构。重构让代码更清晰、更易于理解、更容易扩展。
要重构remember_me.py,可将其大部分逻辑放到一个或多个函数中。remember_me.py的重点是问候用户,因此我们将其所有代码都放到一个名为greet_user()的函数中:
remember_me.py

import json
def greet_user():"""问候用户,并指出其名字""" ❶filename = 'username.json'try:with open(filename) as f_obj:username = json.load(f_obj)except FileNotFoundError:username = input("Whit is your name? ")with open(filename, 'w') as f_obj:json.dump(username, f_obj)print("We'll remember you when you come back, "+username+"!")else:print("Welcome back,"+username+"!")
greet_user()

考虑到现在使用了一个函数,我们删除了注释,转而使用一个文档字符串来指出程序是做什么的(见❶)。这个程序更清晰些,但函数greet_user()所做的不仅仅是问候用户,还在存储了用户名时获取它,而在没有存储用户名时提示用户输入一个。
下面来重构greet_user(),让它不执行这么多任务。为此,我们首先将获取存储的用户名的代码移到另一个函数中:

import json
def get_stored_username():"""如果存储了用户名,就获取它""" ❶filename = 'username.json'try:with open(filename) as f_obj:username = json.load(f_obj)except FileNotFoundError:return None ❷else:return username
def greet_user():"""问候用户,并指出其名字"""username = get_stored_username()if username: ❸print("Welcome back," + username + "!")else:username = input("Whit is your name? ")filename = 'username.json'with open(filename, 'w') as f_obj:json.dump(username, f_obj)print("We'll remember you when you come back, "+username+"!")
greet_user()

新增的函数get_stored_username()目标明确,❶处的文档字符串指出了这一点。如果存储了用户名,这个函数就获取并返回它;如果文件username.json不存在,这个函数就返回None(见❷)。这是一种不错的做法:函数要么返回预期的值,要么返回None;这让我们能够使用函数的返回值做简单测试。在❸处,如果成功地获取了用户名,就打印一条欢迎用户回来的消息,否则就提示用户输入用户名。
我们还需将greet_user()中的另一个代码块提取出来:将没有存储用户名时提示用户输入的代码放在一个独立的函数中:

import json
def get_stored_username():"""如果存储了用户名,就获取它"""filename = 'username.json'try:with open(filename) as f_obj:username = json.load(f_obj)except FileNotFoundError:return Noneelse:return username
def get_new_username():"""提示用户输入用户名"""username = input("What is your name? ")filename = 'username.json'with open(filename, 'w') as f_obj:json.dump(username, f_obj)return username
def greet_user():"""问候用户,并指出其名字"""username = get_stored_username()if username:print("Welcome back," + username + "!")else:username = get_new_username()print("We'll remember you when you come back, "+username+"!")
greet_user()

在remember_me.py的这个最终版本中,每个函数都执行单一而清晰的任务。我们调用greet_user(),它打印一条合适的消息:要么欢迎老用户回来,要么问候新用户。为此,它首先调用get_stored_username(),这个函数只负责获取存储的用户名(如果存储了的话),再在必要时调用get_new_username(),这个函数只负责获取并存储新用户的用户名。要编写出清晰而易于维护和扩展的代码,这种划分工作必不可少。

2.16 测试代码

编写函数或类时,还可为其编写测试。通过测试,可确定代码面对各种输入都能够按要求的那样工作。测试让我们信心满满,深信即便有更多的人使用我们的程序,它也能正确地工作。在程序中添加新代码时,我们也可以对其进行测试,确认它们不会破坏程序既有的行为。程序员都会犯错,因此每个程序员都必须经常测试其代码,在用户发现问题前找出它们。

2.16.1 测试函数

要学习测试,得有要测试的代码。下面是一个简单的函数,它接受名和姓并返回整洁的姓名:name_function.py

def get_formatted_name(first, last):"""Generate a neatly formatted full name."""full_name =  first+' '+lastreturn full_name.title()

函数get_formatted_name()将名和姓合并成姓名,在名和姓之间加上一个空格,并将它们的首字母都大写,再返回结果。为核实get_formatted_name()像期望的那样工作,我们来编写一个使用这个函数的程序。程序names.py让用户输入名和姓,并显示整洁的全名:
names.py

from name_function import get_formatted_name
print("Enter 'q' at any time to quit.'")
while True:first = input("\nPlease give me a first name: ")if first == 'q':breaklast = input("Please give me a last name: ")if last == 'q':breakformatted_name = get_formatted_name(first, last)print("\tNeatly formatted name: "+formatted_name+'.')

这个程序从name_function.py中导入get_formatted_name()。用户可输入一系列的名和姓,并看到格式整洁的全名:

Enter 'q' at any time to quit.'Please give me a first name: janis
Please give me a last name: joplinNeatly formatted name: Janis Joplin.Please give me a first name: bob
Please give me a last name: dylanNeatly formatted name: Bob Dylan.Please give me a first name: q

从上述输出可知,合并得到的姓名正确无误。现在假设我们要修改get_formatted_name(),使其还能够处理中间名。这样做时,我们要确保不破坏这个函数处理只有名和姓的姓名的方式。为此,我们可以在每次修改get_formatted_name()后都进行测试:运行程序names.py,并输入像JanisJoplin这样的姓名,但这太烦琐了。所幸Python提供了一种自动测试函数输出的高效方式。倘若我们对get_formatted_name()进行自动测试,就能始终信心满满,确信给这个函数提供我们测试过的姓名时,它都能正确地工作。

2.16.1.1 单元测试和测试用例

Python标准库中的模块unittest提供了代码测试工具。
单元测试用于核实函数的某个方面没有问题;
测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。良好的测试用例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试。
全覆盖式测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。对于大型项目,要实现全覆盖可能很难。通常,最初只要针对代码的重要行为编写测试即可,等项目被广泛使用时再考虑全覆盖。

2.16.1.2 可通过的测试

创建测试用例的语法需要一段时间才能习惯,但测试用例创建后,再添加针对函数的单元测试就很简单了。要为函数编写测试用例,可先导入模块unittest以及要测试的函数,再创建一个继承unittest.TestCase的类,并编写一系列方法对函数行为的不同方面进行测试。
下面是一个只包含一个方法的测试用例,它检查函数get_formatted_name()在给定名和姓时能否正确地工作:
test_name_function.py

import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase): ❶"""测试name_function.py"""def test_first_last_name(self):"""能够正确地处理像Janis Joplin这样地姓名吗?"""formatted_name = get_formatted_name('janis', 'joplin') ❷self.assertEqual(formatted_name,'Janis Joplin') ❸
unittest.main()

首先,我们导入了模块unittest和要测试的函数get_formatted_name()。在❶处,我们创建了一个名为NamesTestCase的类,用于包含一系列针对get_formatted_name()的单元测试。我们可随便给这个类命名,但最好让它看起来与要测试的函数相关,并包含字样Test。这个类必须继承unittest.TestCase类,这样Python才知道如何运行我们编写的测试。
NamesTestCase只包含一个方法,用于测试get_formatted_name()的一个方面。我们将这个方法命名为test_first_last_name(),因为我们要核实的是只有名和姓的姓名能否被正确地格式化。我们运行testname_function.py时,所有以test打头的方法都将自动运行。在这个方法中,我们调用了要测试的函数,并存储了要测试的返回值。在这个示例中,我们使用实参’janis’和’joplin’调用get_formatted_name(),并将结果存储到变量formatted_name中(见❷)。
在❸处,我们使用了unittest类最有用的功能之一:一个断言方法。断言方法用来核实得到的结果是否与期望的结果一致。在这里,我们知道get_formatted_name()应返回这样的姓名,即名和姓的首字母为大写,且它们之间有一个空格,因此我们期望formatted_name的值为Janis Joplin。为检查是否确实如此,我们调用unittest的方法assertEqual(),并向它传递formatted_name和’Janis Joplin’。代码行self.assertEqual(formatted_name, ‘Janis Joplin’)的意思是说:“将formatted_name的值同字符串’Janis Joplin’进行比较,如果它们相等,就万事大吉,如果它们不相等,跟我说一声!”
代码行unittest.main()让Python运行这个文件中的测试。运行test_name_function.py时,得到的输出如下:

.
----------------------------------------------------------------------
Ran 1 tests in 0.000sOK

第1行的句点表明有一个测试通过了。接下来的一行指出Python运行了一个测试,消耗的时间不到0.001秒。最后的OK表明该测试用例中的所有单元测试都通过了。上述输出表明,给定包含名和姓的姓名时,函数get_formatted_name()总是能正确地处理。修改get_formatted_name()后,可再次运行这个测试用例。如果它通过了,我们就知道在给定Janis Joplin这样的姓名时,这个函数依然能够正确地处理。

2.16.1.3 不能通过的测试

测试未通过时结果是什么样的呢?我们来修改get_formatted_name(),使其能够处理中间名,但这样做时,故意让这个函数无法正确地处理像Janis Joplin这样只有名和姓的姓名。
下面是函数get_formatted_name()的新版本,它要求通过一个实参指定中间名:

def get_formatted_name(first, middle, last):"""生成整洁地姓名"""full_name = first+' '+middle+' '+lastreturn full_name.title()

这个版本应该能够正确地处理包含中间名的姓名,但对其进行测试时,我们发现它再也不能正确地处理只有名和姓的姓名。这次运行程序test_name_function.py时,输出如下:

E ❶
======================================================================
ERROR: test_first last_name(_main_.NamesTestCase)  ❷
Traceback (most recent call last):  ❸File"test_name_function.py",line 8,in test_first_last_nameformatted name = get_formatted_name('janis','joplin')
TypeError: get_formatted_name() missing 1 required positional argumen
t:'last"
----------------------------------------------------------------------
Ran 1 test in 0. 000s ❹
FAILED(errors=1) ❺

其中包含的信息很多,因为测试未通过时,需要让我们知道的事情可能有很多。第1行输出只有一个字母E(见❶),它指出测试用例中有一个单元测试导致了错误。接下来,我们看到NamesTestCase中的test_first_last_name()导致了错误(见❷)。测试用例包含众多单元测试时,知道哪个测试未通过至关重要。在❸处,我们看到了一个标准的traceback,它指出函数调用get_formatted_name(‘janis’,‘joplin’)有问题,因为它缺少一个必不可少的位置实参。
我们还看到运行了一个单元测试(见❹)。最后,还看到了一条消息,它指出整个测试用例都未通过,因为运行该测试用例时发生了一个错误(见❺)。这条消息位于输出末尾,让我们一眼就能看到——我们可不希望为获悉有多少测试未通过而翻阅长长的输出。

2.16.1.4 测试未通过时怎么办

测试未通过时怎么办呢?如果我们检查的条件没错,测试通过了意味着函数的行为是对的,而测试未通过意味着我们编写的新代码有错。因此,测试未通过时,不要修改测试,而应修复导致测试不能通过的代码:检查刚对函数所做的修改,找出导致函数行为不符合预期的修改。
在这个示例中,get_formatted_name()以前只需要两个实参——名和姓,但现在它要求提供名、中间名和姓。新增的中间名参数是必不可少的,这导致get_formatted_name()的行为不符合预期。就这里而言,最佳的选择是让中间名变为可选的。这样做后,使用类似于Janis Joplin的姓名进行测试时,测试就会通过了,同时这个函数还能接受中间名。下面来修改get_formatted_name(),将中间名设置为可选的,然后再次运行这个测试用例。如果通过了,我们接着确认这个函数能够妥善地处理中间名。
要将中间名设置为可选的,可在函数定义中将形参middle移到形参列表末尾,并将其默认值指定为一个空字符串。我们还要添加一个if测试,以便根据是否提供了中间名相应地创建姓名:

def get_formatted_name(first, last, middle=''):"""生成整洁地姓名"""if middle:full_name = first+' '+middle+' '+lastelse:full_name = first+' '+lastreturn full_name.title()

在get_formatted_name()的这个新版本中,中间名是可选的。如果向这个函数传递了中间名(if middle:),姓名将包含名、中间名和姓,否则姓名将只包含名和姓。现在,对于两种不同的姓名,这个函数都应该能够正确地处理。为确定这个函数依然能够正确地处理像Janis Joplin这样的姓名,我们再次运行test_name_function.py:

.
----------------------------------------------------------------------
Ran 1 tests in 0.000sOK

现在,测试用例通过了。太好了,这意味着这个函数又能正确地处理像JanisJoplin这样的姓名了,而且我们无需手工测试这个函数。这个函数很容易就修复了,因为未通过的测试让我们得知新代码破坏了函数原来的行为。

2.16.1.5 添加新测试

确定get_formatted_name()又能正确地处理简单的姓名后,我们再编写一个测试,用于测试包含中间名的姓名。为此,我们在NamesTestCase类中再添加一个方法:

import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):"""测试name_function.py"""def test_first_last_name(self):"""能够正确地处理像Janis Joplin这样地姓名吗?"""formatted_name = get_formatted_name('janis', 'joplin')self.assertEqual(formatted_name,'Janis Joplin')def test_first_last_middle_name(self):"""能够正确地处理像Wolfgang Amadeus Mozart这样的姓名吗?"""formatted_name = get_formatted_name( ❶'wolfgang','mozart','amadeus')self.assertEqual(formatted_name,'Wolfgang Amadeus Mozart')
unittest.main()

我们将这个方法命名为test_first_last_middle_name()。方法名必须以test_打头,这样它才会在我们运行test_name_function.py时自动运行。这个方法名清楚地指出了它测试的是get_formatted_name()的哪个行为,这样,如果该测试未通过,我们就会马上知道受影响的是哪种类型的姓名。在TestCase类中使用很长的方法名是可以的;这些方法的名称必须是描述性的,这才能让我们明白测试未通过时的输出;这些方法由Python自动调用,我们根本不用编写调用它们的代码。
为测试函数get_formatted_name(),我们使用名、姓和中间名调用它(见❶),再使用assertEqual()检查返回的姓名是否与预期的姓名(名、中间名和姓)一致。我们再次运行test_name_function.py时,两个测试都通过了:

..
----------------------------------------------------------------------
Ran 2 tests in 0.000sOK

太好了!现在我们知道,这个函数又能正确地处理像Janis Joplin这样的姓名了,我们还深信它也能够正确地处理像Wolfgang Amadeus Mozart这样的姓名。

后续更新:

Python基础入门知识(11)相关推荐

  1. Python基础入门知识(2)

    接前面的文章: Python基础入门知识(1) Python基础入门教学 2 Python的基础知识 2.2 数据类型 2.2.2 数值类型 2.2.2.1 整数 2.2.2.2 浮点数 2.2.2. ...

  2. 超完整 Python基础入门知识教程

    本书旨在帮助Python开发人员发现该语言和相关库的突出特性,并编写简单.流畅.易于阅读和易于维护的代码.特别是生成器.属性描述符(ORM的键)和Python表达式的对象在数据库处理过程中的具体应用: ...

  3. 【学习笔记】Python基础入门知识笔记,万字攻略带你走进Python编程

    ​ Python笔记,由此开始吧 本文是笔者在学习Python过程做的笔记总结,将简要讲述Python的基础知识,内容清晰易理解,相信你也能轻松的学会Python的入门基础知识内容.同时也希望这篇文章 ...

  4. Python基础入门知识实例【基础算法】

    基础知识很简单却非常重要,有兴趣的伙伴可以看我以前的两篇基础文章: Python基础知识汇总https://blog.csdn.net/weixin_41896770/article/details/ ...

  5. Python基础入门知识

    Python 编译环境的安装 首先安装Python的官方编译环境:Python3.7, 点击Add ... to Path . 点击下一步完成安装. 开始-> 运行 - > cmd -&g ...

  6. 学python需要什么基础知识-学习Python需要知道哪些基础入门知识?

    众所周知,Python以优雅.简洁著称,入行门槛低,可以从事Linux运维.Python Web网站工程师.Python自动化测试.数据分析.人工智能等职位!就目前来看,Python就业前景广阔.很多 ...

  7. 全站最全面的Python 基础入门必备知识大全,学完即就业!【建议收藏仔细学习】

    前言: Python作为21世纪最火的编程语言,市面上各种学习视频层出不穷,关于Python的学习氛围也逐渐浓厚!!最近一段时间越来越多的知友们在私信我,希望我出一期python基础入门的内容,肝了N ...

  8. 万字长文爆肝Python基础入门【巨详细,一学就会】

    目录 数据的名字和种类--变量和类型 初探数据种类 数据类型 数值运算 比较运算 变量和赋值 变量的好处 用赋值更新变量 变量和数据类型的关系 总结 数据类型 数值运算 数值比较 变量和赋值 一串数据 ...

  9. Python基础入门笔记(二)

    前言 本文主要为 Python基础入门笔记(一)内容的补充. 一.迭代器和生成器 1.1 Python迭代器 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元 ...

最新文章

  1. 归一化互相关Normalization cross correlation (NCC)
  2. 将socket设置为非阻塞(non-blocking) - 艾子的日志 - 网易博客
  3. #include 和 #include 的区别
  4. ping php支付,thinkphp框架中引出ping++支付server SDK
  5. bootstraptable中responsehandle获取数据缺失_Python中的向量化字符串操作
  6. canvas绘制字体
  7. C++ 泛型编程-类模板
  8. 福布斯发布区块链50强 这5家中国公司上榜
  9. 0603封装继承多态,综合练习
  10. 安装 mariadb全套教程
  11. 图书查找java_java图书信息查询实例
  12. 华为od机考真题-统计射击比赛成绩
  13. 【53期分享】4款毕业答辩PPT模板免费下载
  14. U盘图标更改个性化工具
  15. 转手动档汽车的换挡技巧
  16. 计算机主机usb插口松,usb插口(电脑usb接口松动小妙招)
  17. dedecms去掉栏目广告
  18. aps系统功能模块有哪些?看了本文你就知道了
  19. 2023新年祝福代码[css动画特效]
  20. 矿机主板EBAZ4025当作开发板

热门文章

  1. 一个java游戏有各种天书三国,机号申请的网络游戏,天书九卷,这游戏是免 的,里...
  2. 全球与中国兽医计算机断层扫描 (CT) 扫描仪市场深度研究分析报告
  3. ffmpeg yasm not found, use --disable-yasm for a crippled build
  4. window下使用C++ Bonjour配置服务
  5. 小小的面试二分题目,竟然暗藏玄机?
  6. 工作五年以上的程序员,应该干些什么
  7. 汇编跳转指令: JMP、JECXZ、JA、JB、JG、JL、JE、JZ、JS、JC、JO、JP 等
  8. Android实现手机内存存储功能
  9. C++11 Features in Visual C++ 11 - VS2010对C++11特性支持的情况
  10. 【笔试——腾讯2021实习笔试题第二次2021.4.4】第3题 n人高空过钢索