0/5
## Initializing Smart Contracts: Understanding Vyper Constructors (`__init__`) When deploying a Vyper smart contract, you often need to set up its initial state. This could involve defining ownership, setting configuration parameters, or establishing starting values for key variables. This critical initialization step is handled by a special function known as the constructor. In Vyper, the constructor follows specific conventions derived from Python. It's a function named `__init__` (double underscore `init` double underscore) that must be decorated with the `@deploy` decorator. This decorator signals to the Vyper compiler that the `__init__` function contains the logic to be executed *only once*, precisely at the moment the contract is deployed onto the blockchain. After deployment, the constructor cannot be called again. ### Setting Initial State: The Owner Pattern One of the most common and crucial uses of a constructor is to establish the owner of the contract. Typically, the owner is the account address that initiates the deployment transaction. Vyper provides a global variable, `msg.sender`, which holds the address of the transaction originator. During deployment, `msg.sender` is the deployer's address. To implement this pattern, you first declare a state variable (usually public for easy verification) to store the owner's address. Then, within the `__init__` function, you assign `msg.sender` to this state variable using the `self` keyword, which refers to the contract's storage. ```vyper # pragma version ^0.4.0 # State variable to store the owner's address owner: public(address) # The constructor function @deploy def __init__(): # Assign the deployer's address to the 'owner' state variable # 'self' refers to the contract's storage space self.owner = msg.sender ``` When this contract is deployed, the `__init__` function executes automatically, setting the `owner` variable to the address that deployed the contract. ### Constructors with Parameters for Custom Initialization Constructors aren't limited to just using global variables like `msg.sender`. They can also accept parameters, allowing you to pass in custom values during the deployment process. This is essential for creating flexible and configurable contracts. These parameters are defined within the parentheses of the `__init__` function definition, just like any regular function. Deployment tools (like Remix) will typically detect these parameters and provide input fields for you to supply the required values when you deploy the contract. Let's extend our previous example to accept a `name` (as a string) and a `duration` (as an integer) to calculate an expiry timestamp. ```vyper # pragma version ^0.4.0 # State variables owner: public(address) name: public(String[100]) expiresAt: public(uint256) # Constructor accepting deployment parameters @deploy def __init__(name: String[100], duration: uint256): # Set the owner using the deployer's address self.owner = msg.sender # Set the name using the provided parameter self.name = name # Calculate the expiry timestamp # block.timestamp is a global variable representing the current block's timestamp self.expiresAt = block.timestamp + duration ``` In this example: 1. The `__init__` function now takes two arguments: `name` of type `String[100]` and `duration` of type `uint256`. 2. When deploying, you would need to provide values for both `name` and `duration`. 3. Inside the constructor, `self.owner` is set as before. 4. `self.name` is initialized with the `name` value passed during deployment. 5. `self.expiresAt` is calculated by taking the timestamp of the block in which the deployment occurs (`block.timestamp`) and adding the `duration` value provided during deployment. After deploying this contract with, for example, `name="Vyper"` and `duration=10`, you could query the public state variables and verify that `owner` is the deployer address, `name` is "Vyper", and `expiresAt` is the deployment `block.timestamp` plus 10 seconds. ### Practical Application: Initializing a Favorite Number Constructors are useful even for simple initialization tasks. Consider a contract designed to store a favorite number, which defaults to `0` if not explicitly set. If you want this number to start at `7` immediately upon deployment, you can use a parameter-less constructor. ```vyper # pragma version ^0.4.0 # State variable to store the favorite number my_favorite_number: public(uint256) # Intended initial value is 7 # Existing functions (e.g., to store or retrieve the number) # ... # Constructor to set the initial value @deploy def __init__(): # Initialize the favorite number to 7 upon deployment self.my_favorite_number = 7 ``` Before adding the constructor, querying `my_favorite_number` right after deployment would return `0`. After adding this `__init__` function, deploying the contract ensures that `my_favorite_number` is immediately set to `7`, demonstrating the constructor's role in overriding default zero-initialization. ### Key Takeaways * **Purpose:** Constructors (`__init__`) initialize a contract's state variables when it's deployed. * **Execution:** They run automatically and *only once* during the deployment transaction. * **Syntax:** Defined as `def __init__(...)` and must have the `@deploy` decorator. * **State Access:** Use the `self` keyword to access and modify state variables within the constructor (e.g., `self.owner = msg.sender`). * **Parameters:** Constructors can accept parameters to allow for customized initialization based on values provided at deployment time. * **Globals:** Commonly used global variables inside constructors include `msg.sender` (deployer address) and `block.timestamp` (deployment time). * **Default Values:** If a state variable isn't explicitly set in the constructor, it retains its default zero value (0, empty string, zero address, etc.). Understanding and utilizing the `__init__` constructor is fundamental to writing robust and correctly initialized Vyper smart contracts, ensuring they start operating with the intended state from the moment they exist on the blockchain.
__init__
)When deploying a Vyper smart contract, you often need to set up its initial state. This could involve defining ownership, setting configuration parameters, or establishing starting values for key variables. This critical initialization step is handled by a special function known as the constructor.
In Vyper, the constructor follows specific conventions derived from Python. It's a function named __init__
(double underscore init
double underscore) that must be decorated with the @deploy
decorator. This decorator signals to the Vyper compiler that the __init__
function contains the logic to be executed only once, precisely at the moment the contract is deployed onto the blockchain. After deployment, the constructor cannot be called again.
One of the most common and crucial uses of a constructor is to establish the owner of the contract. Typically, the owner is the account address that initiates the deployment transaction. Vyper provides a global variable, msg.sender
, which holds the address of the transaction originator. During deployment, msg.sender
is the deployer's address.
To implement this pattern, you first declare a state variable (usually public for easy verification) to store the owner's address. Then, within the __init__
function, you assign msg.sender
to this state variable using the self
keyword, which refers to the contract's storage.
When this contract is deployed, the __init__
function executes automatically, setting the owner
variable to the address that deployed the contract.
Constructors aren't limited to just using global variables like msg.sender
. They can also accept parameters, allowing you to pass in custom values during the deployment process. This is essential for creating flexible and configurable contracts.
These parameters are defined within the parentheses of the __init__
function definition, just like any regular function. Deployment tools (like Remix) will typically detect these parameters and provide input fields for you to supply the required values when you deploy the contract.
Let's extend our previous example to accept a name
(as a string) and a duration
(as an integer) to calculate an expiry timestamp.
In this example:
The __init__
function now takes two arguments: name
of type String[100]
and duration
of type uint256
.
When deploying, you would need to provide values for both name
and duration
.
Inside the constructor, self.owner
is set as before.
self.name
is initialized with the name
value passed during deployment.
self.expiresAt
is calculated by taking the timestamp of the block in which the deployment occurs (block.timestamp
) and adding the duration
value provided during deployment.
After deploying this contract with, for example, name="Vyper"
and duration=10
, you could query the public state variables and verify that owner
is the deployer address, name
is "Vyper", and expiresAt
is the deployment block.timestamp
plus 10 seconds.
Constructors are useful even for simple initialization tasks. Consider a contract designed to store a favorite number, which defaults to 0
if not explicitly set. If you want this number to start at 7
immediately upon deployment, you can use a parameter-less constructor.
Before adding the constructor, querying my_favorite_number
right after deployment would return 0
. After adding this __init__
function, deploying the contract ensures that my_favorite_number
is immediately set to 7
, demonstrating the constructor's role in overriding default zero-initialization.
Purpose: Constructors (__init__
) initialize a contract's state variables when it's deployed.
Execution: They run automatically and only once during the deployment transaction.
Syntax: Defined as def __init__(...)
and must have the @deploy
decorator.
State Access: Use the self
keyword to access and modify state variables within the constructor (e.g., self.owner = msg.sender
).
Parameters: Constructors can accept parameters to allow for customized initialization based on values provided at deployment time.
Globals: Commonly used global variables inside constructors include msg.sender
(deployer address) and block.timestamp
(deployment time).
Default Values: If a state variable isn't explicitly set in the constructor, it retains its default zero value (0, empty string, zero address, etc.).
Understanding and utilizing the __init__
constructor is fundamental to writing robust and correctly initialized Vyper smart contracts, ensuring they start operating with the intended state from the moment they exist on the blockchain.
A core introduction to Initializing Vyper Contracts with `__init__` - Explore how Vyper's constructor sets up initial state variables at deployment, using `msg.sender`, parameters, and the crucial `@deploy` decorator.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Course Overview
About the course
The basics of blockchain transactions, how to send and receive money on a blockchain network.
How to write Python based smart contracts using Vyper.
How to read and understand Vyper smart contracts.
Vyper data structures, arrays, structs, hash maps.
How to build a smart contract application and deploy on ZKsync with Moccasin.
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
On-chain Data Analyst
$59,000 - $139,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Last updated on June 11, 2025
Duration: 2h 08min
Duration: 2h 32min
Duration: 24min
Course Overview
About the course
The basics of blockchain transactions, how to send and receive money on a blockchain network.
How to write Python based smart contracts using Vyper.
How to read and understand Vyper smart contracts.
Vyper data structures, arrays, structs, hash maps.
How to build a smart contract application and deploy on ZKsync with Moccasin.
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
On-chain Data Analyst
$59,000 - $139,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Last updated on June 11, 2025