flybonzai flybonzai - 1 month ago 7
Python Question

Running super().__init__(value) where value is an @property

I'm just trying to grok how exactly Python handles this behind the scenes. So take this code snippet (from Effective Python by Brett Slatkin):

class Resistor(object):
def __init__(self, ohms):
self.ohms = ohms
self.voltage = 0
self.current = 0


class VoltageResistor(Resistor):
def __init__(self, ohms):
super().__init__(ohms)
self._voltage = 0

@property
def ohms(self):
return self._ohms

@ohms.setter
def ohms(self, ohms):
if ohms <= 0:
raise ValueError('{o} ohms must be > 0'.format(o=ohms))
self._ohms = ohms

@property
def voltage(self):
return self._voltage

@voltage.setter
def voltage(self, voltage):
self._voltage = voltage
self.current = self._voltage / self.ohms

VoltageResistor(-1) # fails


Running the
super()
call invokes the property check so that you can't instantiate with a zero or negative value. What is confusing me to me is that I would think that since the the
__init__(ohms)
call is being ran on the superclass, shouldn't it be in a different scope (the scope of the superclass) and thus exempt from invoking the
@property
check?

Answer

Scope doesn't come into play when working with object's attributes. Consider the following:

class A(object):
    def __init__(self):
        self.a = 1

def foo():
    a = A()
    a.a = 2
    return a

def bar(a):
    print(a.a)

bar(foo())

This example code will print 2. Note that within the scope of bar, there is no way to gain access to the scope of foo or even A.__init__. The class instance is carrying along all of it's attributes/properties with it (and a reference to it's class which has a reference to it's superclass, etc).

In your code, when you call VoltageResistor, an instance of VoltageResistor is created and passed to __init__ as self. When you call super.__init__(self), that VoltageResistor instance is passed along to Resistor.__init__. When it does self.ohms = ohms, python sees that self.ohms resolves to a property and you get the error. The tl;dr; here is that self is an instance of VoltageResistor and when working with attributes, the object on which the attributes are accessed is what is important, not the current scope).

Comments