Go for Python Developers

Abstract generated cover for Go for Python Developers.

Go can feel strange coming from Python. Python is flexible, dynamic, and expressive. Go is smaller, stricter, and more explicit. That difference is the point. Go is designed around simple tooling, fast builds, static binaries, explicit error handling, and straightforward concurrency. It is not trying to feel like Python. If you approach Go as "Python with braces," it will be frustrating. If you approach it as a small language for building reliable services and tools, it starts to make sense.

The Mental Model

Python often optimizes for expressiveness. Go often optimizes for clarity and mechanical simplicity. In Python, you might write compact code using dynamic behavior. In Go, you usually write more explicit code:

  • declare types
  • check errors
  • keep control flow visible
  • let the formatter decide style
  • prefer simple composition The result can feel verbose at first, but it is also easy to scan once you learn the patterns.

A Small Go Program

Here is a tiny Go program:

package main

import "fmt"

func main() {
    message := "hello"
    fmt.Println(message)
}

Run it:

go run main.go

Build it:

go build

The `package main` line means this is an executable program. The `main` function is where execution starts.

Types Are Part of the Workflow

Python:

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

Go:

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

Go wants to know the types. This can feel slower when writing code, but it catches many mistakes earlier. You can also let Go infer local variable types:

count := 10
name := "Tristan"

The `:=` operator declares and assigns a new variable.

Error Handling Is Explicit

Python often uses exceptions:

try:
    data = load_file("config.json")
except FileNotFoundError:
    data = {}

Go usually returns errors as values:

data, err := loadFile("config.json")
if err != nil {
    return err
}

You will see this pattern constantly:

result, err := doSomething()
if err != nil {
    return err
}

At first, this looks repetitive. The benefit is that failure paths are visible. You do not have to search for hidden exceptions moving through the program.

Slices and Maps

Python lists and dictionaries are everywhere. Go has slices and maps. A slice:

names := []string{"Ada", "Grace", "Linus"}
names = append(names, "Ken")

A map:

ages := map[string]int{
    "Ada": 36,
    "Grace": 85,
}

fmt.Println(ages["Ada"])

These are everyday data structures in Go. The syntax is different, but the mental model is familiar if you use Python lists and dictionaries.

Structs Instead of Classes

Go does not use classes the same way Python does. You define structs:

type User struct {
    ID    int
    Email string
}

Then you can define methods on them:

func (u User) DisplayName() string {
    return u.Email
}

This gives you data plus behavior without a traditional class hierarchy. Go tends to prefer composition over inheritance.

Interfaces Are Small

Go interfaces describe behavior. Example:

type Writer interface {
    Write([]byte) (int, error)
}

A type satisfies an interface by having the required methods. It does not need to explicitly declare that it implements the interface. This is different from many languages. It encourages small interfaces that describe exactly what a function needs.

Tooling Is a Big Part of Go

Go's tooling is one of its best features. Common commands:

go fmt ./...
go test ./...
go run .
go build
go mod tidy

`gofmt` removes formatting debates. `go test` is built into the toolchain. `go mod` handles modules and dependencies. This makes Go projects feel consistent across machines.

Common Mistakes

Mistake 1: Trying to write Python-style Go

Go code usually favors explicit control flow over clever abstraction. If the code feels boring but clear, that is often fine.

Mistake 2: Ignoring errors

Do not throw away errors just to make code shorter. This is a bad habit:

data, _ := loadFile("config.json")

If something can fail, handle the failure.

Mistake 3: Creating huge interfaces

Small interfaces are easier to satisfy and easier to test. Do not design a large interface before the code needs it.

Where This Shows Up in Real Projects

Go is a good fit for command line tools, backend services, workers, APIs, and infrastructure programs. Python is still excellent for scripting, Django apps, data work, and fast iteration. The choice is not about one language replacing the other. For me, the useful question is:

Does this project benefit from Go's static binary, fast tooling, explicitness, and concurrency model? If yes, Go is worth considering.

Key Takeaways

  • Go is stricter and more explicit than Python.
  • Error handling is visible and repetitive by design.
  • Structs and interfaces replace many class-heavy patterns.
  • Go tooling is simple and consistent.
  • Do not try to force Python habits directly into Go.

    Related Articles

  • Python Virtual Environments Explained

  • How to Structure a Python Project
  • Terminal Tools I Actually Use

← Back to Blog Index