Why is my instance variable not in __dict__? - python

If I create a class A as follows:
class A:
def __init__(self):
self.name = 'A'
Inspecting the __dict__ member looks like {'name': 'A'}
If however I create a class B:
class B:
name = 'B'
__dict__ is empty.
What is the difference between the two, and why doesn't name show up in B's __dict__?

B.name is a class attribute, not an instance attribute. It shows up in B.__dict__, but not in b = B(); b.__dict__.
The distinction is obscured somewhat because when you access an attribute on an instance, the class dict is a fallback. So in the above example, b.name will give you the value of B.name.

class A:
def _ _init_ _(self):
self.name = 'A'
a = A()
Creates an attribute on the object instance a of type A and it can therefore be found in: a.__dict__
class B:
name = 'B'
b = B()
Creates an attribute on the class B and the attribute can be found in B.__dict__ alternatively if you have an instance b of type B you can see the class level attributes in b.__class__.__dict__

Related

How can I force subclasses to have __slots__?

I have a class with __slots__:
class A:
__slots__ = ('foo',)
If I create a subclass without specifying __slots__, the subclass will have a __dict__:
class B(A):
pass
print('__dict__' in dir(B)) # True
Is there any way to prevent B from having a __dict__ without having to set __slots__ = ()?
The answer of #AKX is almost correct. I think __prepare__ and a metaclass is indeed the way this can be solved quite easily.
Just to recap:
If the namespace of the class contains a __slots__ key after the class body is executed then the class will use __slots__ instead of __dict__.
One can inject names into the namespace of the class before the class body is executed by using __prepare__.
So if we simply return a dictionary containing the key '__slots__' from __prepare__ then the class will (if the '__slots__' key isn't removed again during the evaluation of the class body) use __slots__ instead of __dict__.
Because __prepare__ just provides the initial namespace one can easily override the __slots__ or remove them again in the class body.
So a metaclass that provides __slots__ by default would look like this:
class ForceSlots(type):
#classmethod
def __prepare__(metaclass, name, bases, **kwds):
# calling super is not strictly necessary because
# type.__prepare() simply returns an empty dict.
# But if you plan to use metaclass-mixins then this is essential!
super_prepared = super().__prepare__(metaclass, name, bases, **kwds)
super_prepared['__slots__'] = ()
return super_prepared
So every class and subclass with this metaclass will (by default) have an empty __slots__ in their namespace and thus create a "class with slots" (except the __slots__ are removed on purpose).
Just to illustrate how this would work:
class A(metaclass=ForceSlots):
__slots__ = "a",
class B(A): # no __dict__ even if slots are not defined explicitly
pass
class C(A): # no __dict__, but provides additional __slots__
__slots__ = "c",
class D(A): # creates normal __dict__-based class because __slots__ was removed
del __slots__
class E(A): # has a __dict__ because we added it to __slots__
__slots__ = "__dict__",
Which passes the tests mentioned in AKZs answer:
assert "__dict__" not in dir(A)
assert "__dict__" not in dir(B)
assert "__dict__" not in dir(C)
assert "__dict__" in dir(D)
assert "__dict__" in dir(E)
And to verify that it works as expected:
# A has slots from A: a
a = A()
a.a = 1
a.b = 1 # AttributeError: 'A' object has no attribute 'b'
# B has slots from A: a
b = B()
b.a = 1
b.b = 1 # AttributeError: 'B' object has no attribute 'b'
# C has the slots from A and C: a and c
c = C()
c.a = 1
c.b = 1 # AttributeError: 'C' object has no attribute 'b'
c.c = 1
# D has a dict and allows any attribute name
d = D()
d.a = 1
d.b = 1
d.c = 1
# E has a dict and allows any attribute name
e = E()
e.a = 1
e.b = 1
e.c = 1
As pointed out in a comment (by Aran-Fey) there is a difference between del __slots__ and adding __dict__ to the __slots__:
There's a minor difference between the two options: del __slots__ will give your class not only a __dict__, but also a __weakref__ slot.
How about a metaclass like this and the __prepare__() hook?
import sys
class InheritSlots(type):
def __prepare__(name, bases, **kwds):
# this could combine slots from bases, I guess, and walk the base hierarchy, etc
for base in bases:
if base.__slots__:
kwds["__slots__"] = base.__slots__
break
return kwds
class A(metaclass=InheritSlots):
__slots__ = ("foo", "bar", "quux")
class B(A):
pass
assert A.__slots__
assert B.__slots__ == A.__slots__
assert "__dict__" not in dir(A)
assert "__dict__" not in dir(B)
print(sys.getsizeof(A()))
print(sys.getsizeof(B()))
For some reason, this still does print 64, 88 – maybe an inherited class's instances are always a little heavier than the base class itself?

Can a particular instance of a class make its own variables in python?

Can a particular instance make its own variable in python, if yes would it be available to other instances of the class?
for eg:
class A():
Var1 = 10
inst1 = A()
inst1.Var1 # will be 10
but can inst1 make it's own variables like Var2 etc and will these Variables be available to other class A instances like inst2?
In other Words, is a variable, which is bound to an instance of a class, accessible to another instance of the same class?
Actually, the most common use case is for instances to have their "own" variables ("data attributes" in Python terminology) which are not shared between instances. The variables x and y below are examples of such "own" variables (every instance of class A gets its own variable x when the constructor is called, and inst1 also gets its own variable y later):
class A():
def __init__(self): # Constructor - called when A is instantiated
self.x = 10 # Creates x for self only (i.e. for each instance in turn)
inst1 = A()
inst1.x = 15 # Changes x for inst1 only
inst1.y = 20 # Creates y for inst1 only
print(inst1.x, inst1.y) # 15 20
inst2 = A()
print(inst2.x) # 10
To dynamically add attributes to a class or instance you can use setattr:
class MyClass(object):
pass
my_instance = MyClass()
# add attribute to class
setattr(MyClass, 'new_attribute', 'added')
# Class now has attribute
print(MyClass.new_attribute == 'added') # True
# Which is also available to instance
print(my_instance.new_attribute == 'added') # True
# Add attribute to instance
setattr(my_instance, 'instance_only', 'yup')
# Instance now has attribute
print(my_instance.instance_only == 'yup') # True
# Class does not have attribute
MyClass.instance_only # Raises AttributeError
# Add attribute to instances class
settatr(type(my_instance), 'instance_only', 'not anymore')
# Now the attribute is available to the class as well
print(MyClass.instance_only == 'not anymore') # True
# New instances will also have the attributes
new_instance = MyClass()
print(new_instance.new_attribute == 'added') # True
If you are not adding them dynamically see #gilch's answer
Even though the actual use may be questionable, you actually can bind new attributes to a class definition in a way that they are available to all instances of that class:
class A(object):
attrib_one = 'VALUE'
def add_class_attrib(self, name, value):
# Bind new attribute to class definition, **not** to self
setattr(A, name, value)
if __name__ == '__main__':
# Instantiate _before_ changing A's class attributes
a = A()
b = A()
# Add a new class attribute using only _one_ instance
a.add_class_attrib('attrib_two', 'OTHER')
# Print attributes of both instances
print([e for e in dir(a) if not e.startswith('__')])
print([e for e in dir(b) if not e.startswith('__')])
# Create new instance _after_ changing A's class attribs
c = A()
# Print attributes of new instance
print([e for e in dir(c) if not e.startswith('__')])
Running this code will print the following:
['add_class_attrib', 'attrib_one', 'attrib_two']
['add_class_attrib', 'attrib_one', 'attrib_two']
['add_class_attrib', 'attrib_one', 'attrib_two']
And you see, that -- even if a class attribute is added to the class definition after an instance of it has been created, the newly created class attribute in fact is available to all other instances of that (changed) class.
It depends on if you set the variable in the class's dict or the instance's dict.
>>> class A:
var = 10
>>> inst1 = A()
>>> inst2 = A()
>>> inst1.var # not in instance, so looked up in class
10
>>> inst2.var
10
>>> inst2.var = 20 # instance attr shadows that from class
>>> inst2.var
20
>>> A.var = 30 # class attr can also be altered
>>> inst1.var
30
>>> inst2.var
20
>>> del inst2.var # deleting instance attr reveals shadowed class attr
>>> inst2.var
30
>>> inst1.var2 = 'spam'
>>> inst2.var2 # new attr was set on inst1, so not available in inst2
Traceback (most recent call last):
File "<pyshell#663>", line 1, in <module>
inst2.var2
AttributeError: 'A' object has no attribute 'var2'
>>> inst1.__class__.var3 = 'eggs' # same as A.var3 = 'eggs'
>>> inst2.var3 # new attr was set on the class, so all instances see it.
'eggs'

Why does are namedtuple attributes shadowed by class attributes?

With a boring class, object instance attribute shadow class attributes:
class C(object):
a="class_a"
def __init__(self, a):
self.a = a
c = C(a="obja")
print c.a # obja
But if my class attributes are declared in a named_tuple base:
class C(collections.namedtuple("CBase", ['a', ])):
a="class_a"
c = C(a="obja")
print c.a # class_a !!??!
... so, declaring my instance attribute through the name tuple causes that attribute to be shadowed by the class attribute ... which not what you'd expect.
Why is this?
namedtuple "attributes" are implemented as descriptors (specifically, propertys) on the class itself, not attributes in the traditional sense (all the actual data is stored in unnamed indices of the tuple). In this case, the namedtuple (roughly) defines:
#property
def a(self):
return self[0]
Since the property is a class level attribute, when you define a on the subclass, it shadows equivalent definitions in the parent class.

Access class variables from another class

I have a simple class A that gets the name from users.
class A:
def __init__(self, name = ''):
self.name = name
Then I want to create a class B that prints out this name. I tried:
class B:
def print_name(printing_name = A.name):
print(printing_name)
Then I call these methods:
m1 = A("x")
B.print_name(m1)
This returns the error
Traceback (most recent call last):
File "so.py", line 5, in <module>
class B:
File "so.py", line 7, in B
def print_name(printing_name = A.name):
AttributeError: class A has no attribute 'name'
I know that I did not assign a class variable in the class A, and thus the name attribute goes with specific instances, not the entire class. However, the name attribute has to connect with every specific instance because it changes from the case to case. Then how should I get this name in class B?
Change your class B to this:
class B:
#staticmethod
def print_name(obj):
print(obj.name)
The print_name method probably should be decorated as a "static method". The property "name" of self is an instance attribute which can not be referred directly from the class itself.
That's correct: name is an instance attribute, not a class attribute. IN this case, m1 has a name, but class A does not. You need to access the name of the input parameter, not attempt to print a class attribute.
You also need to make B.print_name a class function, since you're not calling it from an instance of B.
class B:
#staticmethod
def print_name(inst):
print(inst.name)
Output:
x
Edit: The answers suggesting #staticmethod are ideal if you understand what it does.
class A:
def __init__(self, name = ''):
self.name = name
class B:
def __init__(self):
pass
def print_name(self, var):
print (var.name)
Output:
>>> m1 = A("X")
>>> b = B()
>>> b.print_name(m1)
X
>>>
In this instance A is the name of the class, and you should not give it as the default argument for calling the print_name method. Have a look at keyword arguments for Python, and you will see that what you have written actually means that you have the default value set to the .name property of the class A, which does not exist unless the class is instantiated (i.e. an object is created of the class).
Your B class should read:
class B:
def print_name(printing_object):
print(printing_object.name)

How to initialise class itself as class Object

How to initialise class as an object with same name
>>> class test:
def name(self,name_):
self.name = name_
>>> a= test()
>>> a
<__main__.test instance at 0x027036C0>
>>> test
<class __main__.test at 0x0271CDC0>
here a is an object so I can do a.name("Hello")
But what I want to achieve is test.name("Hello") without doing something like test = test()
The simple answer is don't bother with a "setter" function. Just access the attribute directly. eg.
a = test()
a.name = "setting an instance attribute"
test.name = "setting the class attribute"
b = test()
# b has no name yet, so it defaults the to class attribute
assert b.name == "setting the class attribute"
If the function is doing something a little more complicated than just setting an attribute then you can make it a classmethod. eg.
class Test(object):
# you are using python 2.x -- make sure your classes inherit from object
# Secondly, it's very good practice to use CamelCase for your class names.
# Note how the class name is highlighted in cyan in this code snippet.
#classmethod
def set_name(cls, name):
cls.name = name
Test.set_name("hello")
assert Test().name == "hello"

Categories