0

I have a module for handling basic geometry features like angles and regular polygons. The portion that's giving me issues is here:

# geometry.py

_angle_mode = 'd'

@property
def angle_mode():
    return _angle_mode

@angle_mode.setter
def angle_mode(value):
    if value != 'd' or value != 'r':
        raise ValueError("ValueError: invalid mode: '{0}'".format(mode))
    _angle_mode = value

class angle:
    def __init__(self, value, mode=None):
        if mode is None:
            mode = _angle_mode
        if mode == 'd':
            self.deg = value
            self.rad = math.radians(value)
        elif mode == 'r':
            self.rad = value
            self.deg = math.degrees(value)
        else:
            raise ValueError("ValueError: invalid mode: '{0}'".format(mode))

    def __repr__(self):
        if _angle_mode == 'd':
            return 'angle({0}deg)'.format(self.deg)
        elif _angle_mode == 'r':
            print(7)
            return 'angle({0}rad)'.format(self.rad)

The issue I'm having is related to the angle_mode property.

At the interpreter, I expect the following to happen:

# interpreter
>>> import geometry
>>> a, b = geometry.angle(72), geometry.angle(2, 'r')
>>> a, b
(angle(72deg), angle(114.59...deg))
>>> geometry.angle_mode = 'r'
>>> a, b
(angle(1.25...rad), angle(2rad))

Instead, a and b both return their values as degrees before and after geometry.angle_mode = 'r'. It works correctly if I set geometry._angle_mode directly, but I would like to get/set it through a property so that I can enforce the modes.

Why are the property and .setter not working as expected, and what's the fix?

EDIT: The suggested duplicate question suggests class classobject(object):... but then proceeds to define the @classobject property inside another class, not outside the class and doesn't suggest a replacement for .setter.

superluminal
  • 101
  • 4
  • Why does your `angle_mode` refers to self, but it is outside a class ? Can you double check your question? – Devesh Kumar Singh May 17 '19 at 16:44
  • Possible duplicate of [Property method without class](https://stackoverflow.com/questions/17007886/property-method-without-class) – rdas May 17 '19 at 16:52
  • @DeveshKumarSingh self was included because i'm used to doing this inside of classes, this is the first time I considered doing it outside a class and it was included as muscle memory. It's been removed, but the issue still remains. – superluminal May 17 '19 at 17:08
  • 1
    Possible duplicate of [Can modules have properties the same way that objects can?](https://stackoverflow.com/questions/880530/can-modules-have-properties-the-same-way-that-objects-can) – juanpa.arrivillaga May 17 '19 at 17:09
  • 1
    @superluminal `property` objects are descriptors, the descriptor protocol always works on instances of classes, not in modules. You can fake this, if you really want to, check out the duplicate. – juanpa.arrivillaga May 17 '19 at 17:10
  • Not sure why you wouldn't put the property in the class. If it's a matter of reusability throughout the module then maybe create a class with just the angle_mode property or maybe just create a class for angle_mode and subclass that in all the places where you need it. – MichaelD May 17 '19 at 17:22
  • @juanpa.arrivillaga That's a little bit inaccurate - modules are just instances of `ModuleType`, after all, and `ModuleType` is a subclass of `object`. It's more of a scoping/syntax issue than a descriptor protocol limitation. – wim May 17 '19 at 17:24
  • @wim fine, but my point is, you can't just plop a property on a module and expect it to work, you'd have to hook into the module object's instantiation, which is possible, IIRC. – juanpa.arrivillaga May 17 '19 at 17:25
  • @juanpa.arrivillaga I read through both and while I have a better idea of why this isn't working (properties don't belong outside of classes), but neither of the suggested duplicates explain a workaround for the .setter. – superluminal May 17 '19 at 17:29
  • @superluminal the workaround in https://stackoverflow.com/questions/880530/can-modules-have-properties-the-same-way-that-objects-can would work for your setter – juanpa.arrivillaga May 17 '19 at 17:30
  • @MichaelD I put it outside the class so the user can change whether __repr__ returns radians or degrees for every instance of an angle, no matter how or when they were created. This also affects how some things would be handled in other classes in the geometry module that I left out for brevity. – superluminal May 17 '19 at 17:32
  • @juanpa.arrivillaga I tried the workarounds listed there but I'm still not seeing the behavior I'm expecting. I think I've reached the point where I have the answer but don't understand how to apply it due to a very patchy understanding of how python actually works. I'm just going to settle for having a separate function to update the _angle_mode variable. – superluminal May 17 '19 at 17:50

0 Answers0