Vyper: برای حلقه ها و آرایه ها.

Vyper یک زبان پایتونیک است اما از آرایه ها یا رشته های پویا به اندازه پایتون پشتیبانی نمی کند. بنابراین، اگر کسی بخواهد با آنها بازی کند، دستورالعمل های خاصی وجود دارد که باید از آنها پیروی کرد for loops
و arrays
. در این آموزش، ما قصد داریم از مثال هایی برای درک بهتر نحوه کار کردن چیزها استفاده کنیم.
@external
def iterate_array_variable() -> int128:
marks: int128[4] = [45, 67, 90, 36]
result: int128[4] = [0, 0, 0, 0]
for x in range(4):
result[x] = marks[x] * 2
return result[2]
در مثال بالا یک تابع تعریف می کنیم iterate_array_variable
که یک متغیر از نوع را برمی گرداند int128
. سپس یک آرایه تعریف می کنیم marks
که باید حاوی 4
تحت اللفظی نوع int128
. result
همچنین یک آرایه است که دقیقاً مانند تعریف شده است marks
. تنها تفاوت آنها مقادیر موجود در این دو آرایه است [45, 67, 90, 36]
و [0, 0, 0, 0]
. هدف این تابع، دادن مقادیر جدید به آرایه نتیجه است result[x] = marks[x] * 2
.
ما انتظار داریم که تابع به را برگرداند result
برای داشتن یک مقدار جدید برای هر تکرار انجام شده. به عنوان مثال، در موقعیت سوم (result[2]
، مقدار باید از تغییر کند 0
به 180
تعامل با قرارداد
import sys
from web3 import Web3
# Connect to BSC node (Binance Smart Chain)
bsc_node_url = 'https://data-seed-prebsc-1-s1.binance.org:8545/' # Replace with your BSC node URL
web3 = Web3(Web3.HTTPProvider(bsc_node_url))
# Set the private key directly (For demonstration purposes only, do not hardcode in production)
private_key = 'Your_private_key' # Replace with your actual private key
account = web3.eth.account.from_key(private_key)
# Contract ABI
contract_abi = [
Your_abi
]
# Contract address
contract_address = web3.to_checksum_address('your_contract_address') # Replace with your contract's address
# Create contract instance
contract = web3.eth.contract(address=contract_address, abi=contract_abi)
# Function to set a choice
def call_iterate_array_variable():
nonce = web3.eth.get_transaction_count(account.address)
tx = contract.functions.iterate_array_variable().build_transaction({
'chainId': 97, # BSC testnet
'gas': 3000000,
'gasPrice': web3.to_wei('5', 'gwei'),
'nonce': nonce,
})
signed_tx = web3.eth.account.sign_transaction(tx, private_key)
tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
result = contract.functions.iterate_array_variable().call()
return result
def main():
result = call_iterate_array_variable()
print(f'Result of the calculation: {result}')
if __name__ == "__main__":
main()
نتیجه
تکرار از طریق مقادیر یک متغیر آرایه
y: public(int128)
@external
def iterate_array_variable() -> int128:
marks: int128[4] = [45, 67, 90, 36]
for x in marks:
self.y = x
return self.y
در مثال بالا، ما مقادیر متغیر را تکرار می کنیم marks
. انتظار داریم تابع برگردد 36
زیرا آخرین مقداری خواهد بود که به آن اختصاص داده شده است y
بعد از تکرار
ممکن است کسی بپرسد، اگر بخواهیم مقدار معینی را از چنین آرایه ای برگردانیم، چه؟ پاسخ در نهفته است assert
عبارتی که برای عملیات بولی استفاده می شود.
y: public(int128)
@external
def get_mark(index: int128) -> int128:
marks: int128[4] = [45, 67, 90, 36]
assert 0 <= index, "Index out of lower limit"
assert index < 4, "Index out of upper limit"
self.y = marks[index]
return self.y
در مثال بالا، کاملاً مشهود است که میتوانیم به صراحت مقداری را که میخواهیم به آن دسترسی داشته باشیم، با ارائه اندیس آن مقدار از یک آرایه تعیین کنیم. assert 0 <= 4
اطمینان حاصل می کند که شاخص بزرگتر یا مساوی صفر است. در غیر این صورت اجرای قرارداد خواهد بود برگردانده شد با پیام خطای “ایندکس از حد پایین تر” assert index < 4
رفتاری مشابه اما با منطق متفاوت دارد.
تعامل با قرارداد
from web3 import web3
"""
.......
......
Other code here
......
....
"""
# Create contract instance
contract = web3.eth.contract(address=contract_address, abi=contract_abi)
# Function to set a choice
def call_get_mark(index):
nonce = web3.eth.get_transaction_count(account.address)
tx = contract.functions.get_mark(index).build_transaction({
'chainId': 97, # BSC testnet
'gas': 3000000,
'gasPrice': web3.to_wei('5', 'gwei'),
'nonce': nonce,
})
signed_tx = web3.eth.account.sign_transaction(tx, private_key)
tx_hash = web3.eth.send_raw_transaction(signed_tx.rawTransaction)
receipt = web3.eth.wait_for_transaction_receipt(tx_hash)
result = contract.functions.get_mark(index).call()
return result
def main():
index = int(input("Enter the index (0 to 3): "))
result = call_get_mark(index)
print(f'Result of the calculation: {result}')
if __name__ == "__main__":
main()
همچنین می توانیم روی یک آرایه تحت اللفظی تکرار کنیم:
# declaring variable y
y: public(int128)
@external
def non_dictated() -> int128:
for x in [34, 76, 89, 45]:
self.y = x
return self.y
کد بالا باز خواهد گشت 45
زیرا آخرین مقداری است که در متغیر ذخیره می شود y
.
تکرار محدوده
در همان ابتدای این مقاله، یک مورد کاربری از محدوده را دیدیم، for x in range(4):
. محدوده ها با استفاده از range
تابع. مثال بالا از یک ساختار پیروی می کند. for i in range(STOP):
جایی که STOP
یک عدد صحیح واقعی بزرگتر از صفر است.
استفاده دیگر از محدوده می تواند با START
و STOP
محدوده
for i in range(START, STOP):
...
اینجا، START
و STOP
اعداد صحیح تحت اللفظی هستند، با STOP
ارزشی بیشتر از START
. i
آغاز می شود به عنوان START
و یک افزایش می یابد تا برابر شود STOP
.
مثال
@external
def iterate_array_variable() -> int128:
marks: int128[4] = [45, 67, 90, 36]
result: int128[4] = [0, 0, 0, 0]
for x in range(1, 2):
result[x] = marks[x] * 2
return result[3]
در هنگام اجرا، کد بالا با خطای شاخص مشخص شده توسط result[3]
، جایگاه چهارم، از دامنه دو موقعیت از رتبه دوم تا سوم فراتر می رود.
مثال مهم دیگر این است که؛
for i in range(stop, bound=N):
...
در اینجا، stop می تواند یک متغیر با نوع عدد صحیح، بزرگتر از صفر باشد. N باید یک ثابت زمان کامپایل باشد. i به صورت صفر شروع می شود و یک افزایش می یابد تا زمانی که برابر با توقف شود. اگر توقف بزرگتر از N باشد، اجرا در زمان اجرا برمی گردد. در موارد خاص، ممکن است تضمینی نداشته باشید که توقف کمتر از N است، اما همچنان می خواهید از احتمال بازگشت زمان اجرا جلوگیری کنید. برای انجام این کار، از
bound=
کلمه کلیدی در ترکیب باmin(stop, N)
به عنوان آرگومان محدوده، مانندrange(min(stop, N), bound=N)
. این برای موارد استفاده مانند تقسیم کردن عملیات در آرایه های بزرگتر در چندین تراکنش مفید است.
برای درک بهتر این موضوع، ابتدا باید درک کنیم ثابت زمان کامپایل و بازگشت زمان اجرا.
بازگشت زمان اجرا به رفتار قرارداد در هنگام مواجهه با خطا در حین اجرا اشاره دارد. اگر شرطی در قرارداد محقق نشود یا استثناء شود، عقد به حالت قبلی قبل از معامله باز می گردد. این تضمین می کند که هیچ تغییر جزئی یا اشتباهی در وضعیت بلاک چین ایجاد نمی شود. به عنوان مثال، استفاده از عبارات assert یا require میتواند در صورت عدم موفقیت شرط، باعث بازگشت مجدد شود.
# compile-time constant
MAX_SUPPLY: constant(uint256) = 1000000
# if amount is not greater than zero,
# the transaction will revert at runtime,
# ensuring the contract state remains unchanged.
@external
def transfer(amount: uint256):
assert amount > 0, "Amount must be greater than zero"
# transfer logic
ما قصد داریم از چهار مثال زیر استفاده کنیم تا به طور کامل بفهمیم که چگونه می توان از محدوده به این روش استفاده کرد. در هر دو مثال، ثابت زمانی کامپایل N
است 4
. آنچه تغییر می کند این است stop
ارزش. جفت اول دارای مقدار توقف است 2
و دیگری دارای مقدار توقف است 84
.
جفت اول
latest_index: public(int128)
N: constant(int128) = 4 # compile time constant
@external
def process_chunk() -> int128:
for i in range(2, bound=N):
self.latest_index = i
return self.latest_index
latest_index: public(int128)
N: constant(int128) = 4 # compile time constant
@external
def process_chunk() -> int128:
for i in range(min(2, N), bound=N):
self.latest_index = i
return self.latest_index
وقتی دو قرارداد فوق را اجرا می کنیم، latest_index
مقدار برگشتی است 1
.
جفت دوم
latest_index: public(int128)
N: constant(int128) = 4 # compile time constant
@external
def process_chunk() -> int128:
for i in range(84, bound=N):
self.latest_index = i
return self.latest_index
latest_index: public(int128)
N: constant(int128) = 4 # compile time constant
@external
def process_chunk() -> int128:
for i in range(min(84, N), bound=N):
self.latest_index = i
return self.latest_index
وقتی اولین قرارداد را در این جفت اجرا می کنیم، a را می اندازد ContractLogicError: Execution Reverted
.
با این حال، آخرین قرارداد مقدار last_index را برمی گرداند 3
هنگام اجرا
توضیح
در اولین جفت مثال، ما 1 را به عنوان مقدار بازگشتی دریافت می کنیم، فقط به این دلیل stop
مقدار از ثابت تجاوز نمی کند N
.
در جفت دوم، میتوانیم ببینیم که در جایی که مثال دوم به خوبی کامپایل میشود، با خطا مواجه میشویم. دلیل این امر استفاده از min(stop, N)
به عنوان یک استدلال به سادگی مقدار توقف را نسبت به مقدار به حداقل می رساند N
ارائه شده است. بنابراین، حداقل مقدار ممکن از stop
در این صورت خواهد بود 4
از این رو مقدار شاخص را برمی گرداند 3
.
برای اطلاعات بیشتر، لطفاً از مستندات رسمی vyper دیدن کنید و همچنین مقاله قبلی خود را برای درک عمیق تر vyperlang توصیه می کنم. اگر این مقاله برای شما مفید بود، خوشحال می شوم اگر به من قلب بدهید. برای ادامه مطلب فالو کنید متشکرم!