Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What allows bare class instances to have assignable attributes?

I am trying to fill in a gap in my understanding of how Python objects and classes work.


A bare object instance does not support attribute assignment in any way:

> object().a = 5
# or
> setattr(object(), 'a', 5)

AttributeError: 'object' object has no attribute 'a'

I assume that this is because a bare object instance does not possess an __dict__ attribute:

> '__dict__' in dir(object())

False

However a bare object instance does have a defined __setattr__ attribute, so this is a bit confusing to me:

> '__setattr__' in dir(object())

True

An instance of a regular empty class on the other hand has full ability of attribute assignment:

class B(object):
    pass

> B().a = 5
> setattr(B(), 'a', 5)

My question is: what inherent difference between an object instance and a class B(object) instance allows the latter to have assignable attributes, if B inherits directly from object?

like image 418
bool3max Avatar asked Dec 17 '21 00:12

bool3max


People also ask

Can a class attribute be used without instance?

while you can access class attributes using an instance it's not safe to do so. In python, the instance of a class is referred to by the keyword self. Using this keyword you can access not only all instance attributes but also the class attributes.

What are class instance attributes?

Class attributes are the variables defined directly in the class that are shared by all objects of the class. Instance attributes are attributes or properties attached to an instance of a class. Instance attributes are defined in the constructor.

Can a class contain instance attributes?

Classes contain characteristics called Attributes. We make a distinction between instance attributes and class attributes. Instance Attributes are unique to each object, (an instance is another name for an object). Here, any Dog object we create will be able to store its name and age.

How do you access class attributes in Python?

Accessing the attributes of a class getattr() − A python method used to access the attribute of a class. hasattr() − A python method used to verify the presence of an attribute in a class. setattr() − A python method used to set an additional attribute in a class.

What is the difference between class and instance attributes?

Instance Attributes. Unlike class attributes, instance attributes are not shared by objects. Every object has its own copy of the instance attribute (In case of class attributes all object refer to single copy). To list the attributes of an instance/object, we have two functions:-.

What is a class attribute?

Class Attributes are unique to each class. Each instance of the class will have this attribute. It’s sometimes used to specify a defualt value that all objects should have after they’ve been instantiated. Here, our class attribute is species

What are the two types of attributes in Java?

02:59 There are two types of attributes: instance attributes and class attributes. Instance attributes are what we’ve seen before. These are the attributes that are independent to each object, like the door color or the height, in the previous example. In this example, our Dog class has two instance attributes: .name and .age.

What are instance attributes in Python?

These are the attributes that are independent to each object, like the door color or the height, in the previous example. In this example, our Dog class has two instance attributes: .name and .age. 03:21 This def __init__ () is a very special function that belongs to our class.


1 Answers

The object() class is like a fundamental particle of the python universe, and is the base class (or building block) for all objects (read everything) in Python. As such, the stated behavior is logical, for not all objects can (or should) have arbitrary attributes set. For example, it wouldn't make sense if a NoneType object could have attributes set, and, just like object(), a None object also does not have a __dict__ attribute. In fact, the only difference in the two is that a None object has a __bool__ attribute. For example:

n = None
o = object()

type(n)
>>> <class 'NoneType'>

set(dir(n)) - set(dir(o))
>>> {'__bool__'}

isinstance(n, object)
>>> True

bool(n)
>>> False

Inheritance from object is automatic, and, just like any other means of inheriting, one can add their own class methods and attributes to the child. Python automatically adds the __dict__ attribute for custom data types as you already showed.

In short, it is much easier to add an object's __dict__ attribute than to take it away for objects that do not have custom writable attributes (i.e. the NoneType).

Update based on comment:

Original comment:

Would it then be safe to assume that it is __setattr__ that checks for the existence of __dict__ and raises an exception accordingly? – bool3max

In CPython, the logic behind object.__setattr__(self, name, value) is implemented by Objects/object.c _PyObject_GenericSetAttrWithDict (see CPython source code). Specifically, it looks like if the name argument is a string, then the object is checked for a __dict__ object in one of its slots and makes sure it is "ready" (see this line).

The readiness state of the object is determined by the PyType_Ready(), briefly described and quoted from here:

Defining a Python type in C involves populating the fields of a PyTypeObject struct with the values you care about. We call each of those fields a “slot”.

On[c]e the definition is ready, we pass it into the PyType_Ready() function, which does a number of things, inclulding exposing most of the type definition to Python’s attribute lookup mechanism.

like image 105
jacob Avatar answered Oct 17 '22 15:10

jacob