3

In the python library pytides, I came across a strange method to initialize a class (the Tide class and its initialization ). I reproduced below a simplified version of the code :

import numpy as np

class Foo(object):
    def __init__(self,x,y):
        self.x = x
        self.y = y

class Foobar(object):
    dtype = np.dtype([('fooObj', object),
                      ('A', float),
                      ('B', float)])

    def __init__(self,model):
        '''model: an ndarray of type Foobar.dtype '''
        self.model = model


# initialize a Foobar object
myFoos = [Foo(4,3),Foo(4,9),Foo(0,2)]
A = [2,3,4]
B = [8,9,0]
model = np.zeros(len(myFoos), dtype = Foobar.dtype)
model['fooObj'] = myFoos     #what is that?!?
model['A'] = A
model['B'] = B
myFoobar = Foobar(model=model)

As I understand, the dtype variable in Foobar is a global variable, but I don't understand what's the point to have it. Is it just here to provide a convenient way to initialize Foobar? Moreover the Foobar class needs an array of Foobar.dtype at construction, is not a sort of cyclic call (which should crash)?

Shivkumar kondi
  • 6,458
  • 9
  • 31
  • 58
Marcel
  • 464
  • 1
  • 6
  • 12
  • 4
    The `dtype` variable in `Foobar` is _not_ a global variable, it's a class attribute, which is shared by all instances of the `Foobar` class. – PM 2Ring Jan 13 '17 at 08:09

2 Answers2

1

Foobar.dtype is a class attribute.

That is a variable which is attached to the definition of the class not a single instance of the class. If you're familiar with other popular object-oriented languages, this concept is very similar to a static variables in Java and C#.

Python docs which explains in more detail https://docs.python.org/3/tutorial/classes.html#class-objects


Considering class Foobar in the example you've provided:

Foobar is a class

myFoobar is an instance of Foobar

let's pretend that there's another instance too: yourFoobar

then myFoobar and yourFoobar (and any other instances) may need to be able to have access to some data (in this case a definition of a numpy datatype) which is the same for all instances of Foobar. Thus there's an argument that it should be associated to the class rather than each individual instance. (However there are also arguments that class attributes / static variables do more harm than good: Why are static variables considered evil?)

i.e. avoiding a way of writing it where you allocate each instance of Foobar its own instance of the same numpy dtype definition, such as...

class Foobar(object):
    def __init__(self,model):
        '''model: an ndarray of type self.dtype '''
        self.model = model
        self.dtype = np.dtype([('fooObj', object),
                      ('A', float),
                      ('B', float)])
Community
  • 1
  • 1
Rich
  • 3,781
  • 5
  • 34
  • 56
  • Thanks @Richard. I think I was confused by the name of the variable (dtype). The Python doc make it clearer. – Marcel Jan 13 '17 at 10:09
1

There isn't much that is strange about this initialization, dtype holds the types Foobar requires for the numpy array it receives durings its initialization (model). It's a class attribute, not a global one, so it is shared by all instances of the Foobar class.

The way model is initialized might seem odd, but it is just initializing model based on the name that specifies the field, this might be best demonstrated by printing out model in between the steps:

model['fooObj'] = myFoos
print(model)
array([(<__main__.Foo object at 0x7f125ed93828>, 0.0, 0.0),
       (<__main__.Foo object at 0x7f125ed93940>, 0.0, 0.0),
       (<__main__.Foo object at 0x7f125ed93240>, 0.0, 0.0)], 
      dtype=[('fooObj', 'O'), ('A', '<f8'), ('B', '<f8')])

adds the values for the 'fooObj' object type. While:

model['A'] = A
model['B'] = B

adds the values for the float types 'A' and 'B' respectively.

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253