Ethereum

Ethereum

Python

Python's Ethereum stack splits along two jobs. web3.py is the general-purpose client — what you import to query a balance, watch logs, or sign a transaction against chain 1 from a script, a Django backend, or a data pipeline. eth-brownie sits one level up, a development framework built on web3.py for writing, testing, and deploying Solidity contracts with pytest-style assertions. The same library that backs a five-line block-explorer script also powers a production indexer, so you rarely outgrow it.

From version 6 on, web3.py offers both a synchronous and an async interface to Ethereum. The sync Web3 is fine for scripts and request-scoped backend work. When you need to fan out many calls at once, switch to AsyncWeb3 paired with an async provider so the calls run concurrently on an asyncio loop instead of blocking one after another.

Web3.py

web3.py is the official Python Ethereum library, and it mirrors the full JSON-RPC surface — block reads, balances, transactions, contract calls, filters. Install it with pip install web3, then wrap the endpoint in an HTTP provider: Web3(Web3.HTTPProvider('https://ethereum.therpc.io/YOUR_API_KEY')). web3.eth.get_balance returns wei as a Python int, and web3.from_wei(..., 'ether') scales it to a Decimal ETH value, so you keep full precision instead of risking float drift on 18-decimal numbers.

from web3 import Web3
from eth_account import Account
import json
# Initialize web3
web3 = Web3(Web3.HTTPProvider('https://ethereum.therpc.io/YOUR_API_KEY'))
# Get balance
def get_balance(address):
balance_wei = web3.eth.get_balance(address)
balance_eth = web3.from_wei(balance_wei, 'ether')
return balance_eth
# Send transaction
def send_transaction(private_key, to_address, value_eth):
account = Account.from_key(private_key)
transaction = {
'nonce': web3.eth.get_transaction_count(account.address),
'to': to_address,
'value': web3.to_wei(value_eth, 'ether'),
'gas': 21000,
'gasPrice': web3.eth.gas_price
}
signed_txn = account.sign_transaction(transaction)
tx_hash = web3.eth.send_raw_transaction(signed_txn.rawTransaction)
return web3.eth.wait_for_transaction_receipt(tx_hash)

Eth-brownie

eth-brownie is a Python framework aimed squarely at the contract side of Ethereum: compiling Solidity, writing pytest tests against a forked or local chain, and managing deployments across networks. Install it with pip install eth-brownie. It pulls in its own compiler management and an interactive console, so MyContract.deploy(...) and MyContract.at(address) feel like ordinary Python objects while Brownie handles the transaction signing and receipt waiting underneath.

from brownie import *
# Deploy contract
def deploy_contract():
account = accounts[0]
return MyContract.deploy({'from': account})
# Interact with contract
def interact_with_contract(contract_address):
contract = MyContract.at(contract_address)
return contract.myFunction({'from': accounts[0]})
# Test contract
def test_contract(Contract):
account = accounts[0]
contract = account.deploy(Contract)
assert contract.myFunction() == expected_value
  • GitHub: https://github.com/eth-brownie/brownie
  • Docs: https://eth-brownie.readthedocs.io/
  • A pytest-based testing framework for Ethereum contracts
  • Deployment management with tracked, repeatable scripts
  • An interactive console for poking at live contracts
  • Network configuration for mainnet, testnets, and local forks
  • A full Python REPL with your contracts already in scope

Async Support

When you need to pull many things from Ethereum at once — say, the last several blocks, or balances for a list of addresses — the async interface pays off. AsyncWeb3 over an async provider lets those calls overlap on an asyncio event loop instead of waiting in line, so the wall-clock time is set by the slowest round-trip rather than the sum of all of them. Each method becomes awaitable: await w3.eth.get_block_number(), and you drive the whole thing from asyncio.run(...).

from web3.auto import w3
import asyncio
async def get_latest_blocks(count):
latest = await w3.eth.get_block_number()
blocks = []
for i in range(count):
block = await w3.eth.get_block(latest - i)
blocks.append(block)
return blocks
# Usage
blocks = asyncio.run(get_latest_blocks(10))

Type Hints

web3.py ships real type stubs, so Ethereum primitives have names you can lean on: Wei for amounts, Address for checksummed addresses, TxParams for the transaction dict. Annotating a function that builds a transaction with these — as below — gives you editor autocompletion and lets mypy catch a swapped argument or a missing field before the code ever reaches mainnet. It's the difference between a type error at your desk and a reverted transaction that still cost gas.

from web3.types import TxParams, Wei, Address
from typing import Optional
def prepare_transaction(
to: Address,
value: Wei,
gas_price: Optional[Wei] = None
) -> TxParams:
return {
'to': to,
'value': value,
'gasPrice': gas_price or web3.eth.gas_price
}

Ready to call this in production?

Free tier covers personal projects. Pay-as-you-go scales without a card.