Pregunta

Estoy viniendo de un fondo de C #, donde este material es muy fácil de tratar de traducir en Python para Maya.

Tiene que' haber una mejor manera de hacer esto. Básicamente, estoy buscando para crear una clase de vectores que simplemente tienen coordenadas x, y, z, pero sería ideal si esta clase devuelve una tupla con las 3 coordenadas y si se podía editar los valores de esta tupla a través de X, propiedades y y z, de alguna manera.

Esto es lo que tengo hasta ahora, pero hay debe haber una mejor manera de hacerlo que mediante una instrucción exec, ¿verdad? No me gusta usar declaraciones Exec.

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))
¿Fue útil?

Solución

Editar He modificado el código con mi respuesta un poco más de @ de originales para simplificar y hacer lo que se hace más clara unutbu. En la última versión, la década de @staticmethod se han eliminado por completo y se reemplaza con anidados de una sola línea. La función externa y la clase anidada han cambiado de nombre y AutoFloatProperties _AutoFloatProperties para reflejar su comportamiento especializado de la conversión y el almacenamiento de los valores asignados como flotadores. A pesar de todo esto, la propia respuesta revisada @ de unutbu usando un decorador de clase en lugar de una metaclase es una solución un poco más sencillo, aunque los componentes internos y el uso son muy similares.

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

Otros consejos

Si entiendo bien su pregunta, usted quiere algo como esto?

class Vector(object):

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

    def setx(self, x): self._x = float(x)
    def sety(self, y): self._y = float(y)        
    def setz(self, z): self._z = float(z)     

    x = property(lambda self: float(self._x), setx)
    y = property(lambda self: float(self._y), sety)
    z = property(lambda self: float(self._z), setz)

Esto utiliza _x, _y y _z a (internamente) almacenar los valores de entrada y los expone a través del uso de propiedad (con captadores, organismos); Me abreviado los captadores '' mediante una instrucción lambda.

Tenga en cuenta que en Python sería muy común para manipular estos valores (por ejemplo: x, y, z) en el objeto en sí directamente (? Creo que se quiere asegurar el flotador explícita de los contenedores)

I se puede leer mal su pregunta, pero creo que lo que quiere ya está hecho para usted en collections.namedtuple :

>>> from collections import namedtuple
>>> Vector = namedtuple('Vector', 'x y z')
>>> v = Vector(0, 0, 0)
>>> v
Vector(x=0, y=0, z=0)
>>> v.x = 10
>>> v
Vector(x=10, y=0, z=0)
>>> tuple(v)
(10, 0, 0)
>>> v._asdict()
{'x': 10, 'y': 0, 'z': 0}
>>>

Cómo se ve sobre la derecha?

Para vergüenza, me olvidé de que las tuplas son inmutables. maldecirme por no actualizar desde Python 2.5 así que podría haber hecho probado el código que he escrito. De todos modos, es posible que desee algo muy similar a collections.namedtuple, excepto más como un namedlist hipotético. O puede que quiera descartar esa idea por completo y usar algo diferente. El punto es que esta respuesta era incorrecta, y me gustaría eliminarlo, excepto que me siento obligado a la gente que me upvoted para corregir mi error.

Es esto lo que está buscando?

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

    # overload []
    def __getitem__(self, index):
        data = [self.x,self.y,self.z]
        return data[index]

    # overload set []
    def __setitem__(self, key, item):
        if (key == 0):
            self.x = item
        elif (key == 1):
            self.y = item
        elif (key == 2):
            self.z = item
        #TODO: Default should throw excetion

Esta es la forma más ingenua de hacerlo. Estoy seguro de que algún gurú Python va a llegar mueca en mi código y sustituirla por una sola línea.

Ejemplos de este código:

v = vector(1,2,3)
v[1] = 4
v[2] = 5

v.x = 1
v.z= 66

Editar Mi respuesta anterior intentó hacer una autoproperties metaclase generalizada que esperaba podría ser de uso general. Como respuesta @ de Martineau muestra una solución especializada para la clase Vector puede hacer las cosas más simples.

Aquí hay otra idea en ese sentido (simplicidad especializada sobre la complejidad generalizada). Se utiliza un decorador de clase (que creo que es un poco más sencillo de entender que una metaclase) y la idea de @ martineau de simplificar los captadores y definidores con valores por defecto:

def AutoProperties(*props):
    def _AutoProperties(cls):
        for attr in props:
            def getter(self,_attr='_'+attr):
                return getattr(self, _attr)
            def setter(self, value, _attr='_'+attr):
                setattr(self, _attr, float(value))
            setattr(cls,attr,property(getter,setter))
        return cls
    return _AutoProperties

@AutoProperties('x','y','z')
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 = map(float,(x, y, z))

Respuesta original: Aquí es una manera de evitar la repetición de código caldera-placa al definir muchas propiedades similares.

He tratado de hacer que la solución razonable en general, por lo que podría ser de utilidad para las personas en otras situaciones lado de éste en particular.

Para usarlo necesita hacer 2 cosas:

  1. Poner

        __metaclass__=AutoProperties(('x','y','z'))
    

    al principio de la definición de la clase. Puede crear una lista (como cadenas) como muchos atributos (por ejemplo x, y, z) como desee. AutoProperties los convertirá en propiedades.

  2. Su clase, por ejemplo, Vector, necesita definir staticmethods _auto_setter y _auto_getter. Ellos toman un argumento, el nombre del atributo como una cadena, y devuelven la función de incubadora o comprador, respectivamente, para ese atributo.

La idea de utilizar metaclases para configurar automáticamente las propiedades proviene de ensayo de Guido Rossum en propiedades y metaclases . Allí se define un autoprop metaclase similar a lo que yo uso a continuación. La diferencia principal es que AutoProperties espera que el usuario defina getter y setter fábricas en lugar de captadores y definidores definidos manualmente.

def AutoProperties(props):
    class _AutoProperties(type):
        # Inspired by autoprop (http://www.python.org/download/releases/2.2.3/descrintro/)
        def __init__(cls, name, bases, cdict):
            super(_AutoProperties, cls).__init__(name, bases, cdict)
            for attr in props:
                fget=cls._auto_getter(attr)
                fset=cls._auto_setter(attr)
                setattr(cls,attr,property(fget,fset))
    return _AutoProperties

class Vector(object):
    '''Creates a Maya vector/triple, having x, y and z coordinates as float values'''
    __metaclass__=AutoProperties(('x','y','z'))
    def __init__(self, x=0, y=0, z=0):
        # I assume you want the initial values to be converted to floats too.
        self._x, self._y, self._z = map(float,(x, y, z))
    @staticmethod
    def _auto_setter(attr):
        def set_float(self, value):
            setattr(self, '_'+attr, float(value))
        return set_float
    @staticmethod   
    def _auto_getter(attr):
        def get_float(self):
            return getattr(self, '_'+attr)
        return get_float

if __name__=='__main__':
    v=Vector(1,2,3)
    print(v.x)
    # 1.0
    v.x=4
    print(v.x)
    # 4.0

Realmente no entiendo la pregunta. Usted tiene un vector que describe un punto en el espacio de 3 coordenadas. Su aplicación ya se le permite cambiar los valores:

v = Vector()
v.x = 10 # now x is 10

¿por qué debería devolver un par de valores? ¿Para qué lo usarías? Dicho esto, una tupla es inmutable por lo que no se puede modificar, pero se puede utilizar una lista. Cambiar los números en esa lista no reflejará en el vector embargo.

Si es necesario para asegurar el tipo es un flotador, considere emisores de propiedad :

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        print "x set to ", value
        self._x = value

c = C()
c.x = 10

print c.x, c._x

Puede fácil representara su vector de hacer esto:

def __repr__(self):
   return "(%.1f, %.1f, %.1f)" % (self.x, self.y, self.z)

Cuando lo haga con métodos __ ... __ es como @Override en Java.

Entiendo que

  1. que desea tener un filtro que transforma los valores de entrada en flotadores
  2. No quiero escribir la propiedad tres veces

Se puede utilizar el siguiente código:

class Vector(object):
    def __init__(self, x,y,z):
         self._x = x

def mangle(name):
return '_'+name

for name in ['x','y','z']:
    def set_xyz(self, value):
        self.__setattr__(mangle(name), float(value))
    def get_xyz(self):
        return self.__getattribute__(mangle(name))
    prop = property(get_xyz, set_xyz)
    setattr(Vector,name, prop)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top