Search code examples
pythonclassobjectvectormaya

Python Vector Class


I'm coming from a C# background where this stuff is super easy—trying to translate into Python for Maya.

There's gotta' be a better way to do this. Basically, I'm looking to create a Vector class that will simply have x, y and z coordinates, but it would be ideal if this class returned a tuple with all 3 coordinates and if you could edit the values of this tuple through x, y and z properties, somehow.

This is what I have so far, but there must be a better way to do this than using an exec statement, right? I hate using exec statements.

class Vector(object):
    '''Creates a Maya vector/triple, having x, y and z coordinates as float values'''

    def __init__(self, x=0, y=0, z=0):
        self.x, self.y, self.z = x, y, z

    def attrsetter(attr):
        def set_float(self, value):
            setattr(self, attr, float(value))
        return set_float

    for xyz in 'xyz':
        exec("%s = property(fget=attrgetter('_%s'), fset=attrsetter('_%s'))" % (xyz, xyz, xyz))

Solution

  • Edit: I've modified the code with my answer a bit more from @unutbu's original to simplify it and make what is being done clearer. In the latest version, the @staticmethod's have been eliminated altogether and replaced with nested one-liners. The outer function and nested class have been renamed AutoFloatProperties and _AutoFloatProperties to reflect their specialized behavior of converting and storing the values assigned as floats. Despite all this, @unutbu's own revised answer using a class decorator instead of a metaclass is a slightly simpler solution, although the internals and usage are very similar.

    def AutoFloatProperties(*props):
        '''metaclass'''
        class _AutoFloatProperties(type):
            # Inspired by autoprop (http://www.python.org/download/releases/2.2.3/descrintro/#metaclass_examples)
            def __init__(cls, name, bases, cdict):
                super(_AutoFloatProperties, cls).__init__(name, bases, cdict)
                for attr in props:
                    def fget(self, _attr='_'+attr): return getattr(self, _attr)
                    def fset(self, value, _attr='_'+attr): setattr(self, _attr, float(value))
                    setattr(cls, attr, property(fget, fset))
        return _AutoFloatProperties
    
    class Vector(object):
        '''Creates a Maya vector/triple, having x, y and z coordinates as float values'''
        __metaclass__ = AutoFloatProperties('x','y','z')
        def __init__(self, x=0, y=0, z=0):
            self.x, self.y, self.z = x, y, z # values converted to float via properties
    
    if __name__=='__main__':
        v=Vector(1,2,3)
        print(v.x)
        # 1.0
        v.x=4
        print(v.x)
        # 4.0