簡體   English   中英

Python 向量類

[英]Python Vector Class

我來自 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))

如果我正確理解你的問題,你想要這樣的東西嗎?

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)公開它們; 我使用 lambda 語句縮寫了“getter”。

請注意,在 Python 中,直接在對象本身上操作這些值(例如:x、y、z)是很常見的(我猜你想確保顯式浮點轉換?)

編輯:我已經用@unutbu 的原始答案修改了代碼,以簡化它並使正在做的事情更清楚。 在最新版本中, @staticmethod已完全消除並替換為嵌套的單行。 外部函數和嵌套類已重命名為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

我可能誤讀了您的問題,但我認為您想要的已經在collections.namedtuple為您制作:

 >>> from collections import namedtuple >>> Vector = namedtuple('Vector', 'xy z') >>> v = Vector(0, 0, 0) >>> v Vector(x=0, y=0, z=0) >>> vx = 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 或者你可能想完全放棄這個想法並使用不同的東西。 關鍵是這個答案是錯誤的,我會刪除它,除非我覺得有義務給我投票的人糾正我的錯誤。

這是你要找的嗎?

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

編輯:我之前的回答試圖制作一個通用的 AutoProperties 元類,我希望它可以通用。 正如@martineau 的回答所示,專門針對Vector類的解決方案可以使事情變得更簡單。

這是沿着這些路線的另一個想法(專門的簡單性而不是廣義的復雜性)。 它使用類裝飾器(我認為它比元類更容易理解)和@martineau 使用默認值簡化 getter 和 setter 的想法:

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

原始答案:這是一種在定義許多相似屬性時避免重復樣板代碼的方法。

我試圖使解決方案合理通用,因此它可能對除此特定情況之外的其他情況下的人們有用。

要使用它,您需要做兩件事:

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

    在你的類定義的開頭。 您可以根據需要列出(作為字符串)任意數量的屬性(例如xyz )。 AutoProperties會將它們變成屬性。

  2. 您的類,例如Vector ,需要定義靜態方法_auto_setter_auto_getter 它們接受一個參數,即作為字符串的屬性名稱,並分別返回該屬性的 setter 或 getter 函數。

使用元類自動設置屬性的想法來自 Guido Rossum 關於屬性和元類的文章。 在那里他定義了一個類似於我在下面使用的autoprop元類。 主要區別在於AutoProperties期望用戶定義 getter 和 setter工廠,而不是手動定義 getter 和 setter。

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

我真的不明白這個問題。 你有一個向量,它用 3 個坐標描述空間中的一個點。 您的實現已經允許您更改值:

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

為什么它應該返回一個元組? 你會用它做什么? 也就是說,元組是不可變的,因此無法修改,但您可以使用列表。 但是,更改該列表中的數字不會反映在 Vector 中。

如果您確實需要確保類型是浮點數,請考慮屬性設置器

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

你可以很容易地表示你的向量這樣做:

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

當您使用__ ... __執行方法時,就像 Java 上的@Override

我明白那個

  1. 您想要一個將輸入值轉換為浮點數的過濾器
  2. 你不想寫三遍屬性

您可以使用以下代碼:

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM