I read through the main answers on usage of slots and it has given me an idea of how and where to use __slots__
.
Now, I am porting a code from Python 2 to Python 3 which is similar to as following:
class B(object):
__slots__ = ('_fields')
_fields = set()
But this is giving error Python 3 while working fine on Python 2:
ValueError: '_fields' in __slots__ conflicts with class variable
.
I change the code to
class B(object):
__slots__ = ('_fields')
def __init__(self):
_fields = set()
and it works fine. My query is, is it even the correct change ?
As i got from original code, I guess it is saying that don't use __dict__
for saving memory or faster access or whatever reason but at the same time is also trying to specify the type of attribute _field
as set(). Can the change above be the right way to say it or it can have some side effects.
Further Experiments: I experimented further with following variants (on Python 3):
import pdb
class A(object):
a = set()
'''
class B(object):
__slots__ = ('a')
a = set()
'''
class C(object):
__slots__ = ('a')
def __init__(self):
a = set()
class D(object):
def __init__(self):
__slots__ = ('a')
a = set()
if __name__ == '__main__':
#pdb.set_trace()
x = A(); print(dir(x))
#y = B()
z = C(); print(dir(z))
z1 = D(); print(dir(z1))
and it gave following output.
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a']
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'a']
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
We can see that only C object shows correct footprint i.e. no __dict__
and only __slots__
. Isn't it what ideally we would want ? Any explanation on __weakref__
would also be helpful.
Also on Python 2, both B and C object show same footprint. Based on that should C be the right way to put it as it is compiling on both Python 2 and 3 as well.
__init__
insteadself._fields = _fields if not None else set()
– Mephistopheles