Содержание

Зачем использовать def main ()? Ru Python


  • Ru Python
  • стиль кодирования&nbsppython
  • Зачем использовать def main ()?

Возможный дубликат:
Что делать, if __name__== "__main__" делать?

Я видел несколько примеров кода и учебников, которые используют

def main(): # my code here if __name__ == "__main__": main() 

Но почему? Есть ли какая-то причина не определять ваши функции в верхней части файла, а затем просто писать код под ним? т.е.

def my_function() # my code here def my_function_two() # my code here # some code # call function # print(something) 

Мне просто интересно, есть ли какая-нибудь рифма в основном?

  • Pythonic: диапазон vs перечислять в питоне для цикла
  • Когда следует использовать символы подчеркивания между словами в именах функций Python (в соответствии с руководством по стилю)?
  • Предпочтительно ли использовать «else» в Python, когда это не обязательно?
  • Каков правильный способ разбить вложенные вызовы функций / конструкторов в Python?
  • Должен ли я использовать вилку или потоки?

Без главного контролера код будет выполнен, даже если скрипт был импортирован как модуль.

Все остальные уже ответили на это, но я думаю, что мне еще есть что добавить.

Причины иметь это утверждение if вызывающее main() (в определенном порядке):

  • Другие языки (например, C и Java) имеют функцию main() которая вызывается при выполнении программы. Используя это, if мы можем заставить Python вести себя так, как они, что кажется более знакомым для многих людей.

  • Код будет чище , легче читать и лучше организован. (да, я знаю, что это субъективно)

  • Можно будет import этот код python в виде модуля без неприятных побочных эффектов.

    • Это означает, что можно будет запускать тесты против этого кода.

    • Это означает, что мы можем импортировать этот код в интерактивную оболочку python и тестировать / отлаживать / запускать его.

  • Переменные внутри def main являются локальными , а внешние – глобальными .

    Это может привести к нескольким ошибкам и неожиданному поведению.

Но вам не требуется писать функцию main() и вызывать ее внутри оператора if .

Я сам обычно начинаю писать небольшие скрипты без каких-либо функций. Если сценарий становится достаточно большим, или если я чувствую, что всякий код внутри функции мне пригодится, то я реорганизую код и делаю это. Это также происходит, когда я пишу сценарии bash .

Даже если вы помещаете код внутри основной функции, вам не нужно писать его точно так же. Оптимальным вариантом может быть:

import sys def main(argv): # My code here pass if __name__ == "__main__": main(sys.argv) 

Это означает, что вы можете вызывать main() из других сценариев (или интерактивной оболочки), передавая пользовательские параметры. Это может быть полезно в модульных тестах или при пакетной обработке. Но помните, что в приведенном выше коде потребуется разбор argv, поэтому, возможно, было бы лучше использовать другой вызов, который уже анализирует параметры.

В объектно-ориентированном приложении, которое я написал, код выглядел так:

class MyApplication(something): # My code here if __name__ == "__main__": app = MyApplication() app.run() 

Поэтому не стесняйтесь писать код, который вам больше подходит. 🙂

если содержание foo.py

print __name__ if __name__ == '__main__': print 'XXXX' 

Файл foo.py можно использовать двумя способами.

  • импортировано в другой файл: import foo

В этом случае __name__ является foo , секция кода не выполняется и не печатает XXXX .

  • выполняется непосредственно: python foo.py

Когда он выполняется непосредственно, __name__

совпадает с __main__ и код в этом разделе выполняется и печатает XXXX

Одна из этих функций позволяет записывать различные модульные тесты в одном модуле.

« Что делать, if __name__==“__main__”: do? » Уже был дан ответ.

Наличие функции main() позволяет вам вызывать ее функциональность, если вы import модуль. Основная (не предназначенная для каламбур) польза от этого (ИМХО) заключается в том, что вы можете его протестировать.

Рассмотрим второй скрипт. Если вы импортируете его в другой, будут выполнены инструкции, как на «глобальном уровне».

  • Как получить URL-адрес не-ascii с помощью urlopen Python?
  • Как печатать переменные без пробелов между значениями
  • Как отступать от списка Python?
  • Является ли a, b = b, a + b хорошим питоном?
  • Помещение точек с запятой в конце высказываний. Является ли это хорошей / плохой практикой программирования в Python?
  • Как вы PEP 8 называете класс, чье имя является аббревиатурой?
  • Что такое метод Pythonic для инициализации атрибутов или свойств?
  • Стиль Python
  • Python: присвоение атрибутов класса boolean / flag
  • Получить полную структуру программы?
  • Питоновский способ повторения вызова метода на различные конечные аргументы

Функции __name__ и __main__ в Python, запуск кода для начинающих

Предыдущий урок: Namedtuple

В различных руководствах по Python часто используется функция main(). Но иногда это может быть и лишним.

Лаконичность — важный элемент программирования. И вполне логично задавать вопрос о том, зачем разработчику добавлять лишние строки в программу. Функция main() требует дополнительных строк, но она служит определенной цели.

В этом материале речь пойдет о функции main(), о том, какую пользу она приносит, а также о том, как правильно использовать ее в коде.

Что такое функция main()?

Main — это специальная функция, которая позволяет добавить больше логики в структуру программ. В Python можно вызвать функцию в нижней части программы, которая и будет запущена. Рассмотрим такой пример:

Копировать Скопировано Use a different Browser


def cookies():
print("Печенье вкусное!")

print("Дайте печенье.")
cookies()

Запустим этот код:

Дайте печенье.
Печенье вкусное!

Можно увидеть, что выражение «Дайте печенье.» выводится до «Печенье вкусное!», потому что метод cookies() не вызывается вплоть до последней строки, а именно в этой функции хранится предложение «Печенье вкусное!».

Такой код работает, но его довольно сложно читать. В таких языках программирования, как C++ и Java весь основной код программы хранится внутри основной функции. Это хороший способ для распределения всего кода программы. Те, кто только знакомится с Python, но уже работал, например, с C++ будут благодарны за использование функции main().

Как создать функцию main

Есть две части основной функции Python. Первая — сама функция main(). В ней хранится код основной программы. Вызовем функцию cookies()

и выведем выражение «Дайте печенье.» из функции main():

Копировать Скопировано Use a different Browser


def cookies():
print("Печенье вкусное!")

def main():
print("Дайте печенье.")
cookies()

Теперь вызовем функцию в конце программы:

Копировать Скопировано Use a different Browser


main()

Можно запустить код:

Дайте печенье. 
Печенье вкусное!

Результат не поменялся. Но теперь сам код читать легче. Пусть в нем и больше строк (и одна дополнительная строка), вполне очевидно, что именно происходит:

  • Cookies() — функция, которая выводит «Печенье вкусное!».
  • Когда программа запускается, определяются две функции: cookies() и main().
  • Затем функция main() вызывается.
  • «Дайте печенье.» выводится в консоли.
  • Затем вызывается функция cookies(), которая выводит в консоль «Печенье вкусное!».

Код не только чище, но и логичнее. Если вы пришли из другого языка, например, Java, но знаете, насколько это удобно.

Значение __name__

Прежде чем переходить к инструкциям __name__ и __main__, которые часто используются вместе, нужно обсудить __name__. __name__ хранит название программы.

Если запустить файл прямо, то значением __name__ будет __main__. Предположим, что файл называется print_name.py:

Копировать Скопировано Use a different Browser


print(__name__)

Этот код можно запустить следующим образом:

$ python print_name.py

Он вернет __main__.

Предположим, что этот код был импортирован в качестве модуля в файл main.py:

Копировать Скопировано Use a different Browser


import print_name

Запустим его:

$ python main.py

Код вернет:

print_name

Код внутри print_name.py исполняется потому что он был импортирован в качестве модуля в основной программе. Файл print_name выводит __name__ в консоль. Поскольку print_name был импортирован в качестве модуля, то и значением __name__ является print_name.

if __name__ == __main__ в Python

Вы наверняка встречали следующую конструкцию в программах на Python в функции main:

Копировать Скопировано Use a different Browser


if __name__ == "__main__":

Что она значит? В Python любая переменная, начинающаяся с двух символов нижнего подчеркивания (__), является специальной. Это зарезервированные значения, которые выполняют определенную роль в программе.

__main__ указывает на область видимости, где будет выполняться код. Если запустить Python-файл прямо, то значением __name__ будет __main__. Если же его запустить в качестве модуля, то значением будет уже не __main__, а название модуля.

Это значит, что строка выше вернет True только в том случае, если программа будет запущена прямо.

Если же ссылаться на файл как на модуль, то содержимое конструкции if не будет выполнено. Рассмотрим на примере.

Как использовать __name__ и __main__

Создадим новый скрипт на Python под названием username.py. В коде будем просить пользователя ввести его имя и проверять, не является ли его длина больше 5. Если символов не больше 5, то попросим ввести имя снова.

Начнем с определения глобальной переменной для хранения имени пользователя:

Копировать Скопировано Use a different Browser


username = ""

После этого определим две функции. Первая будет просить пользователя ввести имя пользователя и проверять, не больше ли 5 символов в нем. Вторая будет выводить значение в оболочке Python:

Копировать Скопировано Use a different Browser


def choose_username():
global username
username = input("Введите логин: ")
if len(username) > 5:
print("Ваш логин сохранен.")
else:
print("Пожалуйста, выберите имя пользователя длиной более пяти символов.")
choose_username()

def print_username():
print(username)

В этом примере использовалось ключевое слово global, чтобы содержимое, присвоенное в методе choose_username(), было доступно глобально. После определения функций нужно создать main, которая и будет их вызывать:


Копировать Скопировано Use a different Browser


def main():
choose_username()
print_username()

После этого нужно добавить if __name__="__main__" в инструкцию if. Это значит, что при запуске файла прямо, интерпретатор Python исполнит две функции. Если же запустить код в качестве модуля, то содержимое внутри main() исполнено не будет.

Копировать Скопировано Use a different Browser


if __name__ == "__main__":
main()

Запустим код:

$ python username.py

Он вернет следующее:

Введите логин: mylogin
Ваш логин сохранен.
mylogin

Этот код запускает функцию choose_username(), а затем — print_username(). Если указать имя длиной меньше 4 символов, то ответ будет таким:

Введите логин: Li
Ваш логин сохранен.
Пожалуйста, выберите имя пользователя длиной более пяти символов.
Введите логин:

Будет предложено ввести другое имя. Если импортировать этот код в качестве модуля, то функция main() не запустится.

Выводы

Функция main() используется для разделения блоков кода в программе. Использование функции main() обязательно в таких языках, как Java, потому что это упрощает понимание того, в каком порядке код запускается в программе. В Python функцию main() писать необязательно, но это улучшает читаемость кода.

Далее: Функция zip()

Немного примеров match/case в Python 3.10 / Хабр

Не так давно (а именно 4 октября 2021 года) официально увидела свет юбилейная версия языка python, а именно версия 3.10. В ней было добавлено несколько изменений, а самым интересным (на мой взгляд) было введение pattern matching statement (оператор сопоставления с шаблонами). Как гласит официальное описание этого оператора в PEP622, разработчики в большей мере вдохновлялись наработками таких языков как: Scala, Erlang, Rust.

Для тех, кто еще не знаком с данным оператором и всей его красотой, предлагаю познакомиться с pattern matching в данной статье. 

Немного о pattern matching

Как говорится в официальной документации (PEP622) в Python очень часто требуется проверять данные на соответствие типов, обращаться к данным по индексу и к этим же данным применять проверку на тип. Также зачастую приходится проверять не только тип данных, но и количество, что приводит к появлению огромного числа веток if/else с вызовом функций isinstance, len и обращению к элементам по индексу, ключу или атрибуту. Именно для упрощения работы и уменьшения is/else был введен новый оператор match/case.

Очень важно не путать pattern matching и switch/case, их главное отличие состоит в том, что pattern matching — это не просто оператор для сравнения некоторой переменной со значениями, это целый механизм для проверки данных, их распаковки и управления потоком выполнения.

Давай же рассмотрим несколько примеров, как данный оператор поможет упростить написание кода и сделать код более читаемым.

Примеры

Самый простой пример — это сравнение некоторой переменной со значениями (сначала рассмотрим как это было бы с if/else):

def load():
   print("Загружаем")
def save():
   print("Сохраняем")
def default():
   print("Неизвестно как обработать")
def main(value):
   if isinstance(value, str) and value == "load":
       load()
   elif isinstance(value, str) and value == "save":
       save()
   else:
       default()
      
main("load")
>>> Загружаем
main("save")
>>> Сохраняем
main("hello")
>>> Неизвестно как обработать

Теперь с match/case:

def main(value):
   match value:
       case "load":
           load()
       case "save":
           save()
       case _:
           default()
main("load")
>>> Загружаем
main("save")
>>> Сохраняем
main(5645)
>>> Неизвестно как обработать

Стало заметно меньше «and» и «==», получилось избавиться от лишних проверок на тип данных и код стал более понятным, однако это лишь самый простой пример, углубимся дальше. Допустим, откуда-то приходят данные в виде строки, которые записаны с разделителем “~”, и заранее известно, что если в данных было ровно 2 значения, то выполнить одно действие, если 3 значения, то иное действие:

def load(link):
   print("Загружаем", link)
   return "hello"
def save(link, filename):
   data = load(link)
   print("Сохраняем в", filename)
def default(values):
   print("Неизвестно как эти данные обработать")
    
def main(data_string):
   values = data_string.split("~")
   if isinstance(values, (list, tuple)) and len(values) == 2 and values[0] == "load":
       load(values[1])
   elif isinstance(values, (list, tuple)) and len(values) == 3 and values[0] == "save":
       save(values[1], values[2])
   else:
       default(values)
      
main("load~http://example.com/files/test.txt")
>>> Загружаем http://example.com/files/test.txt
main("save~http://example.com/files/test.txt~file.txt")
>>> Загружаем http://example.com/files/test.txt
>>> Сохраняем в file. txt
main("use~http://example.com/files/test.txt~file.txt")
>>> Неизвестно как эти данные обработать
main("save~http://example.com/files/test.txt~file.txt~file2.txt")
>>> Неизвестно как эти данные обработать

И с match/case:

def main(data_string):
   values = data_string.split("~")
   match values:
       case "load", link:
           load(link)
       case "save", link, filename:
           save(link, filename)
       case _:
           default(values)
main("load~http://example.com/files/test.txt")
>>> Загружаем http://example.com/files/test.txt
main("save~http://example.com/files/test.txt~file.txt")
>>> Загружаем http://example.com/files/test.txt
>>> Сохраняем в file.txt
main("use~http://example.com/files/test.txt~file.txt")
>>> Неизвестно как эти данные обработать
main("save~http://example.com/files/test.txt~file.txt~file2.txt")
>>> Неизвестно как эти данные обработать

Также, если есть необходимо скачать несколько файлов:

def load(links):
   print("Загружаем", links)
   return "hello"
def main(data_string):
   values = data_string. split("~")
   match values:
       case "load", *links:
           load(links)
       case _:
           default(values)
main("load~http://example.com/files/test.txt~http://example.com/files/test1.txt")
>>> Загружаем ['http://example.com/files/test.txt', 'http://example.com/files/test1.txt']

Match/case сам решает проблему с проверкой типов данных, с проверкой значений и их количеством, что позволяет упростить логику и увеличить читаемость кода. И очень удобно, что можно объявлять переменные и помещать в них значения прямо в ветке case без использования моржового оператора. 

Рассмотрим пример, когда необходимо использовать оператор “или” в примере. Допустим, приходит запрос от пользователя с правами, и необходимо проверить, может ли данный пользователь выполнять текущее действие:

def main(data_string):
   values = data_string.split("~")
   match values:
       case name, "1"|"2" as access, request:
           print(f"Пользователь {name} получил доступ к функции {request} с правами {access}")
       case _:
           print("Неудача")
main("Daniil~2~load")
>>> Пользователь Daniil получил доступ к функции load с правами 2
main("Kris~0~save")
>>> Неудача

В таком случае символ “|” выступает в роли логического “или”, а значение прав доступа в переменную access было записано при помощи оператора «as». Разберем аналогичный пример, но в качестве аргумента будем рассматривать словарь:

def main(data_dict):
   match data_dict:
       case {"name": str(name), "access": 1|2 as access, "request": request}:
           print(f"Пользователь {name} получил доступ к функции {request} с правами {access}")
       case _:
           print("Неудача")
main({"name": "Daniil", "access": 1, "request": "save"})
>>> Пользователь Daniil получил доступ к функции save с правами 1
main({"name": ["Daniil"], "access": 1, "request": "save"})
>>> Неудача
main({"name": "Kris", "access": 0, "request": "load"})
>>> Неудача

Как видим, довольно просто делать сравнение шаблонов для словарей. Пойдем еще дальше и создадим класс для хранения всех этих данных, затем попробуем организовать блок match/case для классов:

class UserRequest:
   def __init__(self, name, access, request):
       self.name = name
       self.access = access
       self.request = request
def main(data_class):
   match data_class:
       case UserRequest(name=str(name), access=1|2 as access, request=request):
           print(f"Пользователь {name} получил доступ к функции {request} с правами {access}")
       case _:
           print("Неудача")
main(UserRequest("Daniil", 1, "delete"))
>>> Пользователь Daniil получил доступ к функции delete с правами 1
main(UserRequest(1234, 1, "delete"))
>>> Неудача
main(UserRequest("Kris", 0, "save"))
>>> Неудача

Чтобы еще упростить код и не писать названия атрибутов класса, которые сравниваются, можно прописать в классе атрибут match_args, благодаря которому case будет рассматривать значения, передаваемые при сравнивании в том порядке, в котором они записаны в  match_args:

class UserRequest:
   __match_args__= ('name', 'access', 'request')
   def __init__(self, name, access, request):
       self. name = name
       self.access = access
       self.request = request
def main(data_class):
   match data_class:
       case UserRequest(str(name), 1|2 as access, request):
           print(f"Пользователь {name} получил доступ к функции {request} с правами {access}")
       case _:
           print("Неудача")
main(UserRequest("Daniil", 1, "delete"))
>>> Пользователь Daniil получил доступ к функции delete с правами 1
main(UserRequest(1234, 1, "delete"))
>>> Неудача
main(UserRequest("Kris", 0, "save"))
>>> Неудача

Так же стоить помнить, что при работе case UserRequest(str(name), access=2, request) оператор похож на создание нового экземпляра, однако это так не работает. Рассмотрим пример, подтверждающий это:

class UserRequest:
   __match_args__= ('name', 'access', 'request')
   def __init__(self, name, access, request):
       print("Создан новый UserRequest")
       self.name = name
       self.access = access
       self.request = request
def main(data_class):
   match data_class:
       case UserRequest(str(name), 1|2 as access, request):
           print(f"Пользователь {name} получил доступ к функции {request} с правами {access}")
       case _:
           print("Неудача")
main(UserRequest("Daniil", 1, "delete"))
>>> Создан новый UserRequest
>>> Пользователь Daniil получил доступ к функции delete с правами 1

Как видно, вызов init произошел всего один раз, поэтому при работе case с классами не создаются новые новые экземпляры классов!

Более сложный и не такой тривиальный пример со сравнением некоторых данных, пришедших в оператор match/case:

class UserRequest:
  __match_args__= ('name', 'access', 'request')
  def __init__(self, name, access, request):
      self. name = name
      self.access = access
      self.request = request
def main(data_class):
  match data_class:
       case UserRequest(_, _, request) if request["func"] == "delete" and request["directory"] == "main_folder":
           print(f"Нельзя удалять файлы из {request['directory']}")
       case UserRequest(str(name), 1|2 as access, request) if request["func"] != "delete":
           print(f"Пользователь {name} получил доступ к файлу {request['file']} с правами {access} на {request['func']}")
       case _:
           print("Неудача")
main(UserRequest("Daniil", 1, {"func": "delete", "file": "test.txt", "directory": "main_folder"}))
>>> Нельзя удалять файлы из main_folder
main(UserRequest("Daniil", 1, {"func": "save", "file": "test.txt", "directory": "main_folder"}))
>>> Пользователь Daniil получил доступ к файлу test.txt с правами 1 на save

“_” позволяет не объявлять переменную под данные, а просто указывает, что на этом месте должны быть какие-то данные, но их можно не задействовать дальше. Также можно использовать оператор if для того, чтобы добавлять новые условия на проверку шаблона.

Заключение

Новый оператор pattern matching сильно упрощает жизнь во многих моментах и делает код еще более читаемым и лаконичным, что позволяет писать код быстрее и эффективнее не боясь за то, что вдруг где-то в коде не стоит проверка на тип элемента или на количество элементов в списке.

В данной статье были рассмотрены лишь несколько примеров для знакомства с оператором match/case, также существует возможность создавать более детальные и глубокие проверки в шаблонах, поэтому каждому стоит поэкспериментировать с данным оператором, так как, возможно, он позволит вам сделать код еще чище и проще.

Определение основных функций в Python — Real Python