سلام سعی می کنم نکته هایی از پایتون که به نظرم جالب هستن رو به اشتراک بزارم.
این قسمت هم چیزی به اسم: __slots__
خب اما این عزیز چیه؟
پایتون به صورت پیش فرض ویژگی های کلاسی(instance attributes) یک شی (object) رو تو یه دیکشنری به اسم __dict__ ذخیره میکنه(البته تا لحظه نوشتن این متن که اینطوریه) یعنی اگر یه کلاس به اسم MyClass داشته باشیم و متغیر first_name هم یکی از ویژگی های این کلاس باشه با فراخوانی __dict__ ویژگی های اون شی رو بدست میاریم. یعنی:
class MyClass(object): def __init__(self, f_name): self.first_name = f_name test_obj = MyClass("vahid") print(test_obj.__dict__) خروجی میشه: #{ 'first_name': 'vahid' }
یا می تونیم ویژگی هایی رو به صورت پویا به اون شی اضافه کنیم. مثلا:
class MyClass(object): def __init__(self, f_name): self.first_name = f_name test_obj = MyClass("vahid") test_obj.last_name = "fathi" # dynamically add attributes print(test_obj.__dict__) خروجی میشه: #{ 'first_name': 'vahid', 'last_name': 'fathi' }
اما مشکل کجاست؟ اینجاست که استفاده از دیکشنری برای ذخیره ویژگی ها باعث هدر رفت فضا میشه و می تونه باعث مشکل کمبود حافظه(RAM) موقعی که تعداد زیاد شی(object) داشته باشیم، بشه(منظور از تعداد زیاد هزاران و میلیون هاست).
اژدها وارد می شود!
خب مشکل رو گفتیم راه حل رو هم بگیم.
داخل پرانتز و قبل از اینکه به مشکل حافظه بپردازیم باید بگم طبق گفته خود سازنده پایتون یعنی اقای Guido van Rossum (که اینجا می تونین بخونین) هدف نهایی __slots__ بحث performance بوده. این لینک هم رو یه مثال درمورد این موضوع داره.
مشکل حافظه:
اومدن گفتن یه کاری کنیم که میزان مصرف حافظه بهبود پیدا کنه و برای اینکار از __slots__ استفاده می کنیم. چرا باعث بهبود حافظه میشه چون __slots__ ویژگی هایی که هر شی باید داشته باشه رو به صورت دقیق مشخص میکنه مثلا:
class MyClass(object): __slots__ = ['first_name'] def __init__(self, f_name): self.first_name = f_name test_obj = MyClass("vahid")
کد بالا درسته و به خوبی کار میکنه اما اگر بخوایم چیزی شبیه کد پایین بنویسیم به ارور می خوریم:
test_obj.last_name = "fathi" Traceback (most recent call last): File "test.py", line 12, in <module> test_obj.last_name = "fathi" AttributeError: 'MyClass' object has no attribute 'last_name'
یه نکته ریز اینکه اگر __slots__ رو اینطوری بنویسم باز اضافه کردن پویا ویژگی رو خواهیم داشت
__slots__ = ['first_name', '__dict__']
از پایتون ۳٫۳ به بعد این مشکل مصرف حافظه تا حدی حل شده و دلیلش هم Key-Sharing در دیکشنری هستش.
With Python 3.3 Key-Sharing Dictionaries are used for the storage of objects. The attributes of the instances are capable of sharing part of their internal storage between each other, i.e. the part which stores the keys and their corresponding hashes. This helps to reduce the memory consumption of programs, which create many instances of non-builtin types.
جمع بندی و اینکه اگر حل شده چرا گفتم؟
منابع:
https://www.python-course.eu/python3_slots.php
http://book.pythontips.com/en/latest/__slots__magic.html
http://python-history.blogspot.com/2010/06/inside-story-on-new-style-classes.html
https://stackoverflow.com/questions/472000/usage-of-slots
شاد و خندون باشین :)