轨道
/
Python
Python
/
练习
/
Guido 的华丽千层面
Guido 的华丽千层面

Guido 的华丽千层面

学习练习

简介

Python 是一门动态且强类型的编程语言。它借助类型提示,同时使用鸭子类型和渐进类型。

虽然 Python 支持许多不同的编程_风格_,但在内部,Python 里的一切都是对象。这包括数字、字符串、数组,甚至函数。

随着我们在学习轨道上继续前进,我们会进一步了解这些内容的含义。

这第一个练习会介绍 Python 语言的 4 个主要特性:

  1. 名称赋值(变量与常量),
  2. 函数(def关键字和return关键字),
  3. 注释,以及
  4. 文档字符串。

Note

一般来说,Python 学习轨道的内容、测试和分析工具都遵循 PEP 8 和 PEP 257 中列出的 Python 代码风格约定,此外还(强烈)建议不要使用单字母变量名,也不要使用名为 "_" 的变量。

在 Python 学习轨道上,变量一律写成snake_case,常量则写成SCREAMING_SNAKE_CASE。


名称赋值(变量与常量)

程序员可以用赋值运算符=把名称(也叫_变量_)绑定到任意类型的对象上:<name> = <value>。 一个名称在其整个生命周期内可以被重新赋值(或重新绑定)为不同的值(不同的对象类型)。

>>> my_first_variable = 1  #<-- my_first_variable bound to an integer object of value one.
>>> my_first_variable = 2  #<-- my_first_variable re-assigned to integer value 2.

>>> print(type(my_first_variable))
<class 'int'>

>>> print(my_first_variable)
2

>>> my_first_variable = "Now, I'm a string." #<-- You may re-bind a name to a different object type and value.
>>> print(type(my_first_variable))
<class 'str'>

>>> my_first_variable = 'You can call me "str".' #<-- Strings can be declared using single or double quote marks.
>>> print(my_first_variable)
You can call me "str".

常量

常量是指在程序中只应赋值一次的名称。 它们应该定义在模块(文件)层级,通常对程序中的所有函数和类都可见。 使用SCREAMING_SNAKE_CASE表示该名称不应被重新赋值,其值也不应被修改。

函数

def关键字用于开始一个函数定义。 每个函数可以在()括号中带有零个或多个形参,后面跟一个:冒号。 函数_主体_的语句从def的下一行开始,并且必须_缩进成一个块_。

# The body of a function is indented by 2 spaces, & prints the sum of the numbers.
def add_two_numbers(number_one, number_two):
  total = number_one + number_two
  print(total)  

>>> add_two_numbers(3, 4)
7


# Inconsistent indentation in your code blocks will raise an error.
>>> def add_three_numbers_misformatted(number_one, number_two, number_three):
...     result = number_one + number_two + number_three   # This was indented by 4 spaces.
...    print(result)     #this was only indented by 3 spaces
...
...
  File "<stdin>", line 3
    print(result)
    ^
IndentationError: unindent does not match any outer indentation level

函数通过 return 关键字_显式_返回值或对象:

# Function definition on first line, explicit return used on final line.
>>> def add_two_numbers(number_one, number_two):
        return number_one + number_two   


# Calling the function in the Python shell returns the sum of the numbers.
>>> add_two_numbers(3, 4)
7

# Assigning the function call to a variable and printing it 
# will also return the value.
>>> sum_with_return = add_two_numbers(5, 6)
>>> print(sum_with_return)
11

如果return后面没有_显式_表达式,函数会_隐式_返回 None 对象。 None 的细节会在后面的练习中介绍。 就本练习和本说明而言,None是一个占位符,表示什么都没有,也就是 null:


# This function will return `None`
def square_a_number(number):
    square = number * number
    return # <-- note that this return is not followed by an expression

# Calling the function in the Python shell appears 
# to not return anything at all.
>>> square_a_number(2)
>>>


# Using print() with the function call shows that 
# the function is actually returning the **None** object.
>>> print(square_a_number(2))
None

省略return的函数也同样会_隐式_返回 None 对象。 也就是说,如果你在函数中没有使用return,Python 会替你返回None对象。

# This function omits a return keyword altogether.
def add_two_numbers(number_one, number_two):
  result = number_one + number_two

>>> add_two_numbers(5, 7)
>>> print(add_two_numbers(5, 7))
None

# Assigning the function call to a variable and printing 
# the variable will also show None.
>>> sum_without_return = add_two_numbers(5, 6)
>>> print(sum_without_return)
None

调用函数

函数通过名字后面跟()的方式来调用。 点(.)号表示法用于调用定义在类或模块内部的函数。

>>> def raise_to_power(number, power):
...     return number ** power
...

>>> raise_to_power(3,3) # <--Invoking the function with the arguments 3 and 3.
27


# A mismatch between the number of parameters and the number of arguments will raise an error.
>>> raise_to_power(4,)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: raise_to_power() missing 1 required positional argument: 'power'


# Calling methods or functions in classes and modules.
>>> start_text = "my silly sentence for examples."
>>> str.upper(start_text)  # <--Calling the upper() method from the built-in str class on start_text.
'MY SILLY SENTENCE FOR EXAMPLES.'


# Importing the math module
>>> import math

>>> math.pow(2,4)  # <--Calling the pow() function from the math module.
16.0

注释

Python 中的注释以一个不属于字符串的#开头,到行尾结束。 与许多其他编程语言不同,Python 不支持多行注释标记。 注释块中的每一行都必须以#字符开头。

文档字符串

函数体的第一条语句可以选择是一个文档字符串,它简要概括函数或对象的用途。 文档字符串使用三引号(""")声明,缩进层级与代码块相同:


# An example from PEP257 of a multi-line docstring
# reformatted to use Google style non-type hinted docstrings.
# Some additional details can be found in the Sphinx documentation:
# https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html#getting-started

def complex(real=0.0, imag=0.0):
    """Form a complex number.

    Keyword Arguments:
        real (float): The real part of the number (default 0.0)
        imag (float): The imaginary part of the number (default 0.0)
        
    """

    if imag == 0.0 and real == 0.0:
        return complex_zero

文档字符串会被 Sphinx 等自动化文档工具读取,也可以通过调用函数、方法或类名上的特殊属性.__doc__来获取。 通用的文档字符串约定见 PEP257,但具体格式会因项目和团队而异。 Exercism 的概念练习尽量对未加类型提示的代码遵循 Google 风格。

文档字符串还可以充当轻量级单元测试,这会在后面的练习中介绍。

# An example on a user-defined function using a Google style docstring. 
>>> def raise_to_power(number, power):
    """Raise a number to an arbitrary power.

    Parameters:
        number (int): The base number.
        power (int): The power to raise the base number to.
    
    Returns:
        int: The number raised to the specified power.
    
    Takes a number and raises it to the specified power, returning the result.

    """

    return number ** power
...

# Calling the .__doc__ attribute of the function and printing the result.
>>> print(raise_to_power.__doc__)
Raise a number to an arbitrary power.

Parameters:
    number (int): The base number.
    power (int): The power to raise the base number to.

Returns:
    int: The number raised to the specified power.

Takes a number and raises it to the specified power, returning the result.

说明

你要写一些代码,帮你用最喜欢的食谱书做出一份美味的千层面。

一共有五个任务,都和做这道菜有关。


Note

我们已经在骨架文件里帮你写好了第一个函数定义,但其余的函数定义需要你自己来写。 你还需要自己定义所有常量。 请仔细阅读骨架文件里的 #TODO 注释行。 完成一个任务后,就把 TODO 注释删掉。


1. 用常量定义预期的烘焙时间(分钟)

定义 EXPECTED_BAKE_TIME常量,它表示千层面需要在烤箱里烘焙多少分钟。 根据你的食谱书,千层面应该在烤箱里烘焙 40 分钟:

>>> print(EXPECTED_BAKE_TIME)
40

2. 计算剩余的烘焙时间(分钟)

补全bake_time_remaining()函数,它接收千层面已经在烤箱里待了多少分钟作为实参,并基于EXPECTED_BAKE_TIME常量返回千层面还需要烘焙多少分钟。

>>> bake_time_remaining(30)
10

3. 计算准备时间(分钟)

定义preparation_time_in_minutes()函数,它接收你想加进千层面里的number_of_layers作为实参,返回制作这些层需要花费多少分钟。 假设每层需要 2 分钟来准备。

>>> def preparation_time_in_minutes(number_of_layers):
        ...
        ...
        
>>> preparation_time_in_minutes(2)
4

4. 计算总共已用时间(准备 + 烘焙)的分钟数

定义elapsed_time_in_minutes()函数,它接收两个形参作为实参:

  • number_of_layers(加进千层面里的层数)
  • elapsed_bake_time(千层面已经在烤箱里烘焙的分钟数)。

这个函数应该返回你在厨房里烹饪的总分钟数,也就是你分层准备的时间加上千层面在烤箱里烘焙的时间。

>>> def elapsed_time_in_minutes(number_of_layers, elapsed_bake_time):
        ...
        ...
        
>>> elapsed_time_in_minutes(3, 20)
26

5. 为食谱补充注释

回头再看一遍这份食谱,用函数文档字符串的形式添加“注释”。

def elapsed_time_in_minutes(number_of_layers, elapsed_bake_time):
    """Calculate the elapsed cooking time.
    
    Parameters:
        number_of_layers (int): The number of layers in the lasagna.
        elapsed_bake_time (int): Time the lasagna has been baking in the oven.
    
    Returns:
        int: The total time elapsed (in minutes) preparing and baking.

    This function takes two integers representing the number of lasagna 
    layers and the time already spent baking the lasagna. It calculates 
    the total elapsed minutes spent cooking (preparing + baking).
    
    """
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Python Exercism

准备好开始 Guido 的华丽千层面 了吗?

注册 Exercism,借助 17 个概念146 个练习 和真人导师指导,学习并掌握 Python,全部免费。