مباحث بیشتر

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

جا به جایی تاپل ها

آیا تاکنون آرزو کرده اید که بتوانید دو مقدار متفاوت را از یک تابع باز گردانید؟این کار امکان پذیر است. تنها کاری که باید انجام دهید، استفاده از یک تاپل است.

>>> def get_error_details():
...     return (2, 'details')
...
>>> errnum, errstr = get_error_details()
>>> errnum
2
>>> errstr
'details'

توجه کنید که استفاده از عبارت <a,b = <some expression نتیجۀ عبارت را به صورت یک تاپل شامل دو مقدار تفسیر می کند.

این موضوع همچنین به این معناست که سریع ترین روش برای جا به جا کردن مقدار دو متغیر در پایتون به صورت زیر است:

>>> a = 5; b = 8
>>> a, b
(5, 8)
>>> a, b = b, a
>>> a, b
(8, 5)

روش های ویژه

روش های ویژه ای وجود دارد مانند __init__ و __del__ که در کلاس ها از اهمیت خاصی برخوردار هستند.

از روش های ویژه برای شبیه سازی انواع داده های داخلی استفاده می شود. برای مثال، اگر بخواهید عملیات نمایه گذاری به شکل x[key] را برای کلاس خود نیز استفاده کنید (همانطور که برای لیست ها و تاپل ها به کار می برید) کافیست روش ()__getitem__ را پیاده سازی کنید و کار تمام است. اگر کمی دربارۀ این موضوع فکر کنید، متوجه می شوید که پایتون نیز همین کار را برای کلاس list انجام می دهد!

برخی از روش های ویژۀ مفید در جدول زیر فهرست شده اند. اگر می خواهید دربارۀ تمام روش های ویژه اطلاعات به دست آورید، به راهنمای رسمی مراجعه کنید.

  • __init__(self, ...)

    • این روش درست پیش از آنکه شئ جدید ایجاد شده برای استفاده باز گردانده شود، فراخوانی می شود.
  • __del__(self)

    • درست پیش از نابود شدن شئ فراخوانی می شود (زمان وقوع این رویداد غیر قابل پیش بینی است؛ پس از استفاده از آن اجتناب کنید).
  • __str__(self)

    • هنگامی که از تابع print یا تابع ()str استفاده می کنیم، فراخوانی می شود.
  • __lt__(self, other)

    • هنگامی که از عملگر کوچکتر از (<) استفاده می شود، فراخوانی می شود. به طور مشابه، برای تمام عملگر ها (+و>و غیره) نیز روش های ویژه ای وجود دارد.
  • __getitem__(self, key)

    • هنگامی که از عملیات نمایه گذاری x[key] استفاده می شود، فراخوانی می شود.
  • __len__(self)

    • هنگامی که تابع داخلی ()len برای یک شئ دنباله ای استفاده می شود، فراخوانی می شود.

بلوک های تک دستوری

دیدیم که هر بلوک از دستورات با سطح تورفتگی مختص خود از دیگر بخش ها جدا می شود. البته در اینجا یک استثنا وجود دارد. اگر بلوک دستورات شما تنها شامل یک دستور باشد، می توانید آن را در همان خط یک دستور شرطی یا حلقه ای قرار دهید. مثال زیر این موضوع را روشن می کند:

>>> flag = True
>>> if flag: print('Yes')
...
Yes

توجه داشته باشید که دستور منفرد در همان محل نوشته شده و به عنوان یک بلوک جدا ارائه نشده است. اگرچه می توانید از این روش برای کوتاه تر کردن برنامه خود استفاده کنید؛ اکیداً توصیه می کنم از این روش میان بر مگر برای بررسی خطا، اجتناب کنید؛ زیرا اگر از تورفتگی مناسب استفاده کنید، افزودن یک دستور دیگر بسیار آسان تر خواهد بود.

فرم های لامبدا (Lambda Forms)

یک دستور lambda برای ایجاد اشیای تابع جدید استفاده می شود. در اصل، lambda یک پارامتر را دریافت می کند و سپس یک عبارت منفرد در اختیار آن قرار می گیرد. لامبدا بدنۀ تابع را تشکیل می دهد. مقدار این عبارت توسط تابع جدید باز گردانده می شود.

مثال را با نام more_lambda.py ذخیره کنید:

points = [{'x': 2, 'y': 3},
          {'x': 4, 'y': 1}]
points.sort(key=lambda i: i['y'])
print(points)

خروجی:

$ python more_lambda.py
[{'y': 1, 'x': 4}, {'y': 3, 'x': 2}]

نحوۀ عملکرد

توجه داشته باشید که روش sort از یک list می تواند پارامتر key را دریافت کند که تعیین می کند لیست چگونه مرتب شود (معمولاً فقط با ترتیب صعودی و نزولی آشنا هستیم). در مثال، ما می خواهیم یک مرتب سازی سفارشی (custom sort) انجام دهیم و برای این کار به نوشتن یک تابع نیاز داریم. به جای نوشتن یک بلوک جداگانۀ def برای تابع که تنها در همین مکان مورد استفاده قرار خواهد گرفت، از عبارت لامبدا برای ایجاد یک تابع جدید استفاده می کنیم.

درک لیستی (List Comprehension)

از درک لیستی برای ایجاد یک لیست جدید از روی یک لیست موجود استفاده می کنیم. فرض کنید لیستی از اعداد در اختیار دارید و می خواهید لیستی متناظر ایجاد کنید که تنها اعدادی که خودشان از 2 بزرگ تر هستند، در 2 ضرب شوند. درک لیستی در چنین موقعیت هایی ایده آل است.

مثال را تحت عنوان more_list_comprehension.py ذخیره کنید:

listone = [2, 3, 4]
listtwo = [2*i for i in listone if i > 2]
print(listtwo)

خروجی:

$ python more_list_comprehension.py
[6, 8]

نحوۀ عملکرد

در اینجا، با مشخص کردن عملیاتی که باید انجام شود (2*i) هنگامی که شرط خاصی مشخص شده باشد (if i>2)، یک لیست جدید ایجاد می کنیم. توجه داشته باشید که لیست اصلی بدون تغییر باقی می ماند.

مزیت استفاده از درک لیستی این است که مقدار کدهای تکراری و اضافی موردنیاز هنگام استفاده از حلقه ها برای پردازش هر عنصر لیست و ذخیره آن در لیستی جدید را کاهش می دهد.

دریافت تاپل ها و دیکشنری ها در توابع

روش ویژه ای برای دریافت پارامترهای یک تابع به صورت یک تاپل و دیکشنری وجود دارد که به ترتیب با استفاده از پیشوندهای * یا ** انجام می شود. این روش هنگام دریافت تعداد متغیری از آرگومان ها در یک تابع مفید است.

>>> def powersum(power, *args):
...     '''Return the sum of each argument raised to the specified power.'''
...     total = 0
...     for i in args:
...         total += pow(i, power)
...     return total
...
>>> powersum(2, 3, 4)
25
>>> powersum(2, 10)
100

از آنجا که متغیر args دارای پیشوند * است، تمام آرگومان های اضافی که به تابع ارسال می شوند، در args به صورت یک تاپل ذخیره می شوند. اگر به جای آن از پیشوند ** استفاده می شد، پارامترهای اضافی به عنوان جفت های کلید/مقدار یک دیکشنری در نظر گرفته می شدند.

دستور assert

از دستور assert برای تایید درست بودن چیزی استفاده می شود. برای مثال، اگر کاملاً مطمئن هستید که لیستی که استفاده می کنید حداقل یک عنصر خواهد داشت و می خواهید این را بررسی کنید و در صورتی که درست نباشد، یک خطا دریافت کنید؛ در این شرایط دستور assert گزینۀ مناسبی است. هنگامی که دستور assert برقرار نباشد، یک AssertionError ایجاد می شود.

روش ()pop آخرین عنصر موجود در لیست را حذف کرده و همان عنصر را باز می گرداند.

>>> mylist = ['item']
>>> assert len(mylist) >= 1
>>> mylist.pop()
'item'
>>> assert len(mylist) >= 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

دستور assert باید با احتیاط و سنجیده استفاده شود. در بیشتر مواقع، بهتر است استثناها را دریافت کنید، مشکل را کنترل کنید یا یک پیام خطا به کاربر نمایش دهید و برنامه را به پایان برسانید.

دکوراتورها (Decorators)

دکوراتورها روشی میان بر برای اعمال توابع پوشاننده هستند. این قابلیت زمانی مفید واقع می شود که بخواهیم یک عملکرد مشخصی را بارها و بارها با استفاده از یک کد یکسان «پوشش» دهیم. برای مثال، من دکوراتور retry را برای خودم ایجاد کردم که می توانم آن را روی هر تابعی اعمال کنم. اگر هنگام اجرا استثنایی رخ دهد، تابع دوباره اجرا می شود تا حداکثر 5 دفعه، و بین هربار تلاش نیز یک وقفه وجود دارد. این قابلیت به ویژه در موقعیت هایی مفید است که قصد دارید یک درخواست شبکه ای به یک رایانۀ راه دور ارسال کنید:

from time import sleep
from functools import wraps
import logging
logging.basicConfig()
log = logging.getLogger("retry")


def retry(f):
    @wraps(f)
    def wrapper_function(*args, **kwargs):
        MAX_ATTEMPTS = 5
        for attempt in range(1, MAX_ATTEMPTS + 1):
            try:
                return f(*args, **kwargs)
            except Exception:
                log.exception("Attempt %s/%s failed : %s",
                              attempt,
                              MAX_ATTEMPTS,
                              (args, kwargs))
                sleep(10 * attempt)
        log.critical("All %s attempts failed : %s",
                     MAX_ATTEMPTS,
                     (args, kwargs))
    return wrapper_function


counter = 0


@retry
def save_to_database(arg):
    print("Write to a database or make a network call or etc.")
    print("This will be automatically retried if exception is thrown.")
    global counter
    counter += 1
    # This will throw an exception in the first call
    # And will work fine in the second call (i.e. a retry)
    if counter < 2:
        raise ValueError(arg)


if __name__ == '__main__':
    save_to_database("Some bad value")

خروجی:

$ python more_decorator.py
Write to a database or make a network call or etc.
This will be automatically retried if exception is thrown.
ERROR:retry:Attempt 1/5 failed : (('Some bad value',), {})
Traceback (most recent call last):
  File "more_decorator.py", line 14, in wrapper_function
    return f(*args, **kwargs)
  File "more_decorator.py", line 39, in save_to_database
    raise ValueError(arg)
ValueError: Some bad value
Write to a database or make a network call or etc.
This will be automatically retried if exception is thrown.

نحوۀ عملکرد

منابع زیر را ببینید:

تفاوت های پایتون 2 و پایتون 3

به منابع زیر مراجعه کنید:

جمع بندی

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

در ادامه، چگونگی یادگیری بیشتر پایتون را کشف خواهیم کرد.

results matching ""

    No results matching ""