مسیرها
/
Python
Python
/
تمرین‌ها
/
لازانیای باشکوه Guido
لازانیای باشکوه Guido

لازانیای باشکوه Guido

تمرین یادگیری

مقدمه

پایتون یک زبان برنامه‌نویسی با نوع‌دهی پویا و قوی است. این زبان هم از نوع‌دهی اردکی و هم از نوع‌دهی تدریجی از طریق نشانه‌های نوع بهره می‌برد.

پایتون از سبک‌های مختلف برنامه‌نویسی پشتیبانی می‌کند، اما در درون خود هر چیزی در پایتون یک شیء است. این شامل اعداد، رشته‌ها، فهرست‌ها و حتی توابع می‌شود.

با ادامه‌ی مسیر، بیشتر به این می‌پردازیم که همه‌ی این‌ها چه معنایی دارند.

این تمرین نخست چهار ویژگی اصلی زبان پایتون را معرفی می‌کند:

  1. تخصیص نام (متغیرها و ثابت‌ها)،
  2. توابع (کلیدواژه‌ی def و کلیدواژه‌ی return)،
  3. کامنت‌ها،
  4. و داکسترینگ‌ها.

Note

به طور کلی، محتوا، آزمون‌ها و ابزارهای تحلیل مسیر پایتون از قراردادهای سبکی که در PEP ۸ و PEP ۲۵۷ برای سبک کد پایتون آمده پیروی می‌کنند، با این پیشنهاد (قوی) که هیچ نام متغیر تک‌حرفی یا متغیری به نام "_" وجود نداشته باشد.

در مسیر پایتون، متغیرها همیشه با 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 استفاده نکنید، پایتون خودش شیء 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

کامنت‌ها

کامنت‌ها در پایتون با یک # که بخشی از یک رشته نیست شروع می‌شوند و در پایان خط خاتمه می‌یابند. برخلاف بسیاری از زبان‌های برنامه‌نویسی دیگر، پایتون از نشانه‌های کامنت چندخطی پشتیبانی نمی‌کند. هر خط از یک بلوک کامنت باید با نویسه‌ی # شروع شود.

داکسترینگ‌ها

نخستین دستور در بدنه‌ی یک تابع می‌تواند به‌صورت اختیاری یک داکسترینگ باشد که هدف تابع یا شیء را به‌طور مختصر خلاصه می‌کند. داکسترینگ‌ها با سه گیومه‌ی دوتایی (""") اعلام می‌شوند و تورفتگی آن‌ها در همان سطح بلوک کد است:


# 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 را تعریف کنید که نشان می‌دهد لازانیا باید چند دقیقه در فر بپزد. طبق کتاب آشپزی‌تان، لازانیا باید ۴۰ دقیقه در فر بماند:

>>> 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 را به عنوان آرگومان می‌گیرد، یعنی تعداد لایه‌هایی که می‌خواهید به لازانیا اضافه کنید، و برمی‌گرداند که ساختن آن‌ها چند دقیقه طول می‌کشد. فرض کنید آماده‌سازی هر لایه ۲ دقیقه طول می‌کشد.

>>> 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 ثبت‌نام کنید تا Python را همراه با 17 مفهوم146 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.