Question

Je viens d'un milieu C # où ce genre de choses est super facile d'essayer de traduire en Python pour Maya.

Il doit y » être une meilleure façon de le faire. Au fond, je suis à la recherche pour créer une classe Vector qui va simplement avoir les coordonnées x, y et z, mais il serait idéal si cette classe est revenu un tuple avec les 3 coordonnées et si vous pouvez modifier les valeurs de ce tuple par x, propriétés y et z, en quelque sorte.

est ce que j'ai jusqu'à présent, mais doit être une meilleure façon de le faire que d'utiliser une instruction exec, non? Je déteste l'aide d'instructions 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))
Était-ce utile?

La solution

Modifier J'ai modifié le code avec ma réponse un peu plus de @ original de unutbu pour simplifier et faire ce qui est fait plus clair. Dans la dernière version, ont été éliminés de la @staticmethod de tout à fait et remplacé par une seule ligne imbriquées. La fonction externe et classe imbriquée ont été renommés AutoFloatProperties et _AutoFloatProperties pour refléter leur comportement spécialisé de la conversion et le stockage des valeurs attribuées comme flotteurs. Malgré tout cela, propre réponse révisée @ unutbu l'aide d'un décorateur de classe au lieu d'une méta-classe est une solution un peu plus simple, bien que les internes et l'utilisation sont très similaires.

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

Autres conseils

Si je comprends bien votre question, vous voulez quelque chose comme ça?

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)

Il utilise _x, _y et _z à (interne) stocker les valeurs entrantes et les expose par l'utilisation de propriété (avec getters, setters); Je les 'getters abrégé' en utilisant une instruction lambda.

Notez que dans Python serait très commun pour manipuler ces valeurs (par exemple: x, y, z) sur l'objet lui-même directement (? Je suppose que vous voulez assurer le flotteur explicite jette)

je peux être interprète mal votre question, mais je pense que ce que vous voulez est déjà fait pour vous dans 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}
>>>

Est-ce que l'air à peu près juste?

Pour la honte, j'oubliais que tuples sont immuables. maudis-moi pour ne pas la mise à niveau de Python 2.5 pour que je puisse avoir effectivement testé le code que j'ai écrit. Quoi qu'il en soit, vous voudrez peut-être quelque chose de tout à fait semblable à collections.namedtuple, à l'exception plus comme un namedlist hypothétique. Ou vous pouvez jeter cette idée tout à fait et utiliser quelque chose de différent. Le point est que cette réponse était fausse, et je le supprimer, sauf que je me sens obligé de ceux qui me upvoted pour corriger mon erreur.

Est-ce que vous cherchez?

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

Ceci est la façon la plus naïve de le faire. Je suis sûr que certains gourou de Python venir ricanement à mon code et le remplacer par un one-liner.

Des exemples de ce code:

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

v.x = 1
v.z= 66

Modifier Ma réponse précédente a essayé de faire une AutoProperties généralisée métaclasse que j'espérais pourrait être d'usage général. Comme la réponse de @ martineau montre une solution spécialisée à la classe Vector peut rendre les choses plus simples.

Voici une autre idée dans ces lignes (simplicité spécialisée sur la complexité généralisée). Il utilise un décorateur de classe (qui je pense est un peu plus simple à comprendre qu'une métaclasse) et l'idée de @ martineau de simplifier les accesseurs avec des valeurs par défaut:

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))

Réponse originale: Voici un moyen d'éviter de répéter le code-plaque de la chaudière lors de la définition de nombreuses propriétés similaires.

J'ai essayé de rendre la solution raisonnablement générale, de sorte qu'il pourrait être utile aux gens dans d'autres situations à côté celui-ci en particulier.

Pour l'utiliser, vous devez faire 2 choses:

  1. Mettre

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

    au début de la définition de votre classe. Vous pouvez lister (sous forme de chaînes) autant d'attributs (par exemple x, y, z) que vous le souhaitez. AutoProperties va les transformer en propriétés.

  2. Votre classe, par exemple Vector, doit définir staticmethods _auto_setter et _auto_getter. Ils prennent un argument, le nom d'attribut comme une chaîne, et le retour de la fonction setter ou getter, respectivement, pour cet attribut.

L'idée d'utiliser métaclasses pour définir les propriétés automatiquement vient de l'essai de Guido Rossum sur propriétés et métaclasses . Là, il définit un autoprop métaclasse semblable à ce que je l'utilise ci-dessous. La principale différence est que AutoProperties attend l'utilisateur de définir getter et setter usines au lieu de getters définis manuellement et sertisseurs.

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

Je ne comprends pas vraiment la question. Vous avez un vecteur qui décrit un point dans l'espace avec 3 coordonnées. Votre implémentation vous permet déjà de changer les valeurs:

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

pourquoi devrait-il retourner un tuple? Que voulez-vous utiliser? Cela dit, un tuple est immuable ne peut donc pas être modifiée, mais vous pouvez utiliser une liste. Modification des numéros dans cette liste ne reflète pas dans le Vector bien.

Si vous avez besoin d'assurer que le type est un flotteur, tenez compte setters propriété :

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

Vous pouvez facilement Représentez votre vecteur faire ceci:

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

Quand vous faites avec des méthodes __ ... __ est comme @Override sur Java.

Je comprends que

  1. vous voulez avoir un filtre qui transforment les valeurs d'entrée en flotte
  2. vous ne voulez pas écrire la propriété trois fois

Vous pouvez utiliser le code suivant:

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)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top