Как стать автором
Обновить
2392.03
МТС
Про жизнь и развитие в IT

Как я начал учить Go и правда ли он похож на Python. Мой личный опыт

Уровень сложностиПростой
Время на прочтение5 мин
Количество просмотров19K

Всем привет! Меня зовут Иван, я программирую на Python и недавно решил освоить новый ЯП. Долго думал, какой выбрать. В итоге решил довериться утверждению, что Python во многом похож на Go — на нем и остановился.

Ниже поделюсь личным опытом изучения языка — и да, я еще продолжаю его осваивать. Расскажу, какие встретил различия между Python и Go в типах данных, преобразовании типов данных, подходах к обработке ошибок. А еще обсудим, какой ЯП быстрее и можно ли импортировать и выполнить код Go в Python. Надеюсь, этот пост будет интересен тем, кто тоже собирается освоить второй ЯП. Ну, let’s Go!

Такие разные Go и Python

Осваивая Go, я понял, что некоторые моменты действительно напоминают Python — например, описание функций и оператор ветвления. Так что и давались они мне легко. А вот многообразие типов данных, их преобразование и обработка ошибок заставили попотеть — об этом и расскажу дальше.

Типизация — статическая и обязательная

Первое и, возможно, самое заметное различие двух языков программирования — это их типизация. В Python типизация динамическая, а в Go статическая, то есть во время выполнения программы нельзя изменить тип переменной.

Например, если в Python можно создать переменную x и сначала присвоить число 1, а после — строку "hello", ошибки не будет:

x = 1
x = “hello”

А вот к чему приведут такие же действия в Go:

var x int = 1
x = “hello” // Ошибка

Обязательную типизацию лучше рассмотреть на примере функции сложения двух чисел.

В Python можно не указывать тип аргументов функции:

def add(a, b):
    return a + b

Но если то же самое сделать в Go, возникнет ошибка:

func add(a, b) { // Ошибка
    return a + b
}

Чтобы ее избежать, добавим тип аргументов (int) и тип данных на выходе из функции (int):

func add(a int, b int) int {
    return a + b
}

Простые типы данных

Еще одно крупное различие — более обширный арсенал простых типов данных у Go. Посмотрите:

Тип данных

Python

Go

integer

int

int, uint, uintptr (32 бита на 32-битной системе и 64 на 64-битной системе)

int8, int16, int32, int64

uint8, uint16, uint32, uint64

float

float

float32, float64

complex

complex

complex64, complex128

string

str

string

boolean

bool

bool

В Python для создания целого числа выбирается int. Зная о динамическом распределении памяти, можно не беспокоиться о его увеличении. Но в Go ситуация немного другая. Если число будет слишком большим, может произойти переполнение.

Пусть Go запускается на 32-битной машине, тогда:

package main

import "fmt"

func main() {
    var number int32 = 2147483647  // Максимальное значение для int32
    fmt.Println(number + 1)        // -2147483648 —> Произошло переполнение
}

В случае же с Python:

number = 2147483647
print(number + 1)  # 2147483648 —> Переполнения не возникло

Преобразование типов данных

Превратить один объект в другой в Python максимально просто. Достаточно написать тип данных и двойные скобки вокруг преобразуемого объекта:

number = 103
str_number = str(number)

В случае с Go придется знать чуть больше:

  • нужно импортировать модуль strconv и воспользоваться функцией Itoa;

  • использовать модуль fmt и выполнить форматирование при помощи Sprintf.

package main

import (
	"fmt"
	"strconv"
)

func main() {
	number := 103
	str_number_1 := strconv.Itoa(num)
	str_number_2 := fmt.Sprintf("%d", num)
}

Обработка ошибок

Что меня действительно удивило при изучении Go — так это работа с ошибками. Допустим, нам нужно открыть файл test.txt и обработать возможные ошибки. В Python достаточно поместить код в блок TRY и использовать EXCEPT для различных исключений:

try:
    with open("test.txt", "r") as file:
        content = file.read()
    print("Содержимое файла:")
    print(content)
except FileNotFoundError:
    print("Ошибка: файл не найден!")
except IOError as exception:
    print(f"Ошибка ввода-вывода: {exception}")
except Exception as exception:
    print(f"Неизвестная ошибка: {exception}")

В Go все по-другому: часто функции передают дополнительный параметр, который указывает, возникла какая-либо ошибка или нет. В нашем примере функция ReadFile возвращает на втором месте nil (похож на None в Python), если ошибки не было. И error (интерфейс), если была.

package main

import (
    "fmt"
    "os"
)

func main() {
    content, err := os.ReadFile("test.txt")
    if err != nil {
        fmt.Println("Ошибка при чтении файла:", err)
        return
    }

    fmt.Println("Содержимое файла:")
    fmt.Println(string(content))
}

Скорость

Как Python и Go отличаются по скорости, рассмотрим на бенчмарках.

1. Комплексный анализ.

Задача: каждый бенчмарк выполняется на всех ядрах с пулом подключений к БД. При каждом запросе:

  • из БД извлекается 100 тестовых пользователей;

  • создается экземпляр класса для каждой строки, преобразуя объект datetime в строку формата ISO и шифруя одно из полей с помощью шифра Цезаря;

  • результат (массив) сериализуется в JSON и возвращается в качестве ответа.

Версия Golang — 1.22.3, а Python — 3.12.3.

Получается, в среднем Go быстрее Python в два раза:

ЯП

Сервер/фреймворк

RPS
(кол-во запросов в секунду)

Время (миллисекунды)

Golang

net/http, json

6 671

0,15

net/http, json, chi

6 177

0,16

net/http, easyjson

7 384

0,14

fasthttp, easyjson

8 054

0,12

Python

gunicorn

1 994

0,50

gunicorn, flask

1 931

0,52

uvicorn, asyncio

3 486

0,29

uvicorn, uvloop

3 664

0,27

gunicorn, aiohttp

3 276

0,31

2. Простые числа.

Задача: вычислить ряд простых чисел от 0 до 10 000 000. И вот что получилось:

Язык программирования

Время (секунды)

Go (int32)

2,37

Go (int64)

7,12

Python

59,64

Python + Numba

7,43

В среднем Python уступает Go по времени выполнения в 17 раз. Но когда на помощь приходит Numba, Python догоняет Go (int64).

Go в Python

Как ни странно, но код, написанный на Go, можно использовать в Python.

Покажу такой пример. Пусть на Go написана функция умножения Multiply:

package main

import "C"

//export Multiply
func Multiply(a, b int) int {
        return a * b
}
func main() {}

Чтобы использовать ее в Python, добавляем перед функцией комментарий со словом export и названием функции.

Выполняем компиляцию:

go build -o multiply.so -buildmode=c-shared multiply.go

Дальше открываем файл multiply.h для определения типа данных. Находим описание функции:

extern GoInt Multiply(GoInt a, GoInt b);

Видим, что тип данных у аргументов функции — GoInt. Значит, идем выше по коду и ищем, что означает GoInt. Можно увидеть такую строку:

typedef GoInt64 GoInt;

Теперь идем еще выше и ищем GoInt64:

typedef long long GoInt64;

Видим long long. Получается что для аргументов нужно будет указать тип данных long long языка программирования C.

Для использования скомпилированного файла в Python возьмем библиотеку ctypes. Укажем типы данных аргументов C long long и в конце выполним функцию Multiply:

>>> import ctypes
>>> lib = ctypes.cdll.LoadLibrary("./multiply.so")
>>> lib.Multiply.argtypes = [ctypes.c_longlong, ctypes.c_longlong]
>>> lib.Multiply(2, 10)
20

Где используют Go

Изучать новый язык программирования всегда классно. Но если не применять знания на практике, они будут постепенно забываться. Это как с иностранным: я учил немецкий в школе и после выпуска не практиковал, так что сейчас из предложения «ты любишь учиться» смогу перевести только местоимение «du».

Чтобы усилия с ЯП не прошли напрасно, я сразу решил, что буду использовать Go для разработки микросервисов. Скорее всего, это будет непросто, но так у меня есть цель.

Вообще Go всегда приходит на помощь там, где нельзя или неудобно использовать Python. Например, при работе с API идеальный выбор Python, но если планируется работа с чанками (например, раздача чанков видео), Go справится лучше. Другие примеры использования Go — облачные и сетевые сервисы, интерфейсы командной строки (CLI).

Среда выполнения Go включает race-детектор и инструменты для бенчмаркинга и статического анализа кода, а мощная экосистема позволяет комфортно разрабатывать сервисы. В стандартную библиотеку входят пакеты для:

  • работы с HTTP-серверами и клиентами;

  • парсинга JSON/XML;

  • взаимодействия с базой данных SQL;

  • обеспечения безопасности и шифрования.

Напоследок несколько примеров, в каких процессах Go используют зарубежные компании:

  • Allegro — для разработки сервиса кэширования.

  • American Express — для работы с платежами.

  • Armut — для сокращения потребления ресурсов и времени ответа на запрос.

  • Bitly перенесли старые проекты на Go и разрабатывают новые на нем же.

  • Dropbox — основные части инфраструктуры теперь работают на Go.

  • Microsoft использует Go для облачной инфраструктуры.

Ну и, конечно, Google использует свой ЯП для создания различных сервисов.

Пока я только начинаю грызть гранит Go. Мне удалось разобраться с циклами, функциями, пакетами, но впереди еще постижение интерфейсов, работы с файлами и параллелизма. Не знаю, как быстро пойдет прогресс, но интересно будет точно!

Буду рад, если в комментариях поделитесь своим опытом освоения Go: что было для вас самым сложным и где используете этот ЯП сейчас. И спасибо, что читали!

Теги:
Хабы:
+34
Комментарии44

Публикации

Информация

Сайт
www.mts.ru
Дата регистрации
Дата основания
Численность
свыше 10 000 человек
Местоположение
Россия