Why can't access the property setter using the super?
Arup Rakshit
ar at zeit.io
Tue Mar 19 15:15:34 EDT 2019
Hello Ian,
That seems like too much code involved. Is this how we do write inheritance in Python. Coming from Ruby and JS world I find Python inheritance mechanism confusing so far. :/
Thanks,
Arup Rakshit
ar at zeit.io
> On 19-Mar-2019, at 9:32 PM, Ian Kelly <ian.g.kelly at gmail.com> wrote:
>
> Here's the thing: the result of calling super() is not an instance of the
> base class. It's just a proxy object with a __getattribute__ implementation
> that looks up class attributes in the base class, and knows how to pass
> self to methods to simulate calling base class methods on an instance. This
> works fine for looking up methods and property getters. It doesn't work so
> well for simulating other behaviors, like setters, or comparisons, or
> iteration, etc.
>
> A property is one example of what in Python is known as a descriptor, which
> is described here:
> https://docs.python.org/3/reference/datamodel.html#implementing-descriptors
>
> A settable property has a __set__ method per the descriptor protocol. When
> you try to set an attribute with the name of the property, Python looks up
> the name in the class dict, finds the property object, and then calls its
> __set__ method. The class of the super proxy object, however, does not
> contain this property, and because you're not doing an attribute lookup,
> the super proxy's __getattribute__ does not get called. So all Python sees
> is that you tried to set an attribute that doesn't exist on the proxy
> object.
>
> The way I would suggest to get around this would be change your super()
> call so that it looks up the property from the base class instead of trying
> to set an attribute directly. For example, this should work:
>
> super(HeatedRefrigeratedShippingContainer,
> self.__class__).celsius.fset(self, value)
>
> On Tue, Mar 19, 2019 at 9:12 AM Arup Rakshit <ar at zeit.io> wrote:
>
>> I have 3 classes which are connected to them through inheritance as you
>> see in the below code:
>>
>> import iso6346
>>
>> class ShippingContainer:
>> """docstring for ShippingContainer"""
>>
>> HEIGHT_FT = 8.5
>> WIDTH_FT = 8.0
>> next_serial = 1337
>>
>> @classmethod
>> def _get_next_serial(cls):
>> result = cls.next_serial
>> cls.next_serial += 1
>> return result
>>
>> @staticmethod
>> def _make_bic_code(owner_code, serial):
>> return iso6346.create(owner_code=owner_code,
>> serial=str(serial).zfill(6))
>>
>> @classmethod
>> def create_empty(cls, owner_code, length_ft, *args, **keyword_args):
>> return cls(owner_code, length_ft, contents=None, *args,
>> **keyword_args)
>>
>> # ... skipped
>>
>> def __init__(self, owner_code, length_ft, contents):
>> self.contents = contents
>> self.length_ft = length_ft
>> self.bic = self._make_bic_code(owner_code=owner_code,
>>
>> serial=ShippingContainer._get_next_serial())
>> # ... skipped
>>
>>
>> class RefrigeratedShippingContainer(ShippingContainer):
>> MAX_CELSIUS = 4.0
>> FRIDGE_VOLUME_FT3 = 100
>>
>> def __init__(self, owner_code, length_ft, contents, celsius):
>> super().__init__(owner_code, length_ft, contents)
>> self.celsius = celsius
>>
>> # ... skipped
>>
>> @staticmethod
>> def _make_bic_code(owner_code, serial):
>> return iso6346.create(owner_code=owner_code,
>> serial=str(serial).zfill(6),
>> category='R')
>> @property
>> def celsius(self):
>> return self._celsius
>>
>> @celsius.setter
>> def celsius(self, value):
>> if value > RefrigeratedShippingContainer.MAX_CELSIUS:
>> raise ValueError("Temperature too hot!")
>> self._celsius = value
>>
>> # ... skipped
>>
>>
>> class HeatedRefrigeratedShippingContainer(RefrigeratedShippingContainer):
>> MIN_CELSIUS = -20.0
>>
>> @RefrigeratedShippingContainer.celsius.setter
>> def celsius(self, value):
>> if value < HeatedRefrigeratedShippingContainer.MIN_CELSIUS:
>> raise ValueError("Temperature too cold!")
>> super().celsius = value
>>
>>
>>
>>
>> Now when I run the code :
>>
>> Python 3.7.2 (v3.7.2:9a3ffc0492, Dec 24 2018, 02:44:43)
>> [Clang 6.0 (clang-600.0.57)] on darwin
>> Type "help", "copyright", "credits" or "license" for more information.
>>>>> from shipping import * >>> h1 =
>> HeatedRefrigeratedShippingContainer.create_empty('YML', length_ft=40,
>> celsius=-18)
>> Traceback (most recent call last):
>> File "<stdin>", line 1, in <module>
>> File "/Users/aruprakshit/python_playground/shipping.py", line 23, in
>> create_empty
>> return cls(owner_code, length_ft, contents=None, *args, **keyword_args)
>> File "/Users/aruprakshit/python_playground/shipping.py", line 47, in
>> __init__
>> self.celsius = celsius
>> File "/Users/aruprakshit/python_playground/shipping.py", line 92, in
>> celsius
>> super().celsius = value
>> AttributeError: 'super' object has no attribute 'celsius'
>>>>>
>>
>>
>> Why here super is denying the fact that it has no celsius setter, although
>> it has. While this code doesn’t work how can I solve this. The thing I am
>> trying here not to duplicate the validation of temperature which is already
>> in the setter property of the RefrigeratedShippingContainer class.
>>
>>
>>
>>
>> Thanks,
>>
>> Arup Rakshit
>> ar at zeit.io
>>
>>
>>
>> --
>> https://mail.python.org/mailman/listinfo/python-list
>>
> --
> https://mail.python.org/mailman/listinfo/python-list
More information about the Python-list
mailing list