Skip to content
On this page

Differences between SmartPy and Python

Although SmartPy is similar to Python in many ways, it has some significant differences. These differences apply to code within SmartPy modules. On the contrary, the test scenario is pure Python. Many of these differences exist because SmartPy is compiled to the Michelson stack-based language, which is very different from Python. Other differences exist because SmartPy is made for writing Tezos smart contracts instead of being a general-purpose programming language.

Code within a test scenario is ordinary Python. Therefore, within a test scenario, you can do things that you can't do in a smart contract, such as import and use Python libraries, call external APIs, and work with private keys and test accounts. For more information about tests, see Test scenarios.

Code within a SmartPy module is subject to these limitations:

Module

You cannot use imported Python modules in SmartPy code. You can import SmartPy code from other .spy files or import SmartPy modules defined within sp.module blocks.

Please see modules.

Control structures

Functions, loops, and conditionals have limitations in SmartPy that are not in Python:

Functions

Functions (including entrypoints, views, and auxiliary functions) must end at a single block of code. For example, this code is not valid because it could return from more than one place in the code, even though the return statements are close to each other:

smartpy
if a > b:
    return a # Error: 'return' in non-terminal position.
return b

Instead, functions must return from a single block of code, as in this example:

smartpy
if a > b:
    return a
else:
    return b

Loops

Similarly, you can't use the break command to end a loop early, as in this example:

smartpy
x = 3
i = 0
while i < 5:
    if i == x:
        break # SyntaxError: Not a statement: break
    i += 1

Logic

  • SmartPy supports the Python if and else statements, but not the elif statement.
  • SmartPy does not support Python exception handling with statements such as try and except.
  • SmartPy does not support some built-in Python functions, such as type and bool.

Logging

To write to STDOUT from SmartPy, use the sp.trace function.

Variables

SmartPy is limited by the types of variables that Michelson supports and how it uses variables:

Types

SmartPy does not support every data type that Python does. Also, SmartPy data types may not have the same methods that the equivalent Python data types have. See the Data types section for the types that SmartPy supports.

Some SmartPy types behave differently from the equivalent Python types. For example, SmartPy numerical types behave differently when they are divided; see Division.

You must be aware of the types that you use in SmartPy modules versus the types that you use in the Python code of test scenarios. For example, within a SmartPy module, lists that you create have the type sp.list[t], where t is the type of the list elements; see Lists, sets, and maps. Therefore, to add elements to a list, you use the push() method of the sp.list type, as in this example:

smartpy
@sp.entrypoint
def lists(self):
    my_list = [1, 2, 3]
    my_list.push(sp.int(4))

However, lists that you create in Python code, including test scenarios, are ordinary Python lists. Therefore, to add elements to a list, you use the append() method, as in this example:

python
@sp.add_test()
def test():
    # Create a test scenario
    scenario = sp.test_scenario("A Test", main)

    # ...

    my_list = [1, 2, 3]
    my_list.append(4)

Similarly, to check if an element is in a SmartPy set of type sp.set, use its contains() method, not the standard Python in operator.

Casting

In most cases, you cannot change the type of a variable after you define it. The sp.cast function does not change the type of a variable; it clarifies the type of a variable for the compiler.

The STDLIB modules provide some traditional casting functions, such as converting between different numerical types.

For more information about casting, see Casting.

Enumerations

To set up an enumeration with SmartPy, use a variant type to create a group of cases. Each value has unit as a value, as in this example:

smartpy
@sp.module
def main():
    status: type = sp.variant(Active=sp.unit, Inactive=sp.unit)

    class C(sp.Contract):
        def __init__(self):
            self.data.status = sp.cast(sp.variant.Active(), status)
            self.data.statusMessage = ""
            with sp.match(self.data.status):
                with sp.case.Active:
                    self.data.statusMessage = "Running"
                with sp.case.Inactive:
                    self.data.statusMessage = "Not running"

Access and iteration

Michelson variables are stored in a stack, which introduces limitations on accessing and iterating over variables. Here are some of those limitations:

  • You cannot retrieve or change an arbitrary element in a list or set with brackets, as in the code myList[2].

  • You can add items to lists but you cannot remove them without iterating over the list.