構(gòu)建四元數(shù)對象四元數(shù)是一個代數(shù)概念,通常用于描述旋轉(zhuǎn),特別是在3D建模和游戲中有廣泛的應(yīng)用。 下面就一步一步演示此對象的創(chuàng)建方法,特別要關(guān)注雙下劃線開始和結(jié)束的那些特殊方法。 class Quaternion: def __init__(self, w, x, y, z): self.w = w self.x = x self.y = y self.z = z 這是首先定義了__init__初始化方法,通過這個方法,在創(chuàng)建實例時將 分別定義為實數(shù)。
貌似一個四元數(shù)對象定義了。但是,它沒有友好的輸出。接下來可以通過定義__repr__和__str__,讓它對機(jī)器或者開發(fā)者都更友好。繼續(xù)在類中增加如下方法: class Quaternion: def __init__(self, w, x, y, z): self.w = w self.x = x self.y = y self.z = z def __repr__(self): return 'Quaternion({}, {}, {}, {})'.format( self.w, self.x, self.y, self.z) def __str__(self): return 'Q = {:.2f} + {:.2f}i + {:.2f}j + {:.2f}k'.format( self.w, self.x, self.y, self.z) 對于這兩方法,在前面的《Python中的5對必知的魔法方法》中已經(jīng)有介紹,請參考。
實現(xiàn)代數(shù)運(yùn)算上述類已經(jīng)能實現(xiàn)實例化了,但是,該對象還要參與計算,比如加、減法等。這類運(yùn)算如何實現(xiàn)? 加法class Quaternion: def __init__(self, w, x, y, z): self.w = w self.x = x self.y = y self.z = z def __repr__(self): return 'Quaternion({}, {}, {}, {})'.format( self.w, self.x, self.y, self.z) def __str__(self): return 'Q = {:.2f} + {:.2f}i + {:.2f}j + {:.2f}k'.format( self.w, self.x, self.y, self.z) def __add__(self, other): w = self.w + other.w x = self.x + other.x y = self.y + other.y z = self.z + other.z return Quaternion(w, x, y, z) __add__是用于實現(xiàn)對象的加法運(yùn)算的特殊方法。這樣就可以使用+運(yùn)算符了:
減法類似地,通過__sub__實現(xiàn)減法運(yùn)算,不過,這次用一行代碼實現(xiàn)。 class Quaternion: def __init__(self, w, x, y, z): self.w = w self.x = x self.y = y self.z = z def __repr__(self): return 'Quaternion({}, {}, {}, {})'.format( self.w, self.x, self.y, self.z) def __str__(self): return 'Q = {:.2f} + {:.2f}i + {:.2f}j + {:.2f}k'.format( self.w, self.x, self.y, self.z) def __add__(self, other): w = self.w + other.w x = self.x + other.x y = self.y + other.y z = self.z + other.z return Quaternion(w, x, y, z) def __sub__(self, other): return Quaternion(*list(map(lambda i, j: i - j, self.__dict__.values(), other.__dict__.values()))) 有點酷。這里使用了實例對象的__dict__屬性,它以字典形式包含了實例的所有屬性, 乘法乘法,如果了解一下線性代數(shù),會感覺有點復(fù)雜。其中常見的一個是“點積”,自從Python3.5以后,用@符號調(diào)用__matmul__方法實現(xiàn),對于四元數(shù)對象而言不能,就是元素與元素對應(yīng)相乘。 對于四元數(shù)而言——本質(zhì)就是向量,也可以說是矩陣,其乘法就跟矩陣乘法類似,比如,同樣不遵守互換率: 。
在__mul__方法中,如果other引用一個四元數(shù)對象,那么就會計算Hamilton積,并返回一個新的對象;如果other是一個標(biāo)量(比如整數(shù)),就會與四元數(shù)對象中的每個元素相乘。 如前所述,四元數(shù)的乘法不遵循交換律,但是,如果執(zhí)行2 * q1這樣的操作,按照上面的方式,會報錯——在上面的__mul__方法中解決了q1 * 2的運(yùn)算,而一般我們認(rèn)為這兩個計算是相同的。為此,定義了·rmul·來解決此問題: class Quaternion: def __init__(self, w, x, y, z): self.w = w self.x = x self.y = y self.z = z def __repr__(self): return 'Quaternion({}, {}, {}, {})'.format( self.w, self.x, self.y, self.z) def __str__(self): return 'Q = {:.2f} + {:.2f}i + {:.2f}j + {:.2f}k'.format( self.w, self.x, self.y, self.z) def __add__(self, other): w = self.w + other.w x = self.x + other.x y = self.y + other.y z = self.z + other.z return Quaternion(w, x, y, z) def __sub__(self, other): return Quaternion(*list(map(lambda i, j: i - j, self.__dict__.values(), other.__dict__.values()))) def __mul__(self, other): if isinstance(other, Quaternion): w = self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z x = self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y y = self.w * other.y + self.y * other.w + self.z * other.x - self.x * other.z z = self.w * other.z + self.z * other.w + self.x * other.y - self.y * other.x return Quaternion(w, x, y, z) elif isinstance(other, (int, float)): return Quaternion(*[other * i for i in self.__dict__.values()]) else: raise TypeError('Operation undefined.') def __rmul__(self, other): if isinstance(other, (int, float)): return self.__mul__(other) else: raise TypeError('Operation undefined.') 相等比較兩個四元數(shù)是否相等,可以通過定義__eq__方法來實現(xiàn)。
其他運(yùn)算下面的方法,也可以接續(xù)到前面的類中,不過就不是特殊放方法了。 from math import sqrtdef norm(self): return sqrt(sum([i**2 for i in self.__dict__.values()))def conjugate(self): x, y, z = -self.x, -self.y, -self.z return Quaterion(self.w, x, y, z)def normalize(self): norm = self.norm() return Quaternion(*[i / norm for in self.__dict__.values()])def inverse(self): qconj = self.conjugate() norm = self.norm() return Quaternion(*[i / norm for i in qconj.__dict__.values()]) 用這些方法實現(xiàn)了各自常見的操作。 通過本文的這個示例,可以更深刻理解雙下劃線的方法為編程帶來的便捷。 |
|