Vahid
Vahid
خواندن ۲ دقیقه·۵ سال پیش

نکته هایی از پایتون؛ این قسمت __slots__

سلام سعی می کنم نکته هایی از پایتون که به نظرم جالب هستن رو به اشتراک بزارم.
این قسمت هم چیزی به اسم: __slots__

https://thewebtier.com/wp-content/uploads/2019/06/Important-Python-Tips-and-Tricks-for-Programmers.jpg
https://thewebtier.com/wp-content/uploads/2019/06/Important-Python-Tips-and-Tricks-for-Programmers.jpg


خب اما این عزیز چیه؟
پایتون به صورت پیش فرض ویژگی های کلاسی(instance attributes) یک شی (object) رو تو یه دیکشنری به اسم __dict__ ذخیره میکنه(البته تا لحظه نوشتن این متن که اینطوریه) یعنی اگر یه کلاس به اسم MyClass داشته باشیم و متغیر first_name هم یکی از ویژگی های این کلاس باشه با فراخوانی __dict__ ویژگی های اون شی رو بدست میاریم. یعنی:

class MyClass(object): def __init__(self, f_name): self.first_name = f_name test_obj = MyClass(&quotvahid&quot) print(test_obj.__dict__) خروجی میشه: #{ 'first_name': 'vahid' }

یا می تونیم ویژگی هایی رو به صورت پویا به اون شی اضافه کنیم. مثلا:

class MyClass(object): def __init__(self, f_name): self.first_name = f_name test_obj = MyClass(&quotvahid&quot) test_obj.last_name = &quotfathi&quot # 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(&quotvahid&quot)

کد بالا درسته و به خوبی کار میکنه اما اگر بخوایم چیزی شبیه کد پایین بنویسیم به ارور می خوریم:

test_obj.last_name = &quotfathi&quot Traceback (most recent call last): File &quottest.py&quot, line 12, in <module> test_obj.last_name = &quotfathi&quot 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.

جمع بندی و اینکه اگر حل شده چرا گفتم؟

  • فهمیدیم که ویژگی های شی تو __dict__ ذخیره میشن.
  • چیزی به اسم __slots__ تو پایتون داریم.
  • هدف نهایی آقای Guido van Rossum از __slots__ بحث performance بوده.
  • افتخار آشنایی با Key-Sharing هم داشتیم.

منابع:

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

شاد و خندون باشین :)


pythonpython tipsslots
یه وحید از نوع برنامه نویسش :)
شاید از این پست‌ها خوشتان بیاید