چند syntax و keyword پایتون که احتمالا نمیدونستید!

چند syntax و keyword پایتون که احتمالا نمیدونستید!

یه سری سینتکس توی پایتون هست که به نسبت کمتر دیده میشن ویا جدیدتر هستن. ممکن هم هست که توی دوره‌های آموزشی، بعنوان بخش پیشرفته آموزش حساب کنن و همون اول دربارش توضیح ندن. بطور کلی دلایل زیادی میتونه براش وجود داشته باشه. پیشنهاد میشه توی هر مورد، نمونه‌هارو اجرا کنید:) چند تا چیز کاربردی‌تر رو هم میتونید اینجا ببینید: https://virgool.io/CodeLovers/%DA%86%D9%86%D8%AF-%DA%86%DB%8C%D8%B2-%D8%AF%D8%B1-%D9%BE%D8%A7%DB%8C%D8%AA%D9%88%D9%86-%DA%A9%D9%87-%D9%87%D9%85%DB%8C%D8%B4%D9%87-%D9%87%D9%85%D8%B1%D8%A7%D9%87-%D9%85%D9%86%D9%87-gxxgtoaa1lpu اکثریت میدونیم که کاربرد اصلی کلمه کلیدی else توی نوشتن شرط‌ها بکار میره: if <condition>:
<code>
elif <condition>:
<code>
else:
<code>اما… جز این هم هست! یکی توی حلقه for. کاربردش اینه که اگه حلقه بطور کامل روی همه اعضای iterable مورد نظر رفت، فرورفتگی داخل خودش رو اجرا کنه. این وقفه معمولا وقتی هست که break توی حلقه اجرا بشه (برای این از لفظ «معمولا» استفاده کردم، چون فقط و فقط این نیست. مثلا اگه به ارور بخوره، یا مثلا توی تابع به return برسه و …):for x in range(10):
print(&quotx =&quot,x)
else:
print(&quotfinished!&quot)
# output: 0 1 2 3 4 …. 8 9 finished!

for x in range(10):
print(&quotx =&quot,x)
if x == 5: break
else:
print(&quotyou won’t see me again!&quot)
# output: 0 1 2 3 4 5مورد بعدی هم توی Error Handling هست. اگه کد داخل فرورفتگی try بدون ارور اجرا بشه، else هم در اخر کار خودش رو میکنه. اگر هم به ارور برسه، بلوک except برخلاف else اجرا میشه. فرقش با finally اینه که finally در هر صورت (یعنی چه به ارور رِسی و چه مَرِسی!) اجرا میشه در اخر. توی مثال زیر، کد اول به ترتیب try و else و finally اجرا میشه؛ اما توی کد دوم، try و except و finally:try:
print(&quot1 / 2 is:&quot)
print(1/2)
except Exception as err:
print(&quotoops! we got an error:&quot,err)
else:
print(&quotyes! it is done completely&quot)
finally:
print(&quotand… nothing! just an output&quot)
# output:
# 1 / 2 is:
# 0.5
# yes! it is done completely
# and… nothing! just an output

try:
print(&quot1 / 0 is:&quot)
print(1/0)
except Exception as err:
print(&quotoops! we got an error:&quot,err)
else:
print(&quotyes! it is done completely&quot)
finally:
print(&quotand… nothing! just an output&quot)
# output:
# 1 / 0 is:
# oops! we got an error: division by zero
# and… nothing! just an outputمطمئنا با حلقه for اشنا هستید. گاهی نوشتن حلقه for زیاد جالب نیست:) این توی موارد کوتاه دیده میشه، مثلا شما میخواید رشته‌هایی با طول بزرگتر از 4 رو از یه لیست جدا کنید (با حلقه for):words = [&quotif&quot, &quotelif&quot, &quotexcept&quot, &quotwhile&quot, &quotglobal&quot, &quotdef&quot, &quotyield&quot]
outs = []
for x in words:
if len(x) > 4:
outs.append(x) خب، پایتون برای این هم یه فکری کرده:) بله، list comprehension برای همین‌جور کارها بوجود اومده. مثلا برای همون مثالی که گفتم:words = [&quotif&quot, &quotelif&quot, &quotexcept&quot, &quotwhile&quot, &quotglobal&quot, &quotdef&quot, &quotyield&quot]
outs = [x for x in words if len(x) > 4]در واقع یه list comprehension ترکیبی از یه لیست (یا generator، اگه از پرانتز استفاده کنید) و یه حلقه for هست، که میتونه حالا شرط‌هارو هم توی خودش داشته باشه. البته میشه if-else رو هم بکار برد:) اگه توی مثال قبلی بخوایم بجای هر رشته‌ای که طولش بزرگتر از ۴ نبود یه رشته خالی بزاریم:outs = [(x if len(x) > 4 else &quot&quot) for x in words]دقت کنید که نمیتونیم else رو بعد از نوشتن for بکار ببریم (چرا؟). البته همونطور که اولش گفتم، توی مواردی که روش حل مسئله یکسانه، استفاده از list comprehension بهینه‌تره (یه مثال از تست سرعتشون با استفاده از timeit روی متد join رو اینجا ببینید). این عکس معادل‌سازی خیلی خوبی انجام داده:معادل‌سازی با حلقه forاگه تا الان فکر می‌کردید lambda همون تابع تعریف‌شده با def هستش، سخت در اشتباه بودید:) بله، اگرچه شبیه به همدیگه هستند؛ اما در حقیقت با هم فرق دارن. البته چون کاربرد مشابه تابع داره، ازش به عنوان anonymous function هم یاد میکنن:) توضیح پایتون رو ببینیم:lambda_expr ::= “lambda” [parameter_list] “:” expressionlambda_expr_nocond ::= “lambda” [parameter_list] “:” expression_nocondLambda expressions (sometimes called lambda forms) are used to create anonymous functions. The expression “lambda parameters: expression” yields a function object. The unnamed object behaves like a functionobject defined with:def <lambda>(parameters):return expressionSee section Function definitions for the syntax of parameter lists.Note that functions created with lambda expressions cannot contain statements or annotations.میبینیم که از لفظ expression استفاده کرده، و در ادامه اون رو anonymous function تعریف کرده. حقیقت اینه که تابع (که با def تعریف میشه)، اولا یه هویت مشخص داره و ثانیا که هدف اصلیش اجرای یه بلوک کد هست، اما lambda هویت مشخص نداره (برای همین بهش anonymous function هم میگن) و در واقع میاد حاصل یه عبارت رو بجاش میزاره (یا شاید عین همون عبارت رو میزاره بعد حساب میکنه مقدار رو، اینو منم نمیدونم(: به قولی: اگرچه راه‌ها فرق دارند، مقصد یکی است!). درباره کلمه هویت، این رو ببینید مثلا:>>> def f(x):
… return x*2

>>> f
<function f at 0x7f6ea5697840>
>>> f.__name__
‘f’
>>> f = lambda x:x*2
>>> f
<function <lambda> at 0x7f6ea569a158>
>>> f.__name__
‘<lambda>’فکر کنم واضحه دیگه:)اینو خودمم همیشه یادم میره چیه:) بنابراین، سَرَکی می‌کشیم به help خودش بازم:The “nonlocal” statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals. This is important because the default behavior for binding is to search the local namespace first. The statement allows encapsulated code to rebind variables outside of the local scope besides the global (module) scope.Names listed in a “nonlocal” statement, unlike those listed in a “global” statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined unambiguously).Names listed in a “nonlocal” statement must not collide with pre-existing bindings in the local scope.خب، اینجور که بنظر میاد شبیه global هست. کاربردش اینه که اگه شما متغیری دارید که توی فرورفتگی(های) قبلی بکار رفته و میخواید توی فرورفتگی داخلی ازش استفاده کنید، بدون nonlocal نمیتونید مقدارش رو عوض کنید. سینتکسش مثل global هست. این مثال رو (با کمی تغییر روی مثال w3school) ببینید:def myfunc1():
x = &quotJohn&quot
def myfunc2():
def myfunc3():
nonlocal x
x = &quothello&quot
myfunc3()
myfunc2()
return x
print(myfunc1())حالا، بدون اون nonlocal (توی خط پنجم) چی میشه؟:) بله، مقدارش عوض نمیشه و رشته John داده میشه. البته اونجوری که من دیدم، نمیشه برای عوض کردن یه متغیر global ازش استفاده کرد (SyntaxError میگیرید) و باید از global استفاده کنید (وگرنه چرا global بوجود اومد(: )فکر کنم بهترین کاربردش همینه. در واقع ممکنه بعضی اسامی هنگام import کردن جالب بنظر نیان. این کارش همینه که اگه خواستید اسم دیگه‌ای برای تابع یا ماژول توی برنامه بزارید. مثلا یکی از مواردی که خودم چندبار استفاده کردم:from os.path import join as join_pathیعنی بجای اینکه تابع با اسم join توی برنامه باشه، به اسم join_path هست. دقت کنید این فقط برای راحتی توی نوشتنه، وگرنه پایتون همونطوری میشناستش:>>> from os.path import join as join_path
>>> join_path.__name__
‘join’برای اینکه ارور رو توی یه متغیر بریزه. ارور هم که از نوع Exception هست. مثلا:try:
print(1/0)
except Exception as err:
print(type(err), err)البته بجای Exception میتونی ارور(های) دیگه هم بزارید (مثلا اینجا: ZeroDivisionError).مستقیما میریم سراغ مثال معروف:)with open(&quotpath/to/file&quot, ‘w’) as f:
f.write(&quotsomething here&quot)والا من تعریف دقیقی براتون ندارم:) دعوتتون میکنم به تعریف سایت learnpython:Generators are very easy to implement, but a bit difficult to understand.Generators are used to create iterators, but with a different approach. Generators are simple functions which return an iterable set of items, one at a time, in a special way.When an iteration over a set of item starts using the for statement, the generator is run. Once the generator’s function code reaches a “yield” statement, the generator yields its execution back to the for loop, returning a new value from the set. The generator function can generate as many values (possibly infinite) as it wants, yielding each one in its turn.اگه متوجه نشدید، نگران نباشید! به کد زیر نگاه کنید:def get(a,b):
n = a
while n <= b:
print(&quotnumber is&quot,n)
yield n
n += 1

numbers = get(10,20)حالا numbers چیه؟<generator object get at 0x7f……..a0>خب، الان با numbers چه میشه کرد؟ این حالت رو ببینید:for number in numbers:
print(&quotnow, we’re in loop:&quot,number)
# output:
# number is 10
# now, we’re in loop: 10
# number is 11
# now, we’re in loop: 11
# …
# number is 20
# now, we’re in loop: 20خب، حالا فرقش چیه با لیست؟ اینکه همون اول همه رو نمیریزه توی یه چیزی مثل لیست (بلکه توی هر دور از حلقه مقدار بعدی رو میگیره). البته لیست مقادیر رو نگه میداره یجا؛ اما generator دیگه وقتی بره جلو برنمی‌گرده عقب:) در واقع، هربار توی حلقه میاد next میکنه. ببینید (فرض کنید حلقه رو روی numbers اعمال نکردیم):>>> next(numbers)
10
>>> next(numbers)
11

>>> next(numbers)
19
>>> next(numbers)
20
>>> next(numbers)
Traceback (most recent call last):
File &quot<stdin>&quot, line 1, in <module>
StopIterationعه! چیشد؟ بله، دیگه چیزی نمونده که توسط next داده بشه:) یه سینتکس ساده‌تر هم براش هست، شبیه list comprehension، تفاوتش هم مثل همونه تقریبا:(x for x in range(20) if x%2==0)بله، کارش هم همینه که فقط فضا پر کنه:) باور ندارید؟ پس اگه تونستید کد زیر رو اجرا کنید:def f():

f()چرا توی f چیزی ننوشتیم؟ سوال خوبیه که جواب قطعی نداره:) در کل میتونید این فرورفتگی‌های خالی رو با pass پر کنید:def f():
pass
f()شما هم اگه چیزی به ذهنتون رسید حتما بگید:)‌ و … به امید روزی که ویرگول یه Syntax Highlighting بزاره!

منبع

Author: admin

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *