I am new to Python having come from mainly Java programming.
I am currently pondering over how classes in Python are instantiated.
I understand that __ini
This answer pertains to new-style Python classes, which subclass object
. New-style classes were added in 2.2, and they're the only kind of class available in PY3.
>>> print object.__doc__
The most base type
The class itself is an instance of a metaclass, which is usually type
:
>>> print type.__doc__
type(object) -> the object's type
type(name, bases, dict) -> a new type
Per the above docstring, you can instantiate the metaclass directly to create a class:
>>> Test = type('Test', (object,), {'__doc__': 'Test class'})
>>> isinstance(Test, type)
True
>>> issubclass(Test, object)
True
>>> print Test.__doc__
Test class
Calling a class is handled by the metaclass __call__
method, e.g. type.__call__
. This in turn calls the class __new__
constructor (typically inherited) with the call arguments in order to create an instance. Then it calls __init__
, which may set instance attributes.
Most objects have a __dict__
that allows setting and deleting attributes dynamically, such as self.value = 10
or del self.value
. It's generally bad form to modify an object's __dict__
directly, and actually disallowed for a class (i.e. a class dict is wrapped to disable direct modification). If you need to access an attribute dynamically, use the built-in functions getattr
, setattr
, and delattr
.
The data model defines the following special methods for customizing attribute access: __getattribute__
, __getattr__
, __setattr__
, and __delattr__
. A class can also define the descriptor protocol methods __get__
, __set__
, and __delete__
to determine how its instances behave as attributes. Refer to the descriptor guide.
When looking up an attribute, object.__getattribute__
first searches the object's class and base classes using the C3 method resolution order of the class:
>>> Test.__mro__
(<class '__main__.Test'>, <type 'object'>)
Note that a data descriptor defined in the class (e.g. a property
or a member
for a slot) takes precedence over the instance dict. On the other hand, a non-data descriptor (e.g. a function) or a non-descriptor class attribute can be shadowed by an instance attribute. For example:
>>> Test.x = property(lambda self: 10)
>>> inspect.isdatadescriptor(Test.x)
True
>>> t = Test()
>>> t.x
10
>>> t.__dict__['x'] = 0
>>> t.__dict__
{'x': 0}
>>> t.x
10
>>> Test.y = 'class string'
>>> inspect.isdatadescriptor(Test.y)
False
>>> t.y = 'instance string'
>>> t.y
'instance string'
Use super to proxy attribute access for the next class in the method resolution order. For example:
>>> class Test2(Test):
... x = property(lambda self: 20)
...
>>> t2 = Test2()
>>> t2.x
20
>>> super(Test2, t2).x
10
Attributes of Python objects are generally stored in a dictionary, just like the ones you create with {}
. Since you can add new items to a dictionary at any time, you can add attributes to an object at any time. And since any type of object can be stored in a dictionary without previous declaration of type, any type of object can be stored as an attribute of an object.
In short, my_object.abc = 42
is (often) just a shorthand for my_object.__dict__["abc"] = 42
.
It is possible to define objects without a __dict__
by defining the __slots__
attribute, or to override certain special methods and store attributes in some other way, though most of the time you shouldn't do that.
I understand that
__init__()
: is like the constructor in Java.
To be more precise, in Python __new__
is the constructor method, __init__
is the initializer. When you do SomeClass('foo', bar='baz')
, the type.__call__
method basically does:
def __call__(cls, *args, **kwargs):
instance = cls.__new__(*args, **kwargs)
instance.__init__(*args, **kwargs)
return instance
Generally, most classes will define an __init__
if necessary, while __new__
is more commonly used for immutable objects.
However, sometimes python classes do not have an init() method which in this case I assume there is a default constructor just like in Java?
I'm not sure about old-style classes, but this is the case for new-style ones:
>>>> object.__init__
<slot wrapper '__init__' of 'object' objects>
If no explicit __init__
is defined, the default will be called.
So to be clear, my question is in Python can we dynamically define new fields to a class during runtime like in this example
Yes.
>>> class A(object):
... def __init__(self):
... self.one_attribute = 'one'
... def add_attr(self):
... self.new_attribute = 'new'
...
>>> a = A()
>>> a.one_attribute
'one'
>>> a.new_attribute
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'new_attribute'
>>> a.add_attr()
>>> a.new_attribute
'new'
Attributes can be added to an instance at any time:
>>> a.third_attribute = 'three'
>>> a.third_attribute
'three'
However, it's possible to restrict the instance attributes that can be added through the class attribute __slots__
:
>>> class B(object):
... __slots__ = ['only_one_attribute']
... def __init__(self):
... self.only_one_attribute = 'one'
... def add_attr(self):
... self.another_attribute = 'two'
...
>>> b = B()
>>> b.add_attr()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in add_attr
AttributeError: 'B' object has no attribute 'another_attribute'
(It's probably important to note that __slots__
is primarily intended as a memory optimization - by not requiring an object have a dictionary for storing attributes - rather than as a form of run-time modification prevention.)