Algorand Python
Algorand Python is a partial implementation of the Python programming language that runs on the Algorand Virtual Machine (AVM). It includes a statically typed framework for the development of Algorand smart contracts and logic signatures, with Pythonic interfaces to underlying AVM functionality.
Algorand Python is compiled for execution on the AVM by PuyaPy, an optimizing compiler that ensures the resulting AVM bytecode execution semantics match the given Python code. PuyaPy produces output that is directly compatible with AlgoKit typed clients, simplifying the process of deployment and calling. This allows developers to use standard Python tooling in their workflow.
Benefits of using Algorand Python
- Rapid development: Python’s concise syntax allows for quick prototyping and iteration of smart contract ideas.
- Lower barrier to entry: Python’s popularity means more developers can transition into blockchain development without learning a new language.
- Ease of Use: Algorand Python is designed to work with standard Python tooling, making it easy for developers familiar with Python to start building smart contracts on Algorand.
- Efficiency: Algorand Python is compiled for execution on the AVM by PuyaPy, an optimizing compiler that ensures the resulting AVM bytecode execution semantics match the given Python code. This makes deployment and calling easy.
- Modularity: Algorand Python supports modular and loosely coupled solution components, facilitating efficient parallel development by small, effective teams, reducing architectural complexity, and allowing developers to pick and choose the specific tools and capabilities they want to use based on their needs and what they are comfortable with.
Python Implementation for AVM
Algorand Python maintains the syntax and semantics of Python, supporting a subset of the language that will grow over time. However, due to the restricted nature of the AVM, it will never be a complete implementation. For example, async
and await
keywords are not supported as they don’t make sense in the AVM context. To learn more refer to AVM Docs(/build/core-concepts/AVM).
This partial implementation allows existing developer tools like IDE syntax highlighting, static type checkers, linters, and auto-formatters to work out of the box. This approach differs from other partial language implementations that add or alter language elements, which require custom tooling support and force developers to learn non-obvious differences from regular Python.
AVM Types and Their Algorand Python Equivalents
The basic types of the AVM are:
uint64
: Represented asUInt64
in Algorand Pythonbytes[]
: Represented asBytes
in Algorand Python
The AVM also supports “bounded” types, such as bigint
(represented as BigUInt
in Algorand Python), which is a variably sized (up to 512-bit) unsigned integer backed by bytes[]
.
It’s important to note that these types don’t directly map to standard Python primitives. For example, Python’s int
is signed and effectively unbounded, while a bytes
object in Python is limited only by available memory. In contrast, an AVM bytes[]
has a maximum length of 4096.
Differences from Standard Python
Unsupported features
Several features of standard Python are not supported in Algorand Python due to AVM limitations:
Feature | Rationale |
---|---|
Exception handling (raise, try/except/finally) | Implementing user-defined exceptions would be costly in terms of opcodes. Additionally, AVM errors and exceptions are not catchable and will immediately terminate the program. As a result, supporting exceptions and exception handling offers minimal to no benefit. |
Context managers (with statements) | Redundant without exception handling support |
Asynchronous programming (async/await) | AVM is not just single-threaded; all operations are effectively “blocking”, rendering asynchronous programming useless. |
Closures and lambdas | Without the support of function pointers, or other methods of invoking an arbitrary function, it’s impossible to return a function as a closure. Nested functions/lambdas may be supported in the future as a means of repeating common operations within a given function. |
Global keyword | Module-level values are only allowed to be constants. No rebinding of module constants is allowed. It’s unclear what the meaning here would be since there’s no real arbitrary means of storing a state without associating it with a particular contract. If you need such a thing, look at gload_bytes or gload_uint64 to see if the contracts are within the same transaction. Otherwise AppGlobal.get_ex_bytes and AppGlobal.get_ex_uint64 . |
Inheritance (outside of contract classes) | Contract inheritance is a special case since each concrete contract is compiled separately; true polymorphism isn’t required as all references can be resolved at compile time. Polymorphism is also impossible to support without function pointers, so data classes (such as arc4.Struct ) don’t currently allow for inheritance. |
Python Primitives
Algorand Python has limitations on standard Python primitives due to the constraints of the Algorand Virtual Machine (AVM).
Supported primitives:
Bool
: Algorand Python has full support forbool
.Tuple
: Python tuples are supported as arguments to subroutines, local variables, return types.
The int
, str
, and bytes
built-in types are currently only supported as module-level constants or literals. They can be passed as arguments to various Algorand Python methods that support them or when interacting with certain AVM types e.g. adding a number to a UInt64
.
Unsupported primitives:
Float
is not supported.- Nested tuples are not supported.
None
:None
is not supported as a value, but is supported as a type annotation to indicate a function or subroutine returns no value.
For instance, Python’s int
is unsigned and unbounded, while AVM’s uint64
(represented as UInt64
in Algorand Python) is a 64-bit unsigned integer. Similarly, Python’s bytes
objects are limited only by available memory, whereas AVM’s bytes[]
(represented as Bytes
in Algorand Python) have a maximum length of 4096 bytes.
PuyaPy Compiler
The PuyaPy compiler is a multi-stage, optimizing compiler that takes Algorand Python and prepares it for execution on the Algorand Virtual Machine (AVM). It ensures that the resulting AVM bytecode execution semantics match the given Python code. The output produced by PuyaPy is directly compatible with AlgoKit typed clients, making deployment and calling of smart contracts easy.
The PuyaPy compiler is based on the Puya compiler architecture, which allows for multiple frontend languages to leverage the majority of the compiler logic. This makes adding new frontend languages for execution on Algorand relatively easy.
For more details, refer to Algokit installation page
Testing and Debugging
The algorand-python-testing
package allows for efficient unit testing of Algorand Python smart contracts in an offline environment. It emulates key AVM behaviors without requiring a network connection, offering fast and reliable testing capabilities with a familiar Pythonic interface.
For more details, refer to Algokit Python Test and Algokit Python Debugging
Best Practices
- Write type-safe code: Always specify variable types, function parameters, and return values.
- Leverage existing Python knowledge: Use familiar Python constructs and patterns where possible.
- Be aware of AVM limitations: When writing your smart contracts, consider the restrictions imposed by the AVM.
- Static typing is crucial in Algorand Python, differing significantly from standard Python’s dynamic typing. This ensures type safety and helps prevent errors in smart contract development.
Resources for Further Learning
For a comprehensive introduction to writing, compiling, and debugging a smart contract with Algorand Python, refer to the Algokit Python smart contracts tutorial for beginners. This tutorial provides step-by-step guidance on getting started with Algorand Python.