讲座 6

欢迎!

  • 在之前的几周里, 你学习了编程的基本构件.
  • 你学习了使用一种叫做 C 的低级编程语言进行编程.
  • 今天, 我们将使用一种叫做 Python 的高级编程语言进行编程.
  • 当你学习这种新语言时,你会发现你将能够更多地自学新的编程语言。

你好 Python!

  • 几十年来, 人们已经看到先前编程语言中的旧设计决策是如何可以改进的.
  • Python 是一种建立在你在 C 语言中所学知识之上的编程语言.
  • Python 还可以访问大量用户创建的库.
  • 与 C 这种编译型语言不同, Python 是一种解释型语言, 你无需单独编译程序. 相反, 你在Python 解释器中运行你的程序.
  • 在此之前, 代码看起来是这样的:

    // 向世界问好的程序
    
    #include <stdio.h>
    
    int main(void)
    {
        printf("hello, world\n");
    }
    

    注意这个 C 程序比下面的 Python 版本更复杂. 你可以在此处下载此代码.

  • 今天, 你会发现编写和编译代码的过程已经简化了.
  • 例如, 上面的代码在 Python 中将呈现为:

    # 向世界问好的程序
    
    print("hello, world")
    

    注意分号消失了, 也不需要库. 你可以在终端中输入 python hello.py 来运行这个程序. 你可以在此处下载此代码.

  • Python 明显可以用相对简单的方式实现 C 语言中相当复杂的内容.
  • 本周的目标之一是更习惯于不舒适感——不知道如何解决问题或正确、语法上实现一个解决方案: 自己搜索资源来帮助你(同时遵守本课程的学术诚信政策)!

拼写检查器

  • 为了说明这种简洁性, 让我们在终端窗口中输入 'code dictionary.py' 并编写如下代码:

    # Words in dictionary
    words = set()
    
    
    def check(word):
        """Return true if word is in dictionary else false"""
        return word.lower() in words
    
    
    def load(dictionary):
        """Load dictionary into memory, returning true if successful else false"""
        with open(dictionary) as file:
            words.update(file.read().splitlines())
        return True
    
    
    def size():
        """Returns number of words in dictionary if loaded else 0 if not yet loaded"""
        return len(words)
    
    
    def unload():
        """Unloads dictionary from memory, returning true if successful else false"""
        return True
    

    注意上面有四个函数. 在 check 函数中, 如果一个 wordwords 中, 它返回 True. 这比在 C 中实现要容易得多! 类似地, 在 load 函数中, 字典文件被打开. 对于该文件中的每一行, 我们将该行添加到 words 中. 使用 rstrip, 尾部的换行符被从添加的单词中移除. size 简单地返回 wordslen 或长度. unload 只需要返回 True, 因为 Python 自己处理内存管理. 你可以在此处下载此代码.

  • 上面的代码说明了为什么存在高级语言: 为了简化并让你更容易地编写代码.
  • 然而, 速度是一个权衡. 因为 C 允许你, 作为程序员, 对内存管理做出决策, 它可能比 Python 运行得更快——取决于你的代码. 当 C 只运行你的代码行时, 当你调用 Python 的内置函数时, Python 会运行所有附带在底层运行的代码.
  • 你可以在 Python 文档中了解更多关于函数的信息

滤镜

  • 为了进一步说明这种简洁性, 在终端窗口中输入 code blur.py 创建一个新文件并编写如下代码:

    # Blurs an image
    
    from PIL import Image, ImageFilter
    
    # Blur image
    before = Image.open("bridge.bmp")
    after = before.filter(ImageFilter.BoxBlur(1))
    after.save("out.bmp")
    

    注意这个程序从名为 PIL 的库中导入模块 ImageImageFilter. 它接受一个输入文件并创建一个输出文件. 你可以在此处下载此代码.

  • 此外, 你可以创建一个名为 edges.py 的新文件如下:

    # Blurs an image
    
    from PIL import Image, ImageFilter
    
    # Find edges
    before = Image.open("bridge.bmp")
    after = before.filter(ImageFilter.FIND_EDGES)
    after.save("out.bmp")
    

    注意此代码是对你的 blur 代码进行了小的调整, 但产生了截然不同的结果. 你可以在此处下载此代码.

  • Python 允许你抽象化在 C 和其他低级编程语言中会更复杂得多的编程.
  • 使用 Python 的权衡之一是它是一种解释型语言, 而不是编译型语言(正如我们之前在课程中严格定义的那样). 因此, 会有一些(通常非常小的)减速, 这在编译程序中可能不会出现.

函数

  • 在 C 中, 你可能见过如下的函数:

    printf("hello, world\n");
    
  • 在 Python 中, 你将看到如下的函数:

    print("hello, world")
    

库, 模块和包

  • 与 C 一样, CS50 库也可以在 Python 中使用.
  • 以下函数将特别有用:

      get_float
      get_int
      get_string
    
  • 你可以按如下方式导入 cs50 库:

    import cs50
    
  • 你也可以选择只从 CS50 库中导入特定函数, 如下所示:

    from cs50 import get_float, get_int, get_string
    

Strings

  • 在 C 中, 你可能还记得以下代码:

    // get_string and printf with %s
    
    #include <cs50.h>
    #include <stdio.h>
    
    int main(void)
    {
        string answer = get_string("What's your name? ");
        printf("hello, %s\n", answer);
    }
    

    注意这个 C 程序是如何使用 CS50 库来获取用户输入的. 你可以在此处下载此代码.

  • 这段代码在 Python 中转换为:

    # get_string and print, with concatenation
    
    from cs50 import get_string
    
    answer = get_string("What's your name? ")
    print("hello, " + answer)
    

    你可以通过在终端窗口中执行 code hello.py 来编写此代码. 然后, 你可以通过运行 python hello.py 来执行它. 注意 + 号是如何连接 "hello, "answer 的. 你可以在此处下载此代码.

  • 类似地, 这也可以不用连接来完成:

    # get_string and print, without concatenation
    
    from cs50 import get_string
    
    answer = get_string("What's your name? ")
    print("hello,", answer)
    

    注意 print 语句会自动在 helloanswer 之间创建一个空格.

  • 类似地, 你可以实现上述代码如下:

    # get_string and print, with format strings
    
    from cs50 import get_string
    
    answer  = get_string("What's your name? ")
    print(f"hello, {answer}")
    

    注意花括号允许 print 函数插入 answer, 使得 answer 出现在其中. f 是必需的, 以便正确格式化包含 answer. 你可以在此处下载此代码.

位置参数和命名参数

  • 在 C 中, 像 fread, fwriteprintf 这样的函数使用位置参数, 你用逗号分隔提供参数. 作为程序员, 你必须记住哪个参数在哪个位置. 这些被称为位置参数.
  • 在 Python 中, 命名参数允许你提供参数而不考虑位置.
  • 你可以在文档中了解更多关于 print 函数的参数.
  • 访问该文档, 你可能会看到以下内容:

    print(*objects, sep=' ', end='\n', file=None, flush=False)
    

    注意可以向 print 提供各种对象. 默认提供了一个单个空格的分隔符, 当向 print 提供多个对象时会显示. 类似地, 在 print 语句的末尾会提供一个换行符.

变量

  • 变量声明也简化了. 在 C 中, 你可能有 int counter = 0;. 在 Python 中, 同样的代码会变成 counter = 0. 你不需要声明变量的类型.
  • Python 倾向于使用 counter += 1 来递增一, 失去了在 C 中编写 counter++ 的能力.

类型

  • Python 中的数据类型不需要显式声明. 例如, 你看到上面的 answer 是一个字符串, 但我们不需要告诉解释器这是事实: 它自己就知道了.
  • 在 Python 中, 常用的类型包括:

      bool
      float
      int
      str
    

    注意 longdouble 不见了. Python 会处理更大和更小的数字应该使用什么数据类型.

  • Python 中的一些其他数据类型包括:

    range   sequence of numbers
    list    sequence of mutable values
    tuple   sequence of immutable values
    dict    collection of key-value pairs
    set     collection of unique values
    
  • 这些数据类型中的每一种都可以在 C 中实现, 但在 Python 中, 它们可以更简单地实现.

计算器

  • 你可能记得之前在课程中的 calculator.c

    // Addition with int
    
    #include <cs50.h>
    #include <stdio.h>
    
    int main(void)
    {
        // Prompt user for x
        int x = get_int("x: ");
    
        // Prompt user for y
        int y = get_int("y: ");
    
        // Perform addition
        printf("%i\n", x + y);
    }
    

    注意这个简单计算器的 C 实现. 你可以在此处下载此代码.

  • 我们可以像在 C 中那样实现一个简单的计算器. 在终端窗口中输入 code calculator.py 并编写如下代码:

    # Addition with int [using get_int]
    
    from cs50 import get_int
    
    # Prompt user for x
    x = get_int("x: ")
    
    # Prompt user for y
    y = get_int("y: ")
    
    # Perform addition
    print(x + y)
    

    注意 CS50 库是如何被导入的. 然后, 从用户那里收集 xy. 最后, 结果被打印出来. 注意在 C 程序中看到的 main 函数已经完全消失了! 虽然你可以使用 main 函数, 但它不是必需的. 你可以在此处下载此代码.

  • 你可以去掉 CS50 库的辅助功能. 按如下方式修改你的代码:

    # Addition with int [using input]
    
    # Prompt user for x
    x = input("x: ")
    
    # Prompt user for y
    y = input("y: ")
    
    # Perform addition
    print(x + y)
    

    注意执行上面的代码会导致奇怪的程序行为. 为什么会这样呢?

  • 你可能已经猜到了, 解释器将 xy 理解为字符串. 你可以通过使用 int 函数来修复你的代码, 如下所示:

    # Addition with int [using input]
    
    # Prompt user for x
    x = int(input("x: "))
    
    # Prompt user for y
    y = int(input("y: "))
    
    # Perform addition
    print(x + y)
    

    注意 xy 的输入是如何传递给 int 函数的, 该函数将其转换为整数. 如果不将 xy 转换为整数, 字符将被连接起来. 你可以在此处下载此代码.

条件语句

  • 在 C 中, 你可能还记得这样的程序:

    // 条件语句, Boolean expressions, relational operators
    
    #include <cs50.h>
    #include <stdio.h>
    
    int main(void)
    {
        // Prompt user for integers
        int x = get_int("What's x? ");
        int y = get_int("What's y? ");
    
        // Compare integers
        if (x < y)
        {
            printf("x is less than y\n");
        }
        else if (x > y)
        {
            printf("x is greater than y\n");
        }
        else
        {
            printf("x is equal to y\n");
        }
    }
    

    注意条件语句在 C 中是如何工作的. 你可以在此处下载此代码.

  • 在 Python 中, 它将如下所示:

    # 条件语句, Boolean expressions, relational operators
    
    from cs50 import get_int
    
    # Prompt user for integers
    x = get_int("What's x? ")
    y = get_int("What's y? ")
    
    # Compare integers
    if x < y:
        print("x is less than y")
    elif x > y:
        print("x is greater than y")
    else:
        print("x is equal to y")
    

    注意不再有花括号. 而是使用缩进. 其次, 在 if 语句中使用冒号. 此外, elif 取代了 else if. 在 ifelif 语句中也不再需要括号. 你可以在此处下载此代码.

  • 进一步看比较, 考虑以下 C 代码:

    // Logical operators
    
    #include <cs50.h>
    #include <stdio.h>
    
    int main(void)
    {
        // Prompt user to agree
        char c = get_char("Do you agree? ");
    
        // Check whether agreed
        if (c == 'Y' || c == 'y')
        {
            printf("Agreed.\n");
        }
        else
        {
            printf("Not agreed.\n");
        }
    }
    

    注意逻辑运算符在 C 中是如何工作的. 你可以在此处下载此代码.

  • 上述代码可以如下实现:

    # Logical operators
    
    from cs50 import get_string
    
    # Prompt user to agree
    s = get_string("Do you agree? ")
    
    # Check whether agreed
    if s == "Y" or s == "y":
        print("Agreed.")
    else:
        print("Not agreed.")
    

    注意在 C 中使用的两条竖线被 or 取代了. 确实, 人们通常喜欢 Python, 因为它对人类更可读. 另外, 注意 char 在 Python 中不存在. 而是使用 str. 你可以在此处下载此代码.

  • 同样的代码另一种方法可以使用列表如下:

    # Logical operators, using lists
    
    from cs50 import get_string
    
    # Prompt user to agree
    s = get_string("Do you agree? ")
    
    # Check whether agreed
    if s in ["y", "yes"]:
        print("Agreed.")
    else:
        print("Not agreed.")
    

    注意我们如何在 list 中表达多个关键字, 如 yyes. 你可以在此处下载此代码.

面向对象编程

  • 某些类型的值不仅内部可以有属性, 还可以有函数. 在 Python 中, 这些值被称为对象
  • 在 C 中, 我们可以创建一个 struct, 在其中你可以将多个变量关联到一个自定义的数据类型中. 在 Python 中, 我们可以做到这一点, 甚至还可以在自定义数据类型中包含函数. 当一个函数属于一个特定的对象时, 它被称为方法.
  • 例如, Python 中的 str 有内置的方法. 因此, 你可以按如下方式修改你的代码:

    # Logical operators, using lists
    
    # Prompt user to agree
    s = input("Do you agree? ").lower()
    
    # Check whether agreed
    if s in ["y", "yes"]:
        print("Agreed.")
    else:
        print("Not agreed.")
    

    注意我们如何使用 s.lower() 来规范化输入, 使用了 str 的内置 lower 方法. 你可以在此处下载此代码.

  • 类似地, 你可能还记得我们如何在 C 中复制字符串:

    // Capitalizes a copy of a string without memory errors
    
    #include <cs50.h>
    #include <ctype.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(void)
    {
        // Get a string
        char *s = get_string("s: ");
        if (s == NULL)
        {
            return 1;
        }
    
        // Allocate memory for another string
        char *t = malloc(strlen(s) + 1);
        if (t == NULL)
        {
            return 1;
        }
    
        // Copy string into memory
        strcpy(t, s);
    
        // Capitalize copy
        if (strlen(t) > 0)
        {
            t[0] = toupper(t[0]);
        }
    
        // Print strings
        printf("s: %s\n", s);
        printf("t: %s\n", t);
    
        // Free memory
        free(t);
        return 0;
    }
    

    注意代码的行数. 你可以在此处下载此代码.

  • 我们可以在 Python 中实现上述代码如下:

    # Capitalizes a copy of a string
    
    # Get a string
    s = input("s: ")
    
    # Capitalize copy of string
    t = s.capitalize()
    
    # Print strings
    print(f"s: {s}")
    print(f"t: {t}")
    

    注意这个程序比它在 C 中的对应程序短得多. 你可以在此处下载此代码.

  • 在本课程中, 我们只会触及 Python 的表面. 因此, 随着你继续学习, Python 文档将特别重要.
  • 你可以在 Python 文档中了解更多关于字符串方法的信息

循环

  • Python 中的循环与 C 非常相似. 你可能还记得 C 中的以下代码:

    // 演示nstrates for loop
    
    #include <stdio.h>
    
    int main(void)
    {
        for (int i = 0; i < 3; i++)
        {
            printf("meow\n");
        }
    }
    
  • for 循环可以在 Python 中实现如下:

    # Better design
    
    for i in range(3):
        print("meow")
    

    注意 i 从未被显式使用. 然而, Python 会递增 i 的值. 你可以在此处下载此代码.

  • 此外, while 循环可以实现如下:

    # 演示nstrates while loop
    
    i = 0
    while i < 3:
        print("meow")
        i += 1
    

    你可以在此处下载此代码.

  • 为了进一步理解 Python 中的循环和迭代, 让我们创建一个名为 uppercase.py 的新文件如下:

    # Uppercases string one character at a time
    
    before = input("Before: ")
    print("After:  ", end="")
    for c in before:
        print(c.upper(), end="")
    print()
    

    注意 end= 是如何用来向 print 函数传递一个参数的, 该参数使打印继续在同一行而不换行. 此代码逐个字符地处理字符串. 你可以在此处下载此代码.

  • 阅读文档, 我们发现 Python 有可以应用于整个字符串的方法如下:

    # Uppercases string all at once
    
    before = input("Before: ")
    after = before.upper()
    print(f"After:  {after}")
    

    注意 .upper 是如何应用于整个字符串的. 你可以在此处下载此代码.

抽象

  • 正如我们今天早些时候暗示的, 你可以使用函数进一步改进我们的代码, 并将各种代码抽象到函数中. 按如下方式修改你之前创建的 meow.py 代码:

    # 抽象
    
    def main():
        for i in range(3):
            meow()
    
    # Meow once
    def meow():
        print("meow")
    
    
    main()
    

    注意 meow 函数将 print 语句抽象化了. 此外, 注意 main 函数出现在文件的顶部. 在文件的底部, 调用了 main 函数. 按惯例, 你应该在 Python 中创建一个 main 函数. 你可以在此处下载此代码.

  • 确实, 我们可以按如下方式在函数之间传递变量:

    # 抽象 with parameterization
    
    def main():
        meow(3)
    
    
    # Meow some number of times
    def meow(n):
        for i in range(n):
            print("meow")
    
    
    main()
    

    注意 meow 现在接受一个变量 n. 在 main 函数中, 你可以调用 meow 并向其传递一个值, 如 3. 然后, meowfor 循环中使用 n 的值. 你可以在此处下载此代码.

  • 阅读上面的代码, 注意你作为一个 C 程序员, 是如何能够很容易地理解上述代码的. 虽然一些约定不同, 但你之前学习的基本构件在这种新的编程语言中非常明显.

截断和浮点数精度问题

  • 回忆一下在 C 中, 我们经历过截断, 其中一个整数除以另一个整数可能导致不精确的结果.
  • 你可以通过修改 calculator.py 代码来查看 Python 如何处理这样的除法:

    # Division with integers, demonstration lack of truncation
    
    # Prompt user for x
    x = int(input("x: "))
    
    # Prompt user for y
    y = int(input("y: "))
    
    # Divide x by y
    z = x / y
    print(z)
    

    注意执行此代码会得到一个值, 但如果你看到 .333333 之后还有更多数字, 你会发现我们面临浮点数精度问题. 截断不会发生. 你可以在此处下载此代码.

  • 我们可以通过稍微修改代码来揭示这个不精确性:

    # Floating-point imprecision
    
    # Prompt user for x
    x = int(input("x: "))
    
    # Prompt user for y
    y = int(input("y: "))
    
    # Divide x by y
    z = x / y
    print(f"{z:.50f}")
    

    注意此代码揭示了不精确性. Python 仍然面临这个问题, 就像 C 一样. 你可以在此处下载此代码.

异常

  • 让我们探索更多关于运行 Python 代码时可能出现的异常.
  • 按如下方式修改 integer.py:

    # Doesn't handle exception
    
    # Prompt user for an integer
    n = int(input("Input: "))
    print("Integer")
    

    注意输入错误的数据可能导致错误. 你可以在此处下载此代码.

  • 我们可以通过按如下方式修改代码来 try 处理和捕获潜在异常:

    # Handles exception
    
    # Prompt user for an integer
    try:
        n = int(input("Input: "))
        print("Integer.")
    except ValueError:
        print("Not integer.")
    

    注意上面的代码反复尝试获取正确类型的数据, 并在需要时提供额外的提示. 你可以在此处下载此代码.

马里奥

  • 回顾几周前我们像马里奥一样把一个方块堆叠在另一个上面的挑战.

    three vertical blocks

  • 在 Python 中, 我们可以按如下方式实现类似的功能:

    # Prints a column of 3 bricks with a loop
    
    for i in range(3):
        print("#")
    

    这将打印一列三个砖块. 你可以在此处下载此代码.

  • 在 C 中, 我们有 do-while 循环的优势. 然而, 在 Python 中, 习惯使用 while 循环, 因为 Python 没有 do-while 循环. 你可以在名为 mario.py 的文件中编写如下代码:

    # Prints a column of n bricks with a loop
    
    from cs50 import get_int
    
    while True:
        n = get_int("Height: ")
        if n > 0:
            break
    
    for i in range(n):
        print("#")
    

    注意 while 循环是如何用来获取高度的. 一旦输入大于零的高度, 循环就会中断. 你可以在此处下载此代码.

  • 考虑以下图片:

    four horizontal问题 blocks

  • 在 Python 中, 我们可以通过按如下方式修改代码来实现:

    # Prints a row of 4 question marks with a loop
    
    for i in range(4):
        print("?", end="")
    print()
    

    注意你可以覆盖 print 函数的默认行为, 使其与上一个打印保持在同一行. 你可以在此处下载此代码.

  • 与上一次迭代的精神类似, 我们可以进一步简化这个程序:

    # Prints a row of 4 question marks without a loop
    
    print("?" * 4)
    

    注意我们可以利用 * 来乘以打印语句以重复 4 次. 你可以在此处下载此代码.

  • 那么一大块砖墙呢?

    three by three block of mario blocks

  • 要实现上述内容, 你可以按如下方式修改代码:

    # Prints a 3-by-3 grid of bricks with loops
    
    for i in range(3):
        for j in range(3):
            print("#", end="")
        print()
    

    注意一个 for 循环是如何存在于另一个循环内部的. print 语句在每一行砖块结束时添加一个换行符. 你可以在此处下载此代码.

  • 你可以在 Python 文档中了解更多关于 print 函数的信息

列表

  • list 是 Python 中的一种数据结构.
  • list 内部有内置的方法或函数.
  • 例如, 考虑以下代码:

    # Averages three numbers using a list
    
    # Scores
    scores = [72, 73, 33]
    
    # Print average
    average = sum(scores) / len(scores)
    print(f"Average: {average}")
    

    注意你可以使用内置的 sum 方法来计算平均值. 你可以在此处下载此代码.

  • 你甚至可以使用以下语法从用户那里获取值:

    # Averages three numbers using a list and a loop
    
    from cs50 import get_int
    
    # Get scores
    scores = []
    for i in range(3):
        score = get_int("Score: ")
        scores.append(score)
    
    # Print average
    average = sum(scores) / len(scores)
    print(f"Average: {average}")
    

    注意此代码使用了列表的内置 append 方法. 你可以在此处下载此代码.

  • 你可以在 Python 文档中了解更多关于列表的信息
  • 你还可以在 Python 文档中了解更多关于 len 的信息

搜索和字典

  • 我们也可以在一个数据结构中进行搜索.
  • Consider a program called phonebook.py as follows:

    # Implements linear search for names using loop
    
    # 一份 list of names
    names = ["Kelly", "David", "John"]
    
    # Ask for name
    name = input("Name: ")
    
    # Search for name
    for n in names:
        if name == n:
            print("Found")
            break
    else:
        print("Not found")
    

    注意这如何为每个名字实现线性搜索. 你可以在此处下载此代码.

  • 然而, 我们不需要遍历列表. 在 Python 中, 我们可以按如下方式执行线性搜索:

    # Implements linear search for names using `in`
    
    # 一份 list of names
    names = ["Kelly", "David", "John"]
    
    # Ask for name
    name = input("Name: ")
    
    # Search for name
    if name in names:
        print("Found")
    else:
        print("Not found")
    

    注意 in 是如何用来实现线性搜索的. 你可以在此处下载此代码.

  • 不过, 这段代码还可以改进.
  • 回忆一下字典dict对的集合.
  • 你可以按如下方式在 Python 中实现字典:

    # Implements a phone book as a list of dictionaries, without a variable
    
    from cs50 import get_string
    
    people = [
        {"name": "Kelly", "number": "+1-617-495-1000"},
        {"name": "David", "number": "+1-617-495-1000"},
        {"name": "John", "number": "+1-949-468-2750"},
    ]
    
    # Search for name
    name = get_string("Name: ")
    for person in people:
        if person["name"] == name:
            print(f"Found {person['number']}")
            break
    else:
        print("Not found")
    

    注意字典的每个条目既有 name 又有 number. 你可以在此处下载此代码.

  • 更好的是, 严格来说, 我们不需要同时有 namenumber. 我们可以按如下方式简化代码:

    # Implements a phone book using a dictionary
    
    from cs50 import get_string
    
    people = {
        "Kelly": "+1-617-495-1000",
        "David": "+1-617-495-1000",
        "John": "+1-949-468-2750",
    }
    
    # Search for name
    name = get_string("Name: ")
    if name in people:
        print(f"Number: {people[name]}")
    else:
        print("Not found")
    

    注意字典是使用花括号实现的. 然后, if name in people 语句检查 name 是否在 people 字典中. 此外, 注意在 print 语句中, 我们可以使用 name 的值来索引 people 字典. 非常有用! 你可以在此处下载此代码.

  • 类似地, 你也可以实现一个字典列表:

    # Implements a phone book as a list of dictionaries
    
    people = [
        {"name": "Kelly", "number": "+1-617-495-1000"},
        {"name": "David", "number": "+1-617-495-1000"},
        {"name": "John", "number": "+1-949-468-2750"},
    ]
    
    # Search for name
    name = input("Name: ")
    for person in people:
        if person["name"] == name:
            number = person["number"]
            print(f"Found {number}")
            break
    else:
        print("Not found")
    

    注意 people 是如何实现为一个字典列表的, 用逗号分隔. 你可以在此处下载此代码.

  • Python 已经尽力通过其内置搜索来实现常数时间.
  • 你可以在 Python 文档中了解更多关于字典的信息

命令行参数

  • 与 C 一样, 你也可以使用命令行参数. 考虑以下代码:

    # Prints a 命令行参数
    
    from sys import argv
    
    if len(argv) == 2:
        print(f"hello, {argv[1]}")
    else:
        print("hello, world")
    

    注意 argv[1] 使用格式化字符串打印, 由 print 语句中的 f 表示. 你可以在此处下载此代码.

  • 你可以在 Python 文档中了解更多关于 sys 库的信息

退出状态

  • sys 库也有内置方法. 我们可以使用 sys.exit(i) 以特定的退出代码退出程序:

    # Exits with explicit value, importing sys
    
    import sys
    
    if len(sys.argv) != 2:
        print("Missing 命令行参数")
        sys.exit(1)
    
    print(f"hello, {sys.argv[1]}")
    sys.exit(0)
    

    注意点号表示法用于使用 sys 的内置函数. 你可以在此处下载此代码.

CSV 文件

  • Python 也有对 CSV 文件的内置支持.
  • 按如下方式修改你的 phonebook.py 代码:

    import csv
    
    file = open("phonebook.csv", "a")
    
    name = input("Name: ")
    number = input("Number: ")
    
    writer = csv.writer(file)
    writer.writerow([name,number])
    
    file.close()
    

    注意 writerow 为我们添加 CSV 文件中的逗号. 你可以在此处下载此代码.

  • 虽然 file.closefile = open 是 Python 中常用且可用的语法, 但这段代码可以改进如下:

    # Uses `with`
    
    import csv
    
    # Get name and number
    name = input("Name: ")
    number = input("Number: ")
    
    # Open CSV file
    with open("phonebook.csv", "a") as file:
    
        # Print to file
        writer = csv.writer(file)
        writer.writerow([name, number])
    

    注意代码在 with 语句下缩进. 这会在完成后自动关闭文件. 你可以在此处下载此代码.

  • 类似地, 我们可以在 CSV 文件中按如下方式编写字典:

    import csv
    
    name = input("Name: ")
    number = input("Number: ")
    
    with open("phonebook.csv", "a") as file:
    
        writer = csv.DictWriter(file, fieldnames=["name", "number"])
        writer.writerow({"name": name, "number": number})
    

    注意此代码与我们之前的迭代非常相似, 但使用了 csv.DictWriter. 你可以在此处下载此代码.

第三方库

  • Python 的优势之一是它庞大的用户群以及同样大量的第三方库.
  • 你可以在自己的计算机上通过输入 pip install cs50 安装 CS50 库, 前提是你已安装了 Python.
  • 考虑到其他库, David 演示了 cowsayqrcode 的使用.

总结

在这节课中, 你学习了之前课程中的编程基本构件如何在 Python 中实现. 此外, 你了解到 Python 如何实现更简化的代码. 同时, 你也学会了如何使用各种 Python 库. 最终, 你明白了你作为程序员的技能并不局限于单一编程语言. 你已经看到你正在通过这门课程发现一种新的学习方式, 这种方式可以在任何编程语言中为你服务——或许, 在几乎任何学习途径中! 具体来说, 我们讨论了以下内容:

  • Python
  • 变量
  • 条件语句
  • 循环
  • 类型
  • 面向对象编程
  • 截断和浮点数精度问题
  • 异常
  • 字典
  • 命令行参数
  • 第三方库

下次见!