Python — это еще один язык программирования, но он интерпретируется (запускается сверху вниз интерпретатором, как JavaScript) и имеет более высокий уровень, чем С (включает более мощные функции и библиотеки).
Например, мы можем реализовать всю resize
, написанную нами ранее на языке C, всего за несколько строк с помощью Python:
import sys from PIL import Image if len(sys.argv) != 4: sys.exit("Usage: python resize.py n infile outfile") n = int(sys.argv[1]) infile = sys.argv[2] outfile = sys.argv[3] inimage = Image.open(infile) width, height = inimage.size outimage = inimage.resize((width * n, height * n)) outimage.save(outfile)
- Во-первых, мы импортируем
import
(какinclude
)sys
библиотеку (для аргументов командной строки) иImage
библиотеку. - Мы проверяем , что есть правильное число аргументов командной строки с
len(sys.argv)
, а затем создаем несколько переменныхn
,infile
иoutfile
, без необходимости указывать их тип. - Затем мы используем библиотеку изображений, чтобы открыть входное изображение, получить его ширину и высоту, изменить его размер с помощью функции
resize
и, наконец, сохранить его в выходной файл.
Давайте посмотрим на новый синтаксис. В Python мы можем создавать переменные просто counter = 0
. Чтобы увеличить переменную, мы можем использовать counter = counter + 1
или counter += 1
.
Условия выглядят так:
if x < y: something elif: something else: something
- В отличие от C и JavaScript (при этом для блоков кода используются фигурные скобки
{
}
), точный отступ каждой строки определяет уровень вложенности в Python.
Булевы выражения тоже немного отличаются:
while True:
something
Циклы могут быть созданы с помощью другой функции range
, которая в приведенном ниже примере возвращает диапазон чисел от 0 до 50, но не включая:
for i in range(50):
something
В Python мы начнем с рассмотрения лишь нескольких типов данных:
bool
,True
илиFalse
;float
, вещественные числа;int
целые числа;str
, строки;dict
словарь пар ключ-значение, которые действуют как хеш-таблицы;list
, как массивы, но может автоматически изменять размерrange
диапазон значений;set
, коллекция уникальных вещей;tuple
группа из двух или более вещей.
В Python мы тоже можем включить библиотеку CS50, наш синтаксис будет таким:
from cs50 import get_float, get_int, get_string
Обратите внимание, что мы указываем функции, которые мы хотим использовать.
В Python мы можем запустить нашу программу, не компилируя её (python hello.py
).
python
— это имя программы, которую мы на самом деле запускаем из командной строки, и это интерпретатор, который может читать наш исходный код (написанный на языке Python) и запускать его по одной строке за раз. (Технически, существует компилятор, который превращает наш исходный код в нечто, называемое байт-кодом, которое фактически выполняет интерпретатор, но это абстракция для нас.)
Типы данных в Python
Наша первая hello.py
программа простая:
print("hello, world")
- Обратите внимание, что нам не нужна функция
main
или что-либо, которую нам нужно было импортировать для функцииprint
функции. Функция print в Python также добавляет новую строку для нас автоматически. - Теперь мы можем запустить его с
python hello.py
.
Мы можем получить строки от пользователя:
from cs50 import get_string s = get_string("Name: ") print("hello,", s)
- Мы создаем переменную с именем
s
без указания типа, и мы можем передать несколько переменных в функциюprint
, которая выведет их для нас на одной строке, автоматически разделенных пробелом. - Чтобы избежать лишних пробелов, мы можем поместить переменные внутри строки, подобно тому, как они включены в C:
print(f"hello, {s}")
. Здесь мы говорим, что строкаhello, {s}
является отформатированной строкой с символомf
перед строкой, и поэтому переменнаяs
будет подставлена в строку. И нам не нужно беспокоиться о типе переменной; мы можем просто включить их в строки.
Также мы можем добавить немного математики:
from cs50 import get_int x = get_int("x: ") y = get_int("y: ") print(f"x + y = {x + y}") print(f"x - y = {x - y}") print(f"x * y = {x * y}") print(f"x / y = {x / y}") print(f"x mod y = {x % y}")
- Обратите внимание, что выражения like
{x + y}
будет оцениваться или вычисляться до того, как оно будет подставлено в строку для печати. - Запустив эту программу, мы увидим, что все работает так, как мы могли ожидать, даже разделив два целых числа, чтобы получить значение с плавающей запятой. (Чтобы сохранить прежнее поведение всегда возвращать усеченное целое с делением, есть
//
оператор.)
Мы можем поэкспериментировать со значениями с плавающей точкой:
from cs50 import get_float x = get_float("x: ") y = get_float("y: ") z = x / y print(f"x / y = {z}")
- Когда мы запускаем эту программу, мы видим следующее:
$ python floats.py
x: 1
y: 10
x / y = 0.1
- Мы можем напечатать больше десятичных знаков с синтаксисом, например
print(f"x / y = {z:.50f}")
:
x / y = 0.10000000000000000555111512312578270211815834045410
Оказывается, что Python по-прежнему имеет неточность с плавающей точкой по умолчанию, но есть некоторые библиотеки, которые будут использовать больше памяти для более точного хранения десятичных значений.
Мы можем проверить, имеет ли Python целочисленное переполнение:
from time import sleep
i = 1
while True:
print(i)
i *= 2
sleep(1)
Мы используем функцию sleep
, чтобы приостановить нашу программу на одну секунду, но удваиваем i
снова и снова. И получается, что целые числа в Python могут быть настолько большими, насколько позволяет память, поэтому мы не будем испытывать переполнение в течение гораздо более длительного времени.
Программирование на Python
Давайте внимательнее посмотрим на условия:
from cs50 import get_int # Get x from user x = get_int("x: ") # Get y from user y = get_int("y: ") # Compare x and y 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")
- Обратите внимание, что мы используем последовательный отступ, но нам не нужны скобки или скобки для наших условий.
- Комментарии тоже начинаются с одного
#
символа.
Мы можем сравнивать строки так, как мы могли бы ожидать:
from cs50 import get_char # Prompt user for answer c = get_string("Answer: ") # Check answer if c == "Y" or c == "y": print("yes") elif c == "N" or c == "n": print("no")
- Строки можно сравнивать напрямую, а логические выражения могут включать слова
and
иor
.
Мы можем написать функции в Python следующим образом:
def main(): for i in range(3): cough() def cough(): """Cough once""" print("cough") if __name__ == "__main__": main()
- Мы используем ключевое слово
def
для определения функцииcough
, указывающей, что она не принимает никаких параметров или входных данных, используя just()
, и вызываем ее из нашей функцииmain
. Обратите внимание, что весь код для каждой функции имеет дополнительный отступ, а не заключен в фигурные скобки. - Затем, ниже, мы используем специальную строку
if __name__ == "__main__":
для вызова функцииmain
при запуске нашей программы. Таким образом, интерпретатор узнает о
функцииcough
к тому моменту, когдаmain
действительно вызывается. Мы могли бы также вызватьcough
напрямую, вместоmain
, хотя это было бы нетрадиционно в Python. (Вместо этого мы хотим попытаться быть «питонами» или следовать стилям и шаблонам, поощряемым языком и его сообществом.)
Мы также можем добавить параметры и циклы в функцию cough
:
def main(): cough(3) def cough(n): for i in range(n): print("cough") if __name__ == "__main__": main()
n
переменная, которую можно передать вcough
и которую мы также можно передать вrange
. И обратите внимание, что мы не указываем типы в Python, поэтомуn
может быть любым типом данных (ему даже может быть присвоено значение другого типа).
Мы можем определить функцию, чтобы получить положительное целое число:
from cs50 import get_int def main(): i = get_positive_int("Positive integer: ") print(i) def get_positive_int(prompt): while True: n = get_int(prompt) if n > 0: break return n if __name__ == "__main__": main()
- Поскольку в Python нет цикла do-while, как в C, у нас есть
while
цикл, который будет продолжаться бесконечно, но мы используемbreak
для завершения цикла ifn > 0
. Тогда наша функция будет простоreturn n
. - Обратите внимание, что переменные в Python по умолчанию имеют область действия функции, что означает, что
n
могут быть инициализированы в цикле, но все же будут доступны позже в функции.
Мы можем напечатать каждый символ в строке и сделать их заглавными:
from cs50 import get_string s = get_string() for c in s: print(c.upper(), end="") print()
- Обратите внимание, что мы можем легко перебирать символы в строке чем-то вроде
for c in s
, и мы печатаем версию каждого символа в верхнем регистре с помощьюc.upper()
. Строки в Python — это объекты, такие как структура данных с сохраняемым значением, а также встроенные функции.upper()
, которые мы можем вызвать. - Наконец, мы передаем в функцию
print
еще один аргумент, чтобыend=""
каждый раз печатал новую строку. Python имеет именованные аргументы, где мы можем называть аргументы, которые мы можем передавать, в дополнение к позиционным аргументам, в зависимости от их положения в списке. С именованными аргументами мы можем передавать аргументы в разных порядках и полностью опускать необязательные аргументы. Обратите внимание, что этот пример помеченend
, указывая строку, которой мы хотим завершить каждую напечатанную строку. Передавая пустую строку""
, ничего не будет напечатано после каждого символа. Раньше, когда мы вызывалиprint
безend
аргумента, в качестве функции\n
по умолчанию использовалась функцияend
, которая позволяет автоматически получать новые строки.
Мы можем получить длину строки с помощью len()
функции.
from cs50 import get_string s = get_string("Name: ") print(len(s))
Мы будем использовать 3-ю версию Python, которую мир начинает использовать все больше и больше, поэтому при поиске документации мы хотим быть уверены, что она подходит для правильной версии.
Мы можем взять аргументы командной строки с:
from sys import argv
if len(argv) == 2:
print(f"hello, {argv[1]}")
else:
print("hello, world")
- Мы проверяем количество аргументов, посмотрев на длину
argv
, список аргументов, и, если есть 2, мы печатаем второй. Как и в C, первый аргумент командной строки — это имя программы, которую мы написали, а не словоpython
, которое технически является именем программы, которую мы запускаем в командной строке. - Мы можем напечатать каждый аргумент в списке:
from sys import argv
for s in argv:
print(s)
-
- Это будет перебирать каждый элемент в списке
argv
, что позволяет нам использовать его какs
.
- Это будет перебирать каждый элемент в списке
И мы можем перебирать каждый символ каждого аргумента:
from sys import argv
for s in argv:
for c in s:
print(c)
print()
Мы можем поменять две переменные в Python, просто изменив их порядок:
x = 1
y = 2
print(f"x is {x}, y is {y}")
x, y = y, x
print(f"x is {x}, y is {y}")
- Здесь мы используем ,
x, y = y, x
чтобы установить ,x
чтобыy
в то же время , как установкаy
дляx
.
Мы можем создать список и добавить к нему:
from cs50 import get_int numbers = [] # Prompt for numbers (until EOF) while True: # Prompt for number number = get_int("number: ") # Check for EOF if not number: break # Check whether number is already in list if number not in numbers: # Add number to list numbers.append(number) # Print numbers print() for number in numbers: print(number)
- Здесь мы создаем пустой список с именем
numbers
withnumbers = []
и получаемnumber
от пользователя. Если этогоnumber
еще нет в нашем списке, мы добавляем его в наш список. Мы можем использовать,not in
чтобы проверить, есть ли значение (нет) в списке, иappend
добавить значение в конец списка.
Мы можем создавать собственные структуры данных, объекты:
from cs50 import get_string # Space for students students = [] # Prompt for students' names and dorms for i in range(3): name = get_string("name: ") dorm = get_string("dorm: ") students.append({"name": name, "dorm": dorm}) # Print students' names and dorms for student in students: print(f"{student['name']} is in {student['dorm']}.")
- Мы создаем список с именем
students
, и после того, как мы получим некоторую информацию от пользователя, мы добавляем в этот список словарь пар ключ-значение{"name": name, "dorm": dorm}
. Здесь"name"
и"dorm"
находятся ключи, и мы хотим, чтобы их значения были переменными, которые мы собрали в качестве входных данных. Затем мы можем позже получить доступ к значениям каждого объекта с помощьюstudent['name']
илиstudent['dorm']
и распечатать их. В Python мы можем индексировать в словари словами или строками, а не просто числовыми индексами в списках.
Давайте напечатаем четыре знака вопроса, по одному за раз:
for i in range(4): print("?", end="") print()
Мы также можем напечатать вертикальную полосу хеш-меток:
for i in range(3): print("#")
И мы можем напечатать квадрат с вложенным циклом:
for i in range(3): for j in range(3): print("#", end="") print()
Теперь мы можем вернуться resize.py
, и это может иметь больше смысла для нас сейчас:
from PIL import Image from sys import argv if len(sys.argv) != 4: sys.exit("Usage: python resize.py n infile outfile") n = int(sys.argv[1]) infile = sys.argv[2] outfile = sys.argv[3] inimage = Image.open(infile) width, height = inimage.size outimage = inimage.resize((width * n, height * n)) outimage.save(outfile)
- Мы импортируем библиотеку изображений из чего-то, называемого PIL, бесплатной библиотеки с открытым исходным кодом, которую мы можем загрузить и установить (которая по умолчанию не поставляется с Python).
- Затем мы импортируем
argv
из библиотеки системы, и мы проверяем наши аргументы, сохраняя их в качествеn
,infile
иoutfile
, преобразование входной строки дляn
вint
. - Читая документацию по Python и библиотеке изображений, мы можем открывать файлы в виде изображения, получать его
size
и вызывать для негоresize
функцию, чтобы получить другое изображение, которое мы затем можем передатьsave
в другой файл.
Давайте посмотрим на другой пример, проверку орфографии в Python:
# 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""" file = open(dictionary, "r") for line in file: words.add(line.rstrip("\n")) file.close() 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
- Функции для
dictionary.py
довольно просты, так как все, что нам нужно — этоset()
, коллекция, в которую мы можем загружать уникальные значения. Вload
мы открываемdictionary
файл и добавляем каждую строку в файле как слово (без символа новой строки). - Для
check
мы можем просто вернуть будь тоword
вwords
, а дляsize
мы можем просто вернем длинуwords
. Наконец, нам не нужно ничего делатьunload
, поскольку Python управляет памятью за нас.
Используя сначала C, мы получили понимание алгоритма и реализуем его в абстракции, которые предоставляет нам язык более высокого уровня, такой как Python. Действительно, если мы запустим некоторые тесты на производительность, реализация speller в Python может быть в 1,5 раза медленнее, и поэтому в зависимости от приложения, это может быть или не быть достаточно важным, чтобы оправдать человеческое время, которое может потребоваться для написания программы в язык более низкого уровня, такой как C, который может работать намного быстрее или требовать меньше памяти.
Примеры реализации заданий см. в статье Практические задания шестой недели курса CS50.
Читайте больше по теме: