Search code examples
pythonclasscomplex-numbers

real and imag of class complex data descriptors or class variables?


You would be aware of class complex in python. It contains :

>>> dir(complex)
Output :
['__abs__', '__add__', '__bool__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__int__', '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__pos__', '__pow__', '__radd__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rmod__', '__rmul__', '__rpow__', '__rsub__', '__rtruediv__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', 'conjugate', 'imag', 'real']

Here conjugate is a method of class complex. But my doubt here is what are real and imag called as??

In help():

>>>help(complex)
Output:
class complex(object)
 |  complex(real=0, imag=0)
...
...
...
 ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  imag
 |      the imaginary part of a complex number
 |  
 |  real
 |      the real part of a complex number

In help(), real and imag are given as data descriptors.

Where in type():

>>> a=1j
>>> type(a.real)
<class 'float'>
>>> type(a.imag)
<class 'float'>

Also we are accessing real and imag as we access class variable inside a class.

classname.class_variable (or) objectname.class_variable

Hence, I got a doubt here. Whether real and imag are a kind of class variables or data descriptors??? Similarly, a doubt in start, stop and step in class range.

Need clarification for :

  1. Are they data descriptors or a kind of class variables??

  2. If they are data descriptors, kindly explain me why they are called data descriptors???

  3. Any reference links regarding data descriptors related to my doubt are much needed

Thanks in advance


Solution

  • A descriptor is a special kind of object in Python that, when it is stored as a class variable gets special methods run on it when it gets looked up via an instance.

    The descriptor protocol is used for several kind of special behavior, such as method binding (how self gets passed as the first argument). The protocol is made available easily for Python code via the property type, which is a descriptor you can apply as a decorator to a method so that it gets called when the attribute gets looked up (without needing the user to explicitly call anything).

    In your case, the real and imag attributes of the complex type (as well as the three attributes of the range type) are descriptors, but they're less fancy than those others. Rather, the descriptors are just how attribute access works for instances of immutable builtin classes (that is, ones that are implemented in C, rather than in pure Python). The actual data of a complex (or range) object is stored in a C structure. The descriptor allows it to be accessed by Python code. Note that you can't assign to those attributes, because that would break the immutability of the object.

    You could implement a similar type with property:

    class MyComplex():
        def __init__(self, real=0, imag=0):
            self._real = real
            self._imag = imag
    
        @property
        def real(self):
            return self._real
    
        @property
        def imag(self):
            return self._imag
    

    Here real and imag are property objects, which are descriptors similar to the ones in the builtin complex type. They're also read only (though the class as a whole is not really immutable).