5

私は C# のバックグラウンドを持っており、この作業は非常に簡単で、Maya 用の Python に変換しようとしています。

これを行うにはもっと良い方法が必要です。基本的には、単純に x、y、z 座標を持つ Vector クラスを作成しようとしていますが、このクラスが 3 つの座標すべてを含むタプルを返し、x を介してこのタプルの値を編集できれば理想的です。どういうわけか、y および z プロパティ。

これは私がこれまでに持っているものですが、これを実行するには、exec ステートメントを使用するよりも良い方法があるはずですよね? 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))
4

8 に答える 8

5

私があなたの質問を正しく理解していれば、あなたはこのようなものが欲しいですか?

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)

これは、_x、_y、および _z を使用して、入力値を (内部的に) 格納し、プロパティ(getter、setter を使用) を使用してそれらを公開します。ラムダステートメントを使用して「ゲッター」を省略しました。

Python では、これらの値 (x、y、z など) をオブジェクト自体で直接操作するのが非常に一般的であることに注意してください(明示的な float キャストを確実にしたいと思いますか?)

于 2010-03-08T12:40:23.227 に答える
4

編集: @unutbuのオリジナルからもう少し回答を加えてコードを修正し、コードを簡素化し、何が行われているかをより明確にしました。最新バージョンでは、 は@staticmethod完全に削除され、ネストされたワンライナーに置き換えられました。外側の関数とネストされたクラスの名前が変更され、float として割り当てられた値を変換して格納する特殊な動作を反映するようになりましたAutoFloatProperties_AutoFloatPropertiesこれらすべてにもかかわらず、メタクラスの代わりにクラスデコレータを使用した@unutbu独自の改訂された回答は、内部構造と使用法が非常に似ていますが、少し単純なソリューションです.

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
于 2010-07-28T21:39:55.917 に答える
3

私はあなたの質問を誤解しているかもしれませんが、あなたが望むものはすでにあなたのために作られていると思います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}
>>>

それは正しいように見えますか?

残念なことに、タプルは不変であることを忘れていました。私が書いたコードを実際にテストできたので、Python 2.5 からアップグレードしなかったことを呪ってください。とにかく、collections.namedtuple仮想の のようなものを除いて、 に非常に似たものが必要になる場合がありますnamedlist。または、そのアイデアを完全に破棄して、別のものを使用することもできます。要点は、この答えは間違っていたということです。間違いを正すように私に賛成票を投じてくれた人々に義務を感じていることを除いて、私はそれを削除します。

于 2010-03-08T12:38:49.347 に答える
2

これはあなたが探しているものですか?

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

これは最も素朴な方法です。Python の第一人者が私のコードを嘲笑し、ワンライナーに置き換えることは間違いありません。

このコードの例:

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

v.x = 1
v.z= 66
于 2010-03-08T12:42:11.083 に答える
2

編集:私の以前の回答は、一般的な使用を望んでいた一般化された AutoProperties メタクラスを作成しようとしました。@martineauの回答が示すように、Vectorクラスに特化したソリューションは物事をより簡単にすることができます。

これらの方針に沿った別のアイデアを次に示します (一般化された複雑さに対する特殊化された単純さ)。クラスデコレータ(メタクラスよりも少し理解しやすいと思います)と、デフォルト値でゲッターとセッターを単純化する@martineauのアイデアを使用します。

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

元の回答: 多くの同様のプロパティを定義するときに定型コードを繰り返さないようにする方法を次に示します。

私は解決策を合理的に一般化しようとしたので、この特定の状況以外の他の状況の人々にも役立つかもしれません.

使用するには、次の 2 つのことを行う必要があります。

  1. 置く

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

    クラスの定義の先頭に。x必要な数の属性 (例: 、y、 ) を(文字列として) リストできzます。AutoPropertiesそれらをプロパティに変換します。

  2. あなたのクラス、例えばVectorは staticmethods_auto_setterとを定義する必要があります_auto_getter。これらは 1 つの引数 (文字列としての属性名) を取り、その属性のセッターまたはゲッター関数をそれぞれ返します。

メタクラスを使用してプロパティを自動的に設定するというアイデアは、プロパティとメタクラスに関する Guido Rossum のエッセイから来ています。そこで彼は、autoprop私が以下で使用するものと同様のメタクラスを定義しています。主な違いは、ゲッターとセッターを手動で定義するのではなく、ユーザーがゲッターとセッターのファクトリAutoPropertiesを定義することを期待していることです。

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
于 2010-03-08T18:59:44.860 に答える
1

質問がよくわかりません。3 つの座標を持つ空間内の点を表すベクトルがあります。実装では、すでに値を変更できます。

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

なぜタプルを返す必要があるのですか? 何に使うの?つまり、タプルは不変であるため変更できませんが、リストを使用できます。ただし、そのリストの数値を変更しても、Vector には反映されません。

型が float であることを確認する必要がある場合は、プロパティ セッターを検討してください。

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
于 2010-03-08T12:31:11.247 に答える
0

これを行うと、ベクトルを簡単に表現できます。

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

メソッドを使用するときは、Java__ ... __のようです。@Override

于 2015-05-14T18:50:20.113 に答える
-1

という事は承知しています

  1. 入力値を浮動小数点数に変換するフィルターが必要です
  2. プロパティを3回書きたくない

次のコードを使用できます。

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)
于 2010-03-08T12:46:41.043 に答える