廣州做網(wǎng)站建設(shè)的公司泰安百度公司代理商
一、核心要義
以第九章定義的二維向量為基礎(chǔ),定義表示多為向量的Vector類。該類將支持如下功能:
1. 基本的序列協(xié)議
2. 適當(dāng)?shù)那衅С?#xff0c;且返回的是新Vector實(shí)例
3.綜合各個(gè)元素的值計(jì)算散列值
4.格式化展示
二、代碼示例
1、前情提要
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/2/17 13:56
# @Author : Maple
# @File : 00-相關(guān)背景知識(shí).py
# @Software: PyCharmclass MySeq:def __getitem__(self, index):return indexif __name__ == '__main__':# mylist = [1,2,3,4,5,6]# print(mylist[1:5:2]) # [2, 4]# 1. 自定義序列的getitem方法中的index測(cè)試s = MySeq()## 1-1 單個(gè)索引,index返回的是整數(shù)print(s[1])## 1-2 1:4 返回的是slice(1, 4, None),其中1是序列的起始位置,4是結(jié)束位置,而且是左閉右開,即[1,4)print(s[1:4]) # slice(1, 4, None)## 1-3 1:4:2 返回的是slice(1, 4, 2),其中1是序列的起始位置,4是結(jié)束位置,2代表步長(zhǎng)print(s[1:4:2]) # slice(1, 4, 2)## 1-4 復(fù)合切片1print(s[1:4:2,9]) # (slice(1, 4, 2), 9)#1-5 復(fù)合切片2print(s[1:4:2,7:9]) #(slice(1, 4, 2), slice(7, 9, None))# 2.slice測(cè)試"""slice是Python內(nèi)置的類型"""##2-1 slice有一個(gè)indices方法, 以及start,step和stop三個(gè)數(shù)據(jù)屬性print(dir(slice)) # [..'indices', 'start', 'step', 'stop']]##2-2 而indices方法主要是用于優(yōu)雅地處理缺失索引和負(fù)索引,以及長(zhǎng)度超過目標(biāo)序列的切片### 2-2-1 對(duì)一個(gè)長(zhǎng)度為5的序列,進(jìn)行切片,其中起始位置缺失,結(jié)束位置為10(很顯然已經(jīng)超過了序列長(zhǎng)度),步長(zhǎng)為2### indices方法會(huì)幫忙將切片調(diào)整為 :(0, 5, 2)print(slice(None,10,2).indices(5))### 2-2-2 對(duì)一個(gè)長(zhǎng)度為5的序列,進(jìn)行切片,其中起始位置為-3,結(jié)束位置未知,步長(zhǎng)未知### indices方法會(huì)幫忙將切片調(diào)整為 :(2, 5, 1)print(slice(-3,None,None).indices(5))# 3. 格式化測(cè)試name = 'maple'age = 18print('{name!r} and {age!r}'.format(name= name,age= age)) # 'maple' and 18print('{!r} and {!r}'.format(name,age)) # 'maple' and 18,不能使用關(guān)鍵字參數(shù)傳遞print('{name!r} and {!r}'.format(age,name=name)) # 'maple' and 18,positional argument要放在前面
2、Vector類的改造
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/2/17 14:19
# @Author : Maple
# @File : 01-Vector類的改造.py
# @Software: PyCharm"""相對(duì)于第9章的Vector類-構(gòu)造方法是傳入形如(1,2)這樣的二元元組本章的Vector類
-(1)首先是可以接收任意多個(gè)參數(shù)
-(2)構(gòu)造方法傳入的是可迭代的對(duì)象
"""
import math
import reprlib
from array import arrayclass Vector:typecode = 'd'def __init__(self,components):self._components = array(self.typecode,components)def __repr__(self):# 返回的components是str類型components = reprlib.repr(self._components)components = components[components.find('['):-1]return 'Vector({})'.format(components)def __str__(self):return str(tuple(self))def __iter__(self):return iter(self._components)def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(self._components))def __eq__(self, other):return tuple(self) == tuple(other)def __bool__(self):return bool(abs(self))def __abs__(self):return math.sqrt(sum(x * x for x in self._components))@classmethoddef frombytes(cls,octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(memv)if __name__ == '__main__':v = Vector([1,2,3,4])print('*******1. repr測(cè)試*****************')# 1. repr測(cè)試 :如果沒有定義str方法,print(v)會(huì)調(diào)用__repr__方法print(v) # Vector([1.0, 2.0, 3.0, 4.0])# 2.str測(cè)試print('*******2. str測(cè)試*****************')print(v) # (1.0, 2.0, 3.0, 4.0)# 3.相等性測(cè)試print('*******3.相等性測(cè)試*****************')v2 = Vector([1,2,3,4])print(v is v2) # False,不同的對(duì)象print(v == v2) # False,值相等# 4.迭代測(cè)試print('*******4.迭代測(cè)試****************')for i in v:"""1.02.03.04.0
"""print(i)# 5.模長(zhǎng)(abs)測(cè)試print('*******5.模長(zhǎng)(abs)測(cè)試****************')print(abs(v)) # 5.477225575051661# 6. bytes測(cè)試print('*******6. bytes測(cè)試****************')print(bytes(v)) # b'd\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x08@\x00\x00\x00\x00\x00\x00\x10@#7. frombytes測(cè)試print('*******7. frombytes測(cè)試****************')v_byte = bytes(v)v_clone = Vector.frombytes(v_byte)print(v ==v_clone)# 8. 切片測(cè)試: 未實(shí)現(xiàn)getitem方法,無法使用切片print(v[1:3]) # TypeError: 'Vector' object is not subscriptable
3、Vector類切片功能實(shí)現(xiàn)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/2/17 14:57
# @Author : Maple
# @File : 02-Vector類切片功能實(shí)現(xiàn).py
# @Software: PyCharm#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/2/17 14:19
# @Author : Maple
# @File : 01-Vector類的改造.py
# @Software: PyCharm"""相對(duì)于第9章的Vector類-構(gòu)造方法是傳入形如(1,2)這樣的二元元組本章的Vector類
-(1)首先是可以接收任意多個(gè)參數(shù)
-(2)構(gòu)造方法傳入的是可迭代的對(duì)象
"""
import math
import numbers
import reprlib
from array import arrayclass Vector:"""切片返回?cái)?shù)組"""typecode = 'd'def __init__(self,components):self._components = array(self.typecode,components)def __repr__(self):# 返回的components是str類型components = reprlib.repr(self._components)components = components[components.find('['):-1]return 'Vector({})'.format(components)def __str__(self):return str(tuple(self))def __iter__(self):return iter(self._components)def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(self._components))def __eq__(self, other):return tuple(self) == tuple(other)def __bool__(self):return bool(abs(self))def __abs__(self):return math.sqrt(sum(x * x for x in self._components))@classmethoddef frombytes(cls,octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(memv)def __len__(self):return len(self._components)def __getitem__(self, index):# index是一個(gè)slice類型數(shù)據(jù),返回?cái)?shù)組return self._components[index]class Vector2:"""切片仍然返回Vector類型數(shù)據(jù)"""typecode = 'd'def __init__(self,components):self._components = array(self.typecode,components)def __repr__(self):# 返回的components是str類型components = reprlib.repr(self._components)components = components[components.find('['):-1]return 'Vector({})'.format(components)def __str__(self):return str(tuple(self))def __iter__(self):return iter(self._components)def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(self._components))def __eq__(self, other):return tuple(self) == tuple(other)def __bool__(self):return bool(abs(self))def __abs__(self):return math.sqrt(sum(x * x for x in self._components))@classmethoddef frombytes(cls,octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(memv)def __len__(self):return len(self._components)def __getitem__(self, index):cls = type(self)if isinstance(index,slice):return cls(self._components[index])elif isinstance(index,numbers.Integral):return self._components[index]else:msg = '{cls.__name__} indices must be integers'return TypeError(msg.format(cls = cls))if __name__ == '__main__':v = Vector([1,2,3,4,5])# 1. 切片測(cè)試:返回的是數(shù)組print(v[1]) # 2.0print(v[1:3]) # array('d', [2.0, 3.0])print(v[1:5:2]) # array('d', [2.0, 4.0])# slice(1,5,2)print(v[-4:10:2]) # array('d', [2.0, 4.0])# 2. 切片測(cè)試:返回的是Vector類型數(shù)據(jù)v2 = Vector2([1, 2, 3, 4, 5])print(v2[1]) # 2.0print(v2[1:3]) # (2.0, 3.0)print(v2[1:5:2]) # (2.0, 4.0)print(v2[1.0]) # Vector2 indices must be integers
4、Vector類動(dòng)態(tài)存取屬性
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/2/17 15:10
# @Author : Maple
# @File : 03-Vector類動(dòng)態(tài)存取屬性.py
# @Software: PyCharm
import numbers
import reprlib
from array import arrayclass Vector:"""實(shí)現(xiàn)能夠通過單個(gè)變量訪問前幾個(gè)分量,比如 v.x,v.y等實(shí)現(xiàn)方式: getattr方法"""typecode = 'd'shortcut_names = 'xyzt'def __init__(self,components):self._components = array(self.typecode,components)def __repr__(self):# 返回的components是str類型components = reprlib.repr(self._components)components = components[components.find('['):-1]return 'Vector({})'.format(components)def __str__(self):return str(tuple(self))def __iter__(self):return iter(self._components)def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(self._components))def __eq__(self, other):return tuple(self) == tuple(other)def __bool__(self):return bool(abs(self))def __abs__(self):return math.sqrt(sum(x * x for x in self._components))@classmethoddef frombytes(cls,octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(memv)def __len__(self):return len(self._components)def __getitem__(self, index):cls = type(self)if isinstance(index,slice):return cls(self._components[index])elif isinstance(index,numbers.Integral):return self._components[index]else:msg = '{cls.__name__} indices must be integers'return TypeError(msg.format(cls = cls))def __getattr__(self, item):# 只有當(dāng)v.x實(shí)例不存在x屬性時(shí),才會(huì)調(diào)用getattrcls = type(self)if len(item) == 1:position = cls.shortcut_names.find(item)if 0 <= position < len(self._components):return self._components[position]msg = '{.__name__!r} object has not attribute {!r}'raise AttributeError(msg.format(cls,item))class Vector2:"""實(shí)現(xiàn)能夠通過單個(gè)變量訪問前幾個(gè)分量,比如 v.x,v.y等實(shí)現(xiàn)方式: getattr方法"""typecode = 'd'shortcut_names = 'xyzt'def __init__(self, components):self._components = array(self.typecode, components)def __repr__(self):# 返回的components是str類型components = reprlib.repr(self._components)components = components[components.find('['):-1]return 'Vector({})'.format(components)def __str__(self):return str(tuple(self))def __iter__(self):return iter(self._components)def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(self._components))def __eq__(self, other):return tuple(self) == tuple(other)def __bool__(self):return bool(abs(self))def __abs__(self):return math.sqrt(sum(x * x for x in self._components))@classmethoddef frombytes(cls, octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(memv)def __len__(self):return len(self._components)def __getitem__(self, index):cls = type(self)if isinstance(index, slice):return cls(self._components[index])elif isinstance(index, numbers.Integral):return self._components[index]else:msg = '{cls.__name__} indices must be integers'return TypeError(msg.format(cls=cls))def __getattr__(self, item):# 只有當(dāng)v.x實(shí)例不存在x屬性時(shí),才會(huì)調(diào)用getattrcls = type(self)if len(item) == 1:position = cls.shortcut_names.find(item)if 0 <= position < len(self._components):return self._components[position]msg = '{.__name__!r} object has not attribute {!r}'raise AttributeError(msg.format(cls, item))def __setattr__(self, name, value):cls = type(self)if len(name) == 1:# 限制修改'xyzt'單字母屬性值if name in cls.shortcut_names:error = 'readonly attribute {attr_name!r}'elif name.islower():# 限制修改單字母(a-z)的屬性值error = "can't set attributes 'a' to 'z' in {cls_name}!r"else:error = ''if error:msg = error.format(cls_name=cls, attr_name=name)raise AttributeError(msg)# 允許修改名字為其它值的屬性super().__setattr__(name, value)if __name__ == '__main__':# 1.未設(shè)置setattr方法時(shí)的測(cè)試v = Vector([1,2,3,4,5])print(v.x) # 1.0# print(v.q) # 'Vector' object has not attribute 'q'v.x = 10# 當(dāng)設(shè)置了v.x = 10之后,相當(dāng)于給v實(shí)例新增了屬性x(self.x = x),之后再訪問v.x,不會(huì)走getattr方法,而是直接訪問實(shí)例v的屬性x的值print(v.x) # 10# 但是v的第一個(gè)分量值仍然為1.0,并沒有發(fā)生變化(也正常,畢竟getattr方法也沒有修改_components的值)# 但是上述兩條結(jié)果時(shí)矛盾的:v.x(本意是對(duì)應(yīng)實(shí)例v的第一個(gè)分量)的值發(fā)生了變化,但是通過直接訪問v-的第一個(gè)分量值卻又沒有發(fā)生變化# 為了避免上述矛盾,可以通過setattr方法,限制修改`單字母`屬性的值print(v) # (1.0, 2.0, 3.0, 4.0, 5.0)# 2. 設(shè)置setattr方法時(shí)的測(cè)試print('*********2. 設(shè)置setattr方法時(shí)的測(cè)試************')v2 = Vector2([1, 2, 3, 4, 5])print(v2.x)## 2-1 嘗試修改v2.x的值#v2.x = 10 # AttributeError: readonly attribute 'x'## 2-2 嘗試修改[a-z]之間某個(gè)單值屬性的值#v2.a = 100 # AttributeError: can't set attributes 'a' to 'z' in <class '__main__.Vector2'>!r## 2-3 嘗試修改名字為其它值的屬性v2.name = 'Maple'# 修改成功print(v2.name) # Maple# 3.散列測(cè)試v3 = Vector2([1, 2, 3, 4, 5])v4 = Vector2([1, 2, 3, 4, 5])# 未實(shí)現(xiàn)hash方法,不能散列化set([v3,v4]) #TypeError: unhashable type: 'Vector2'
5、Vector類實(shí)現(xiàn)散列化
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/2/17 17:26
# @Author : Maple
# @File : 04-Vector類實(shí)現(xiàn)散列化.py
# @Software: PyCharmimport functools
import numbers
import operator
import reprlib
from array import array"""
實(shí)現(xiàn)__eq__(已實(shí)現(xiàn),為提升效率,改寫以下)和__hash__
"""class Vector:typecode = 'd'shortcut_names = 'xyzt'def __init__(self, components):self._components = array(self.typecode, components)def __repr__(self):# 返回的components是str類型components = reprlib.repr(self._components)components = components[components.find('['):-1]return 'Vector({})'.format(components)def __str__(self):return str(tuple(self))def __iter__(self):return iter(self._components)def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(self._components))def __bool__(self):return bool(abs(self))def __abs__(self):return math.sqrt(sum(x * x for x in self._components))@classmethoddef frombytes(cls, octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(memv)def __len__(self):return len(self._components)def __getitem__(self, index):cls = type(self)if isinstance(index, slice):return cls(self._components[index])elif isinstance(index, numbers.Integral):return self._components[index]else:msg = '{cls.__name__} indices must be integers'return TypeError(msg.format(cls=cls))def __getattr__(self, item):# 只有當(dāng)v.x實(shí)例不存在x屬性時(shí),才會(huì)調(diào)用getattrcls = type(self)if len(item) == 1:position = cls.shortcut_names.find(item)if 0 <= position < len(self._components):return self._components[position]msg = '{.__name__!r} object has not attribute {!r}'raise AttributeError(msg.format(cls, item))def __setattr__(self, name, value):cls = type(self)if len(name) == 1:# 限制修改'xyzt'單字母屬性值if name in cls.shortcut_names:error = 'readonly attribute {attr_name!r}'elif name.islower():# 限制修改單字母(a-z)的屬性值error = "can't set attributes 'a' to 'z' in {cls_name}!r"else:error = ''if error:msg = error.format(cls_name=cls, attr_name=name)raise AttributeError(msg)# 允許修改名字為其它值的屬性super().__setattr__(name, value)def __eq__(self, other):# 如果分量太多,下面這種方式效率太低# return tuple(self) == tuple(other)if len(self) != len(other):return Falsefor x, y in zip(self, other):if x != y:return Falsereturn Truedef __hash__(self):# 生成一個(gè)迭代器hashes = (hash(x) for x in self._components)return functools.reduce(operator.xor, hashes, 0)# 等價(jià)于下面的寫法# return functools.reduce(lambda x,y : x *y ,hashes,0)if __name__ == '__main__':v1 = Vector([1, 2, 3, 4, 5])v2 = Vector([1, 2, 3, 4, 5])print(set([v1, v2])) # {Vector([1.0, 2.0, 3.0, 4.0, 5.0])}
6、Vector類格式化
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/2/17 17:38
# @Author : Maple
# @File : 05-Vector類格式化.py
# @Software: PyCharmimport functools
import itertools
import math
import numbers
import operator
import reprlib
from array import arrayclass Vector:typecode = 'd'shortcut_names = 'xyzt'def __init__(self, components):self._components = array(self.typecode, components)def __repr__(self):# 返回的components是str類型components = reprlib.repr(self._components)components = components[components.find('['):-1]return 'Vector({})'.format(components)def __str__(self):return str(tuple(self))def __iter__(self):return iter(self._components)def __bytes__(self):return (bytes([ord(self.typecode)]) + bytes(self._components))def __bool__(self):return bool(abs(self))def __abs__(self):return math.sqrt(sum(x * x for x in self._components))@classmethoddef frombytes(cls, octets):typecode = chr(octets[0])memv = memoryview(octets[1:]).cast(typecode)return cls(memv)def __len__(self):return len(self._components)def __getitem__(self, index):cls = type(self)if isinstance(index, slice):return cls(self._components[index])elif isinstance(index, numbers.Integral):return self._components[index]else:msg = '{cls.__name__} indices must be integers'return TypeError(msg.format(cls=cls))def __getattr__(self, item):# 只有當(dāng)v.x實(shí)例不存在x屬性時(shí),才會(huì)調(diào)用getattrcls = type(self)if len(item) == 1:position = cls.shortcut_names.find(item)if 0 <= position < len(self._components):return self._components[position]msg = '{.__name__!r} object has not attribute {!r}'raise AttributeError(msg.format(cls, item))def __setattr__(self, name, value):cls = type(self)if len(name) == 1:# 限制修改'xyzt'單字母屬性值if name in cls.shortcut_names:error = 'readonly attribute {attr_name!r}'elif name.islower():# 限制修改單字母(a-z)的屬性值error = "can't set attributes 'a' to 'z' in {cls_name}!r"else:error = ''if error:msg = error.format(cls_name=cls, attr_name=name)raise AttributeError(msg)# 允許修改名字為其它值的屬性super().__setattr__(name, value)def __eq__(self, other):# 如果分量太多,下面這種方式效率太低# return tuple(self) == tuple(other)if len(self) != len(other):return Falsefor x, y in zip(self, other):if x != y:return Falsereturn Truedef __hash__(self):# 生成一個(gè)迭代器hashes = (hash(x) for x in self._components)return functools.reduce(operator.xor, hashes, 0)# 等價(jià)于下面的寫法# return functools.reduce(lambda x,y : x *y ,hashes,0)# 計(jì)算n維球體的某個(gè)角坐標(biāo)def angle(self,n):r = math.sqrt(sum(x * x for x in self[n:]))a = math.atan2(r,self[n-1])if (n == len(self) - 1) and (self[-1] < 0):return math.pi * 2 - 1else:return adef angles(self):return (self.angle(n) for n in range(1,len(self)))def __format__(self, fmt_spec):if fmt_spec.endswith('h'): # 超球面體fmt_spec = fmt_spec[:-1]coords = itertools.chain([abs(self)],self.angles())outer_format = '<{}>'else:coords = selfouter_format = '({})'components = (format(c,fmt_spec) for c in coords)return outer_format.format(', '.join(components))if __name__ == '__main__':# 格式化輸出測(cè)試v1 = Vector([1, 2, 3, 4, 5])# 球面極坐標(biāo)輸出print(format(v1,'.2fh')) # <7.42, 1.44, 1.30, 1.13, 0.90># 其它正常格式輸出print(format(v1,'.2f')) # (1.00, 2.00, 3.00, 4.00, 5.00)print(format(v1,'.2e')) #(1.00e+00, 2.00e+00, 3.00e+00, 4.00e+00, 5.00e+00)