عملگر walrus در پایتون =: (walrus operator)

با سلام. توی این پست می خوام شما رو با یکی از از عملگر های جدید پایتون به نام walrus (معادل فارسیشو نمی دونم ولی تو دیکشنری که زدم، میگفت میشه شیرماهی) که در نسخه 3.8 به آن اضافه شده آشنا کنم.

این عملگر به این شکل نشون داده می شه ( =: ).

همه ما برخی اوقات با همچین موقعیت هایی مواجه میشیم

1234567m1 = p1.match(data)
m2 = p2.match(data)

if m1:
     pass
elif m2:
     pass

توی این برنامه، سعی می کنیم دو الگو رو روی data تست کنیم، هر کدوم که match شد کار های مربوط به اون رو انجام میدیم اما این برنامه زیاد بهینه نیست. چون ما دو تا الگو رو یک جا تست می کنیم و این مرحله برنامه رو کمی کند می کنه. اگه الگوی اول match بشه، دومی بلااستفاده می مونه. در نتیجه ما از m2 هیچ استفاده خاصی نکردیم و فقط زمان هدر دادیم. شاید بهتر بود که این برنامه رو اینطور پیاده سازی کنیم

1234567m1 = p1.match(data)
if m1:
    pass
else:
    m2 = p1.match(data)
    if m2:
        pass

در این برنامه در صورتی که الگوی اول match بشه، دیگه ما سراغ دومی نمیریم اما اگه نشد، اونوقت ما دومی رو تست می کنیم. شاید متوجه شده باشید که خیلی ساختار برنامه پیچیده شد. کد ها خوانایی کمتری نسبت به قبل دارند. و این دقیقا همون مشکلیه که می خواهیم با walrus حلش کنیم. با استفاده از این عملگر جدید می تونیم کد رو طوری بنویسیم که از اولش هم خوانا تر و سریع تر باشه

1234if m1 := p1.match(data):
    pass
elif m2 := p2.match(data):
    pass

نیازی به توضیح نیست، به راستی این است خوانایی پایتون!

اول از همه بزارید چند تا مثال دیگه برای استفاده از این عملگر بزنم که با ماهیت استفاده اش آشنا بشید بعد همه ی موارد استفاده و نحوه استفاده از این عملگر تو هر کدوم رو برسی می کنیم. حالا کد زیر رو در نظر بگیرید.

12variable = "value"
print (variable)

اما حالا پایتون 3.8 به شما این امکان رو میده تا این دو خط کد رو به یک خط کد تبدیل کنید

1print (variable := "value")

اگر این خط کد رو اجرا کنید، value چاپ میشه و مقدارش هم توی متغیر variable ذخیره میشه. بعد ها می تونید از همین variable دوباره استفاده کنید و نیازی به دوباره محاسبه کردن نیست. ( دقیقا همون کاری که در مثال قبلی انجام دادیم)

مثال بعدی: فرض کنید که برنامه ای دارید که آیتم هایی رو از کاربر به عنوان ورودی میگیره و اون رو به یک لیست (سبد خرید کاربر) اضافه می کنه. و وقتی که کاربر کلمه Q رو وارد می کنه، گرفتن ورودی رو متوقف می کنه.

123456shopping_cart = [] # initialize the list
while True:
      item = input ("enter an item to add: ")
      if item == "Q": break
      shopping_cart.append(item)
# the rest of code ...

خوب حالا این کد رو میشه اینطوری نوشت:

123shopping_cart = []
while (current := input("enter an item to add: ")) != "Q":
    shopping_cart.append(current)

خیلی بهتر شد مگه نه؟

دقیقا چیکار می کنه:

خوب اگه دقیقا می خواید از کارش سر دربیارید، خیلی ساده است، ترمینالتون رو باز کنید و وارد کنسول پایتون بشید. حالا این کد رو اجرا کنید

123>>>(a:=10)
out: 10
>>>

همین که این کد رو اجرا کنید میبینید که 10 رو به عنوان مقدار برگشتی دارید. یعنی اینکه این عبارت هم در a ذخیره می کنه و هم مقدارش رو بر میگردونه پس ما می تونیم از مقدار برگشتی به عنوان ورودی توابع و … استفاده کنیم و اگه دوباره نیاز به استفاده ازش داشتیم، به راحتی با استفاده از a به مقداری که قبلا حساب شده دسترسی داشته باشیم.

به طور کلی هر جا از این استفاده کنید هیچ اتفاق خاصی نمی افته به غیر از اینکه اون مقدار توی متغیر گفته شده (که در سمت چپ =: قرار داره) ذخیره میشه

مثلا:

برای شما
123456789def function(arg):
     return arg * 2

function( a:=10 )

def function2(arg, kwarg):
     # the rest of code goes here ...

function2(a:=10, kwarg = (b:=20))

در اینجا هیچ اتفاق خاصی نمی افته به غیر از اینکه مقادیر، هم به عنوان ورودی به تابع داده میشه و هم اینکه در یک متغیر که نامش قبلا داده شده (در سمت چپ =: قرار داره) ذخیره میشه. به غیر از این، همه چیز مثل قبل کار میکنه.

بعضی اوقات برخی از مقادیری که استفاده می کنیم حساب کردنشون سخته و برای اینکه برنامه از اینی که هست کند تر نشه باید فقط یک بار حسابش کنیم وگر نه دوبرابر برنامه مان کند تر میشه.

یکی از مهم ترین استفاده های این عملگر برای جلوگیری از این طور موقعیت هاست

نحوه نگارش (syntax):

شما می تونید توی خیلی از عبارت های پایتون از =: استفاده کنید، نحوه استفاده اش اکثرا به این شکله:

1(identifier := expr)

به طوری که identifier می تونه اسم یک متغیر باشه مثلا a، و expr هم می تونه هر گونه expression پایتون به غیر از tuple بدون پرانتز باشد. هر کجا که expression داشته باشید می تونید از =: استفاده کنید. مثلا:

1func( another_func(10, 20), 45) - 35

این یک expression محسوب میشه (هر کدی که منجر به تولید خروجی بشه، expression محسوب میشه، expression ها تقریبا همه جا وجود دارند)

خیلی خوب این هم از نحوه استفاده اش در موقعیت های مختلف:

12345678910111213# conditional statements
if  identifier := f(x) :
    pass #something

# using with while statements
while chunck := file.read(1024):
    socket.send(chunck)

# reuse a value which is expensive to compute
numbers =[ (y:=f(x)) , y ** 2, y ** 3]

# create a subsequence by filtering out some items
new_numbers = [ y for x in numbers if (y:= SomeFilter(x)) is not None ]

در برخی موارد می تونید از =: بدون پرانتز اطرافش استفاده کنید، مثل عبارت های شرطی، یا حلقه while اما برخی اوقات باید بین پرانتز قرارش بدید که در ادامه توضیح میدم.

  • استفاده از =: در قسمت top level کد (قسمت اصلی کد، بدون اینکه عضوی از یک statement باشه) بدون استفاده از پرانتز اشتباهه
12>>> a := 10 # invalid
>>> (a := 10) # valid
  • همچنین استفاده از این عبارات در سمت راست یک عبارت بدون پرانتز ممنوعه
12c = a := 10 # completely invalid
c = ( a := 10) # valid but not so useful
  • استفاده از این عبارات موقع اختصاص مقادیر به توابع به صورت کلید/مقدار (key/value)، یا همون keyword argument بدون استفاده از پرانتز ممنوعه
12Function(kwarg = c:=10) # invalid
Function(kwarg = (c:=10)) # valid
  • استفاده از این عبارات هنگام تعیین مقادیر پیشفرض برای پارامتر های توابع، باز هم بدون استفاده از پرانتز ممنوعه
12def Function( argument = c := "default value"): pass # invalid
def Function( argument = ( c := "default value" )): pass # valid

استفاده از این عبارات به عنوان annotation ، بدون پرانتز ممنوعه

12def s( a: c:=10 = 20): pass # invalid
def s( a: (c:=10) = 20): pass #valid
  • استفاده از این عبارات در توابعی که به صورت lambda تعریف شده اند، بدون پرانتز اشتباهه
1234(lambda: x := 1) # INVALID
lambda: (x := 1) # Valid, but unlikely to be useful
(x := lambda: 1) # Valid
lambda line: (m := re.match(pattern, line)) and m.group(1) # Valid
  • هنگام استفاده از این عبارت در fstring ها باید از پرانتز استفاده شود
1f"{(x:=2)}" # valid

این عبارت درسته و مقدار 2 رو در x ذخیره می کنه

12x = "Hello"
f"{x:=10}" # valid

این عبارت هم از لحاظ symtax درسته اما = رو به formatter میده و نتیجه اونطوری که ما می خواهیم نیست، ارور میگیریم!


خوب، دونستن اینها تا به اینجا کافیه و حالا می تونید از این عملگر در برنامه های پایتونی تون استفاده کنید.

ولی اگر خیلی دوست دارید راجب این عملگر اطلاعات بیشتری کسب کنید، به منبع این مطلب یعنی pep 572 سری بزنید.

نویسنده مطلب: اشکان محمدی

منبع مطلب

به فکر سرمایه‌گذاری هستی؟

با هر سطحی از دانش در سریع‌ترین زمان با آموزش گام به گام، سرمایه گذاری را تجربه کن. همین الان میتونی با لینک زیر ثبت نام کنی و ۱۰ درصد تخفیف در کارمزد معاملاتی داشته باشی

ثبت نام و دریافت جایزه
ممکن است شما بپسندید
نظر شما درباره این مطلب

آدرس ایمیل شما منتشر نخواهد شد.