Введение
В этом разделе мы более тщательно рассмотрим практику написания сценариев на Python.
This tutorial is from open-source community. Access the source code
💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал
В этом разделе мы более тщательно рассмотрим практику написания сценариев на Python.
Сценарий - это программа, которая выполняет一系列语句 и завершается.
## program.py
statement1
statement2
statement3
...
До сих пор мы в основном писали сценарии.
Если вы напишете полезный сценарий, он будет расти по функциям и функциональности. Возможно, вы захотите применить его к другим связанным задачам. Со временем он может стать критическим приложением. И если вы не будете следить, он может превратиться в огромную запутанную массу. Поэтому давайте будем организованы.
Имена должны всегда быть определены, прежде чем их использовать впоследствии.
def square(x):
return x*x
a = 42
b = a + 2 ## Требует, чтобы `a` было определено
z = square(b) ## Требует, чтобы `square` и `b` были определены
Порядок важен. Вы几乎总是把变量和函数的定义放在接近顶部的位置。
Хорошей идеей является размещение всего кода, связанного с одной задачей, в одном месте. Используйте функцию.
def read_prices(filename):
prices = {}
with open(filename) as f:
f_csv = csv.reader(f)
for row in f_csv:
prices[row[0]] = float(row[1])
return prices
Функция также упрощает повторяющиеся операции.
oldprices = read_prices('oldprices.csv')
newprices = read_prices('newprices.csv')
Функция - это именованная последовательность инструкций.
def funcname(args):
statement
statement
...
return result
Любая инструкция Python может использоваться внутри.
def foo():
import math
print(math.sqrt(2))
help(math)
В Python нет особенных инструкций (что делает ее легкой для запоминания).
Функции могут быть определены в любом порядке.
def foo(x):
bar(x)
def bar(x):
statements
## ИЛИ
def bar(x):
statements
def foo(x):
bar(x)
Функции должны быть определены только перед тем, как они будут использованы (или вызваны) во время выполнения программы.
foo(3) ## foo должен быть уже определен
С точки зрения стиля, более распространено определять функции в низу-вверх порядке.
Функции рассматриваются как строительные блоки. Маленькие/простые блоки идут первыми.
## myprogram.py
def foo(x):
...
def bar(x):
...
foo(x) ## Определено выше
...
def spam(x):
...
bar(x) ## Определено выше
...
spam(42) ## Код, использующий функции, появляется в конце
Позже определяемые функции основываются на более ранних. Опять же, это лишь вопрос стиля. Единственное, что имеет значение в вышеприведенной программе, - это то, что вызов spam(42)
должен быть последним.
По идее функции должны быть чёрным ящиком. Они должны действовать только на переданные входные данные и избегать глобальных переменных и неожиданных побочных эффектов. Ваши основные цели: модульность и предсказуемость.
Хорошей практикой является включение документации в виде doc-строки. Doc-строки - это строки, записанные сразу после имени функции. Они используются для help()
, IDE и других инструментов.
def read_prices(filename):
'''
Read prices from a CSV file of name,price data
'''
prices = {}
with open(filename) as f:
f_csv = csv.reader(f)
for row in f_csv:
prices[row[0]] = float(row[1])
return prices
Хорошей практикой при написании doc-строк является написание короткого однострочного резюме того, что делает функция. Если требуется больше информации, включите короткий пример использования, а также более подробное описание аргументов.
Вы также можете добавить необязательные подсказки типов к определениям функций.
def read_prices(filename: str) -> dict:
'''
Read prices from a CSV file of name,price data
'''
prices = {}
with open(filename) as f:
f_csv = csv.reader(f)
for row in f_csv:
prices[row[0]] = float(row[1])
return prices
Подсказки не влияют на работу программы. Они являются чисто информативными. Однако ими могут пользоваться IDE, программы проверки кода и другие инструменты для более глубокого анализа.
В разделе 2 вы написали программу report.py
, которая выводила отчет о производительности портфеля акций. Эта программа состояла из нескольких функций. Например:
## report.py
import csv
def read_portfolio(filename):
'''
Read a stock portfolio file into a list of dictionaries with keys
name, shares, and price.
'''
portfolio = []
with open(filename) as f:
rows = csv.reader(f)
headers = next(rows)
for row in rows:
record = dict(zip(headers, row))
stock = {
'name' : record['name'],
'shares' : int(record['shares']),
'price' : float(record['price'])
}
portfolio.append(stock)
return portfolio
...
Однако в программе также были участки, которые выполняли серию заранее заданных вычислений. Этот код располагался в конце программы. Например:
...
## Output the report
headers = ('Name', 'Shares', 'Price', 'Change')
print('%10s %10s %10s %10s' % headers)
print(('-' * 10 +'') * len(headers))
for row in report:
print('%10s %10d %10.2f %10.2f' % row)
...
В этом упражнении мы собираемся взять эту программу и организовать ее более четко вокруг использования функций.
Измените программу report.py
так, чтобы все основные операции, включая вычисления и вывод, выполнялись с использованием коллекции функций. Specifically:
print_report(report)
, которая выводит отчет.Возьмите последнюю часть вашей программы и упакуйте ее в отдельную функцию portfolio_report(portfolio_filename, prices_filename)
. Сделайте так, чтобы вызов этой функции создавал отчет как и раньше:
portfolio_report('/home/labex/project/portfolio.csv', '/home/labex/project/prices.csv')
В этой окончательной версии ваша программа будет состоять только из серии определений функций, за которыми следует единственный вызов функции portfolio_report()
в конце (который выполняет все шаги, связанные с программой).
Преобразовав вашу программу в отдельную функцию, становится легко запускать ее с разными входными данными. Например, попробуйте эти инструкции интерактивно после запуска вашей программы:
>>> portfolio_report('/home/labex/project/portfolio2.csv', '/home/labex/project/prices.csv')
... look at the output...
>>> files = ['/home/labex/project/portfolio.csv', '/home/labex/project/portfolio2.csv']
>>> for name in files:
print(f'{name:-^43s}')
portfolio_report(name, '/home/labex/project/prices.csv')
print()
... look at the output...
>>>
В Python очень легко писать относительно неструктурированный сценарийный код, где у вас просто есть файл с последовательностью инструкций. В целом, почти всегда лучше использовать функции, когда это возможно. В какой-то момент этот сценарий будет расти, и вы пожелаете, чтобы было немного больше организации. Кроме того, малоизвестный факт заключается в том, что Python работает немного быстрее, если вы используете функции.
Поздравляем! Вы завершили лабораторную работу по сценариям. Вы можете практиковаться в более лабораторных работах в LabEx, чтобы улучшить свои навыки.