آموزش پایتون - بازتاب

در برنامه‌نویسی شیءگرا، بازتاب (Reflection) به توانایی استخراج اطلاعات درباره هر شیء در حال استفاده اشاره دارد. شما می‌توانید نوع شیء، اینکه آیا زیرکلاسی از کلاس دیگر است یا خیر، ویژگی‌ها (Attributes) آن چیست و موارد بسیار دیگری را متوجه شوید. کتابخانه استاندارد پایتون شامل چند تابع است که ویژگی‌های مختلف یک شیء را منعکس و بررسی می‌کنند. بازتاب گاهی اوقات خودبازرسی (Introspect) نیز نامیده می‌شود.

در ادامه فهرست توابع بازتاب در پایتون آمده است −

  • تابع ()type
  • تابع ()isinstance
  • تابع ()issubclass
  • تابع ()callable
  • تابع ()getattr
  • تابع ()setattr
  • تابع ()hasattr
  • تابع ()dir

تابع ()type

ما بارها از این تابع استفاده کرده‌ایم. این تابع به شما می‌گوید که یک شیء متعلق به کدام کلاس است.

مثال

دستورات زیر کلاس مربوط به اشیاء مختلف از نوع داده‌های توکار را چاپ می‌کنند

print (type(10))
print (type(2.56))
print (type(2+3j))
print (type("Hello World"))
print (type([1,2,3]))
print (type({1:'one', 2:'two'}))

در اینجا، خروجی زیر را دریافت خواهید کرد −

<class 'int'>
<class 'float'>
<class 'complex'>
<class 'str'>
<class 'list'>
<class 'dict'>

بیاین نوع یک شیء از یک کلاس تعریف‌شده توسط کاربر را بررسی کنیم −

class test:
   pass
   
obj = test()
print (type(obj))

این کد خروجی زیر را تولید خواهد کرد −

<class '__main__.test'>

تابع ()isinstance

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

سنتکس

isinstance(obj, class)

این تابع همیشه یک مقدار بولین برمی‌گرداند؛ اگر شیء واقعاً متعلق به کلاس داده‌شده باشد True و در غیر این صورت False.

مثال

دستورات زیر مقدار True را برمی‌گردانند −

print (isinstance(10, int))
print (isinstance(2.56, float))
print (isinstance(2+3j, complex))
print (isinstance("Hello World", str))

این کد خروجی زیر را تولید خواهد کرد −

True
True
True
True

در مقابل، این دستورات مقدار False را چاپ می‌کنند.

print (isinstance([1,2,3], tuple))
print (isinstance({1:'one', 2:'two'}, set))

این کد خروجی زیر را تولید خواهد کرد −

False
False

همچنین می‌توانید این بررسی را با یک کلاس تعریف‌شده توسط کاربر انجام دهید

class test:
   pass
   
obj = test()
print (isinstance(obj, test))

این کد خروجی زیر را تولید خواهد کرد −

True

در پایتون، حتی خود کلاس‌ها نیز شیء هستند. همه کلاس‌ها شیئی از کلاس object محسوب می‌شوند. این موضوع را می‌توان با کد زیر بررسی کرد −

class test:
   pass
   
print (isinstance(int, object))
print (isinstance(str, object))
print (isinstance(test, object))

تمام دستورات print بالا مقدار True را چاپ می‌کنند.

تابع ()issubclass

این تابع بررسی می‌کند که آیا یک کلاس، زیرکلاسی از کلاس دیگر هست یا خیر. این تابع مربوط به کلاس‌هاست، نه نمونه‌های آن‌ها.

همان‌طور که قبلاً اشاره شد، تمام کلاس‌های پایتون زیرکلاسی از کلاس object هستند. بنابراین، خروجی دستورات print زیر برای همه آن‌ها True است.

class test:
   pass
   
print (issubclass(int, object))
print (issubclass(str, object))
print (issubclass(test, object))

این کد خروجی زیر را تولید خواهد کرد −

True
True
True

تابع ()callable

یک شیء زمانی فراخوانی‌پذیر (callable) است که فرایند خاصی را اجرا کند. یک تابع پایتون که فرایند مشخصی را انجام می‌دهد، یک شیء فراخوانی‌پذیر است. بنابراین (callable(function مقدار True را برمی‌گرداند. هر تابعی، اعم از توکار، تعریف‌شده توسط کاربر یا متد، فراخوانی‌پذیر است. اشیاء مربوط به انواع داده‌ای توکار مانند int ،str و غیره، فراخوانی‌پذیر نیستند.

مثال

def test():
   pass
   
print (callable("Hello"))
print (callable(abs))
print (callable(list.clear([1,2])))
print (callable(test))

یک شیء رشته‌ای فراخوانی‌پذیر نیست. اما abs تابعی است که فراخوانی‌پذیر محسوب می‌شود. متد pop در لیست‌ها فراخوانی‌پذیر است، اما ()clear در واقع یک فراخوانی تابع است و نه خود شیء تابع، بنابراین فراخوانی‌پذیر نیست.

این کد خروجی زیر را تولید خواهد کرد −

False
True
True
False
True

یک نمونه از کلاس در صورتی فراخوانی‌پذیر است که دارای متد ()__call__ باشد. در مثال زیر، کلاس test شامل متد ()__call__ است. بنابراین، از شیء آن می‌توان به گونه‌ای استفاده کرد که گویی یک تابع را فراخوانی می‌کنیم. به همین دلیل، شیءِ کلاسی که دارای تابع ()__call__ باشد، یک شیء فراخوانی‌پذیر است.

class test:
   def __init__(self):
      pass
   def __call__(self):
      print ("Hello")
      
obj = test()
obj()
print ("obj is callable?", callable(obj))

این کد خروجی زیر را تولید خواهد کرد −

Hello
obj is callable? True

تابع ()getattr

تابع توکار ()getattr مقدار ویژگی نام‌گذاری‌شده یک شیء را بازیابی می‌کند.

مثال

class test:
   def __init__(self):
      self.name = "Manav"
      
obj = test()
print (getattr(obj, "name"))

این کد خروجی زیر را تولید خواهد کرد −

Manav

تابع ()setattr

تابع توکار ()setattr یک ویژگی جدید به شیء اضافه کرده و مقداری به آن اختصاص می‌دهد. همچنین می‌تواند مقدار یک ویژگی موجود را تغییر دهد.

در مثال زیر، شیء کلاس test دارای یک ویژگی تک به نام name است. ما از ()setattr برای اضافه کردن ویژگی age و تغییر مقدار ویژگی name استفاده می‌کنیم.

class test:
   def __init__(self):
      self.name = "Manav"
      
obj = test()
setattr(obj, "age", 20)
setattr(obj, "name", "Madhav")
print (obj.name, obj.age)

این کد خروجی زیر را تولید خواهد کرد −

Madhav 20

تابع ()hasattr

این تابع توکار اگر ویژگی داده‌شده برای آرگومان شیء موجود باشد مقدار True و در غیر این صورت مقدار False را برمی‌گرداند. ما از همان کلاس test استفاده می‌کنیم و بررسی می‌کنیم که آیا ویژگی خاصی دارد یا خیر.

class test:
   def __init__(self):
      self.name = "Manav"
      
obj = test()
print (hasattr(obj, "age"))
print (hasattr(obj, "name"))

این کد خروجی زیر را تولید خواهد کرد −

False
True

تابع ()dir

اگر این تابع توکار بدون آرگومان فراخوانی شود، نام‌های موجود در اسکوپ (محدوده) فعلی را برمی‌گرداند. برای هر شیء که به عنوان آرگومان داده شود، لیستی از ویژگی‌های آن شیء و ویژگی‌های قابل دسترس از طریق آن را برمی‌گرداند.

  • برای یک شیء ماژول − این تابع ویژگی‌های ماژول را برمی‌گرداند.

  • برای یک شیء کلاس − این تابع ویژگی‌های آن کلاس و به صورت بازگشتی ویژگی‌های کلاس‌های پایه آن را برمی‌گرداند.

  • برای هر شیء دیگر − ویژگی‌های خود شیء، ویژگی‌های کلاس آن و به صورت بازگشتی ویژگی‌های کلاس‌های پایه کلاس مربوطه‌اش را برمی‌گرداند.

مثال

print ("dir(int):", dir(int))

این کد خروجی زیر را تولید خواهد کرد −

dir(int): ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__getstate__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_count', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

مثال

print ("dir(dict):", dir(dict))

این کد خروجی زیر را تولید خواهد کرد −

dir(dict): ['__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__ior__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__ror__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

مثال

class test:
   def __init__(self):
      self.name = "Manav"

obj = test()
print ("dir(obj):", dir(obj))

این کد خروجی زیر را تولید خواهد کرد −

dir(obj): ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']

پیشرفت مطالعه: وضعیت خوانده‌شدن این درس فقط در همین مرورگر ذخیره می‌شود؛ بدون نیاز به حساب کاربری.