Python中序列的修改、散列與切片詳解
前言
本文主要給大家介紹了關(guān)于Python中序列的修改、散列與切片的相關(guān)內(nèi)容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。
Vector類:用戶定義的序列類型
我們將使用組合模式實現(xiàn) Vector 類,而不使用繼承。向量的分量存儲在浮點數(shù)數(shù)組中,而且還將實現(xiàn)不可變扁平序列所需的方法。
Vector 類的第 1 版要盡量與前一章定義的 Vector2d 類兼容。
Vector類第1版:與Vector2d類兼容
Vector 類的第 1 版要盡量與前一章定義的 Vector2d 類兼容。然而我們會故意不讓 Vector 的構(gòu)造方法與 Vector2d 的構(gòu)造方法兼容。為了編寫 Vector(3, 4) 和 Vector(3, 4, 5) 這樣的代碼,我們可以讓 __init__ 方法接受任意個參數(shù)(通過 *args);但是,序列類型的構(gòu)造方法最好接受可迭代的對象為參數(shù),因為所有內(nèi)置的序列類型都是這樣做的。
測試 Vector.__init__ 和 Vector.__repr__ 方法
>>> Vector([3.1, 4.2]) Vector([3.1, 4.2]) >>> Vector((3, 4, 5)) Vector([3.0, 4.0, 5.0]) >>> Vector(range(10)) Vector([0.0, 1.0, 2.0, 3.0, 4.0, ...])
vector_v1.py:從 vector2d_v1.py 衍生而來
from array import array import reprlib import math class Vector: typecode = 'd' def __init__(self, components): self._components = array(self.typecode, components) #self._components是“受保護的”實例屬性,把Vector的分量保存在一個數(shù)組中 def __iter__(self): return iter(self._components) #為了迭代,我們使用self._components構(gòu)建一個迭代器 def __repr__(self): components = reprlib.repr(self._components) #使用reprlib.repr()函數(shù)獲取self._components 的有限長度表示形式(如 array('d', [0.0, 1.0, 2.0, 3.0, 4.0, ...])) components = components[components.find('['):-1] #把字符串插入 Vector 的構(gòu)造方法調(diào)用之前,去掉前面的array('d' 和后面的 ) return 'Vecotr({})'.format(components) #直接使用 self._components 構(gòu)建 bytes 對象 def __str__(self): return str(tuple(self)) def __bytes__(self): return (bytes([ord(self.typecode)]) + bytes(self._components)) def __eq__(self, other): return tuple(self) == tuple(other) def __abs__(self): return math.hypot(sum(x * x for x in self)) #不能使用hypot方法了,因此我們先計算各分量的平方之和,然后再使用sqrt方法開平方 def __bool__(self): return bool(abs(self)) @classmethod def frombytes(cls, octets): typedcode = chr(octets[0]) memv = memoryview(octets[1:]).cast(typedcode) return cls(memv) #我們只需在 Vector2d.frombytes 方法的基礎(chǔ)上改動最后一行:直接把memoryview傳給構(gòu)造方法,不用像前面那樣使用*拆包
協(xié)議和鴨子類型
在 Python 中創(chuàng)建功能完善的序列類型無需使用繼承,只需實現(xiàn)符合序列協(xié)議的方法。不過,這里說的協(xié)議是什么呢?
在面向?qū)ο缶幊讨?,協(xié)議是非正式的接口,只在文檔中定義,在代碼中不定義。例如,Python 的序列協(xié)議只需要 __len__ 和 __getitem__ 兩個方法。任何類(如 Spam),只要使用標準的簽名和語義實現(xiàn)了這兩個方法,就能用在任何期待序列的地方。Spam 是不是哪個類的子類無關(guān)緊要,只要提供了所需的方法即可。
class FrenchDeck: ranks = [str(n) for n in range(2, 11)] + list('JQKA') suits = 'spades diamonds clubs hearts'.split() def __init__(self): self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks] def __len__(self): return len(self._cards) def __getitem__(self, position): return self._cards[position]
協(xié)議是非正式的,沒有強制力,因此如果你知道類的具體使用場景,通常只需要實現(xiàn)一個協(xié)議的部分。例如,為了支持迭代,只需實現(xiàn)__getitem__ 方法,沒必要提供 __len__ 方法。
Vector類第2版:可切片的序列
如 FrenchDeck 類所示,如果能委托給對象中的序列屬性(如self._components
數(shù)組),支持序列協(xié)議特別簡單。下述只有一行代碼的 __len__ 和 __getitem__ 方法是個好的開始:
class Vector: # 省略了很多行 # ... def __len__(self): return len(self._components) def __getitem__(self, index): return self._components[index]
添加這兩個方法之后,就能執(zhí)行下述操作了:
>>> v1 = Vector([3, 4, 5]) >>> len(v1) >>> v1[0], v1[-1] (3.0, 5.0) >>> v7 = Vector(range(7)) >>> v7[1:4] array('d', [1.0, 2.0, 3.0])
可以看到,現(xiàn)在連切片都支持了,不過尚不完美。如果 Vector 實例的切片也是 Vector 實例,而不是數(shù)組,那就更好了。前面那個FrenchDeck 類也有類似的問題:切片得到的是列表。對 Vector 來說,如果切片生成普通的數(shù)組,將會缺失大量功能。
為了把 Vector 實例的切片也變成 Vector 實例,我們不能簡單地委托給數(shù)組切片。我們要分析傳給 __getitem__ 方法的參數(shù),做適當?shù)奶幚怼?/p>
切片原理
了解 __getitem__ 和切片的行為
>>> class MySeq: ... def __getitem__(self, index): ... return index ... >>> s = MySeq() >>> s[1] #__getitem__直接返回傳給它的值 >>> s[1:4] #[1:4]表示變成了slice(1, 4, None) slice(1, 4, None) >>> s[1:4:2] #[1:4:2]的意思為從第1個索引開始,到第4個索引結(jié)束,步長為2 slice(1, 4, 2) >>> s[1:4:2, 9] (slice(1, 4, 2), 9) #神奇的事情發(fā)生了..wtf...如果[]中有逗號,那么__getitem__接收的是元祖 >>> s[1:4:2, 7:9] #元祖中還可以包含多個切片對象 (slice(1, 4, 2), slice(7, 9, None))
🌰 查看slice類的屬性
>>> slice <class 'slice'> >>> dir(slice) ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'indices', 'start', 'step', 'stop']
調(diào)用 dir(slice) 得到的結(jié)果中有個 indices 屬性,這個方法有很大的作用,但是鮮為人知。help(slice.indices) 給出的信息如下。
indices(...)
S.indices(len) -> (start, stop, stride)
給定長度為 len 的序列,計算 S 表示的擴展切片的起始(start)和結(jié)尾(stop)索引,以及步幅(stride)。超出邊界的索引會被截掉,這與常規(guī)切片的處理方式一樣。
舉個 🌰 假設(shè)有個長度為5的序列,例如'ABCDE':
>>> slice(None, 10, 2).indices(5) #'ABCDE'[:10:2]等同于[:] (0, 5, 2) >>> slice(-3, None, None).indices(5) #'ABCDE'[-3:]等同于[2:5:1] (2, 5, 1)
能處理切片的__getitem__方法
vector_v2.py 的部分代碼:為 vector_v1.py 中的 Vector類添加 __len__ 和__getitem__ 方法
def __len__(self): return len(self._components) def __getitem__(self, index): cls = type(self) #獲取實例的類(Vector) if isinstance(index, slice): #判斷傳遞進來的index是否為slice對象 return cls(self._components[index]) #調(diào)用類的構(gòu)造方法,創(chuàng)建一個新的Vector實例 elif isinstance(index, numbers.Integral): #如果傳遞進來的是個整數(shù) return self._components[index] #返回 _components 中相應(yīng)的元素 else: #拋出異常 msg = '{cls.__name__} indices must be integers' raise TypeError(msg.format(cls=cls))
測試 🌰 改進的 Vector.__getitem__
方法
>>> v7 = Vector(range(7)) >>> v7[-1] #獲取單個整數(shù)索引,返回一個浮點數(shù) 6.0 >>> v7[1:4] #切片索引創(chuàng)建一個新的Vector實例 Vector([1.0, 2.0, 3.0]) >>> v7[-1:] #長度為1的切片也會創(chuàng)建一個新的Vector實例 Vector([6.0]) >>> v7[1,2] #我們在上面的slice已經(jīng)知道,如果slice中包含了,則是一個包含slice的元祖,所以報錯了 Traceback (most recent call last): ... TypeError: Vector indices must be integers
Vector類第3版:動態(tài)存取屬性
Vector2d 變成 Vector 之后,就沒辦法通過名稱訪問向量的分量了(如 v.x 和 v.y)?,F(xiàn)在我們處理的向量可能有大量分量。不過,若能通過單個字母訪問前幾個分量的話會比較方便。比如,用 x、y 和 z 代替 v[0]、v[1] 和 v[2]
在 Vector2d 中,我們使用 @property 裝飾器把 x 和 y 標記為只讀特性。我們可以在 Vector 中編寫四個特性,但這樣太麻煩。特殊方法 __getattr__ 提供了更好的方式。
屬性查找失敗后,解釋器會調(diào)用 __getattr__ 方法。簡單來說,對my_obj.x 表達式,Python 會檢查 my_obj 實例有沒有名為 x 的屬性;如果沒有,到類(my_obj.__class__
)中查找;如果還沒有,順著繼承樹繼續(xù)查找。 如果依舊找不到,調(diào)用 my_obj 所屬類中定義的__getattr__ 方法,傳入 self 和屬性名稱的字符串形式(如 'x')。
vector_v3.py 的部分代碼:在 vector_v2.py 中定義的Vector 類里添加 __getattr__ 方法
def __getattr__(self, name): cls = type(self) #獲取Vector if len(name) == 1: #如果屬性名只有一個字母,可能是shortcut_names中的一個 pos = cls.shorcut_name.find(name) #查找屬性name是否在xyzx中的位置,如果木有就返回-1,有就返回對應(yīng)的索引 if 0 <= pos < len(self._components): #判斷這個查找到的索引是否在區(qū)間內(nèi) return self._components[pos] #返回查找的到的數(shù)組中的值 msg = '{.__name__!r} object has no attribute {!r}' #報錯的信息 raise AttributeError(msg.format(cls, name)) #拋出異常
測試下效果:
>>> v = Vector(range(5)) >>> v Vector([0.0, 1.0, 2.0, 3.0, 4.0]) >>> v.x # 使用v.x獲取第一個元素v[0] 0.0 >>> v.x = 10 # 為v.x賦新的值,按理說應(yīng)該會報異常 >>> v.x # 讀取v.x,返回來的是新的值 >>> v Vector([0.0, 1.0, 2.0, 3.0, 4.0])# 數(shù)組并沒有改變什么~
如果為 .x 或 .y 實例屬性賦值,會拋出 AttributeError。為了避免歧義,在 Vector 類中,如果為名稱是單個小寫字母的屬性賦值,我們也想拋出那個異常。為此,我們要實現(xiàn) __setattr__ 方法。
vector_v3.py 的部分代碼:在 Vector 類中實現(xiàn)__setattr__ 方法
def __setattr__(self, name, value): cls = type(self) if len(name) == 1: #特別處理名稱是單個字符的屬性 if name in self.shorcut_name: #如果name是xyzt中的一個,設(shè)置特殊的錯誤消息 error = 'readonly attribute {attr_name!r}' elif name.islower(): #如果name是小寫字母,為所有小寫字母設(shè)置一個錯誤消息 error = "can't set attributes 'a' to 'z' in {cls_name!r}" else: error = '' if error: #否則,把錯誤消息設(shè)為空字符串 msg = error.format(cls_name=cls.__name__, attr_name=name) raise AttributeError(msg) #如果有錯誤消息,拋出 AttributeError super().__setattr__(name, value) #默認情況:在超類上調(diào)用__setattr__方法,提供標準行為
Vector類第4版:散列和快速等值測試
我們要再次實現(xiàn) __hash__ 方法。加上現(xiàn)有的 __eq__ 方法,這會把Vector 實例變成可散列的對象。
我們要使用^(異或)運算符依次計算各個分量的散列值,像這樣:v[0] ^ v[1] ^ v[2]...。這正是functools.reduce
函數(shù)的作用。
歸約函數(shù)(reduce、sum、any、all)把序列或有限的可迭代對象變成一個聚合結(jié)果
我們已經(jīng)知道 functools.reduce()
可以替換成 sum()
,下面說說它的原理。它的關(guān)鍵思想是,把一系列值歸約成單個值。reduce()
函數(shù)的第一個參數(shù)是接受兩個參數(shù)的函數(shù),第二個參數(shù)是一個可迭代的對象。假如有個接受兩個參數(shù)的 fn 函數(shù)和一個 lst 列表。調(diào)用reduce(fn, lst)
時,fn 會應(yīng)用到第一對元素上,即 fn(lst[0],lst[1])
,生成第一個結(jié)果 r1。然后,fn 會應(yīng)用到 r1 和下一個元素上,即 fn(r1, lst[2])
,生成第二個結(jié)果 r2。接著,調(diào)用 fn(r2,lst[3])
,生成 r3……直到最后一個元素,返回最后得到的結(jié)果 rN。
舉個🌰 使用 reduce 函數(shù)可以計算 5!(5 的階乘):
>>> 2 * 3 * 4 * 5 # 想要的結(jié)果是:5! == 120 120 >>> import functools >>> functools.reduce(lambda a,b: a*b, range(1, 6)) 120
回到散列問題上。下面的 🌰 展示了計算聚合異或的 3 種方式:一種使用 for 循環(huán),兩種使用 reduce 函數(shù)。
>>> n = 0 >>> for i in range(1, 6): # 使用for循環(huán)和累加器變量計算聚合異或 ... n ^= i ... >>> n >>> import functools >>> functools.reduce(lambda a, b: a^b, range(6)) # 使用reduce傳入匿名函數(shù) >>> import operator >>> functools.reduce(operator.xor, range(6)) # 使用 functools.reduce 函數(shù),把 lambda 表達式換成 operator.xor
給代碼中添加__hash__方法
from array import array import reprlib import math import numbers import functools import operator class Vector: typecode = 'd' shorcut_name = 'xyzt' """ 省略的代碼 """ def __eq__(self, other): return tuple(self) == tuple(other) def __hash__(self): hashes = (hash(x) for x in self._components) return functools.reduce(operator.xor, hashes, 0) #把hashes提供給reduce函數(shù),使用xor函數(shù)計算聚合的散列值;第三個參數(shù),0 是初始值
注意:
使用 reduce 函數(shù)時最好提供第三個參數(shù),reduce(function, iterable, initializer)
,這樣能避免這個異常:TypeError: reduce() of empty sequence with no initial value
(這個錯誤消息很棒,說明了問題,還提供了解決方法)。如果序列為空,initializer 是返回的結(jié)果;否則,在歸約中使用它作為第一個參數(shù),因此應(yīng)該使用恒等值。比如,對 +、| 和 ^ 來說, initializer 應(yīng)該是 0;而對 * 和 & 來說,應(yīng)該是 1。
實現(xiàn)的 __hash__ 方法是一種映射歸約計算
映射歸約:把函數(shù)應(yīng)用到各個元素上,生成一個新序列(映射,map),然后計算聚合值(歸約,reduce)
映射過程計算各個分量的散列值,歸約過程則使用 xor 運算符聚合所有散列值。把生成器表達式替換成 map 方法,映射過程更明顯:
def __hash__(self): hashes = map(hash, self._components) return functools.reduce(operator.xor, hashes, 0) #把hashes提供給reduce函數(shù),使用xor函數(shù)計算聚合的散列值;第三個參數(shù),0 是初始值
為了提高比較的效率,Vector.__eq__
方法在 for循環(huán)中使用 zip 函數(shù)
def __eq__(self, other): if len(self) != len(other): #如果對比的兩個長度不一樣,返回False return False for a, b in zip(self, other): #如果兩個對比Vector實例傳遞的值通過惰性對比,有不不一樣的就返回FALSE if a != b: return False return True
zip的效率很好,不過用于計算聚合值的整個 for 循環(huán)可以替換成一行 all 函數(shù)調(diào)用:如果所有分量對的比較結(jié)果都是 True,那么結(jié)果就是 True。只要有一次比較的結(jié)果是 False,all 函數(shù)就返回False。使用 all 函數(shù)實現(xiàn) __eq__ 方法的方式如下:
使用 zip 和 all 函數(shù)實現(xiàn) Vector.__eq__ 方法,效果和上面的代碼一樣~
def __eq__(self, other): return len(self) == len(other) and all(a == b for a, b in zip(self, other))
出色的 zip 函數(shù)
使用 for 循環(huán)迭代元素不用處理索引變量,還能避免很多缺陷,但是需要一些特殊的實用函數(shù)協(xié)助。其中一個是內(nèi)置的 zip 函數(shù)。使用 zip 函數(shù)能輕松地并行迭代兩個或更多可迭代對象,它返回的元組可以拆包成變量,分別對應(yīng)各個并行輸入中的一個元素。
舉個 🌰
>>> zip(range(3), 'abc') <zip object at 0x1024d7b48> >>> list(zip(range(3), 'abc')) #zip返回一個生成器,按需生成元祖 [(0, 'a'), (1, 'b'), (2, 'c')] >>> dict(zip('123', 'abc')) #使用zip快速構(gòu)造一個字典 {'1': 'a', '2': 'b', '3': 'c'} >>> from itertools import zip_longest #使用zip_longest可以給給個fillvalue設(shè)置一個默認值,當元祖迭代盡的時候可以補充默認值 >>> list(zip_longest(range(3), 'ABC', [0.0, 1.1, 2.2, 3.3], fillvalue=-1)) [(0, 'A', 0.0), (1, 'B', 1.1), (2, 'C', 2.2), (-1, -1, 3.3)]
Vector類第5版:格式化
Vector 類的 __format__ 方法與 Vector2d 類的相似,但是不使用極坐標,而使用球面坐標(也叫超球面坐標),因為 Vector 類支持 n 個維度,而超過四維后,球體變成了“超球體”。 因此,我們會把自定義的格式后綴由 'p' 變成 'h'。
下面幾個示例摘自 vector_v5.py 的 doctest,是四維球面坐標格式:
>>> format(Vector([-1, -1, -1, -1]), 'h') '<2.0, 2.0943951023931957, 2.186276035465284, 3.9269908169872414>' >>> format(Vector([2, 2, 2, 2]), '.3eh') '<4.000e+00, 1.047e+00, 9.553e-01, 7.854e-01>' >>> format(Vector([0, 1, 0, 0]), '0.5fh') '<1.00000, 1.57080, 0.00000, 0.00000>'
vector_v5.py:Vector 類最終版的 doctest 和全部代碼;帶標號的那幾行是為了支持 __format__ 方法而添加的代碼
from array import array import reprlib import math import numbers import functools import operator import itertools class Vector: typecode = 'd' def __init__(self, components): self._components = array(self.typecode, components) def __iter__(self): return iter(self._components) def __repr__(self): components = reprlib.repr(self._components) components = components[components.find('['):-1] return 'Vector({})'.format(components) def __str__(self): return str(tuple(self)) def __bytes__(self): return (bytes([ord(self.typecode)]) + bytes(self._components)) def __eq__(self, other): return (len(self) == len(other) and all(a == b for a, b in zip(self, other))) def __hash__(self): hashes = map(hash, self._components) return functools.reduce(operator.xor, hashes, 0) def __abs__(self): return math.sqrt(sum(x * x for x in self)) def __bool__(self): return bool(abs(self)) 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 = '{.__name__} indices must be integers' raise TypeError(msg.format(cls)) shorcut_names = 'xyzt' def __getattr__(self, name): cls = type(self) if len(name) == 1: pos = cls.shorcut_names.find(name) if 0 <= pos < len(self._components): return self._components[pos] msg = '{.__name__!r} object has no attribute {!r}' raise AttributeError(msg.format(cls, name)) 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 - a else: return a def 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_fmt = '<{}>' else: coords = self outer_fmt = '({})' components = (format(c, fmt_spec) for c in coords) return outer_fmt.format(', '.join(components)) @classmethod def frombytes(cls, octets): typecode = octets[0] memv = memoryview(octets[1:]).cast(typecode) return cls(memv)
測試的結(jié)果為:
""" A multidimensional ``Vector`` class, take 5 A ``Vector`` is built from an iterable of numbers:: >>> Vector([3.1, 4.2]) Vector([3.1, 4.2]) >>> Vector((3, 4, 5)) Vector([3.0, 4.0, 5.0]) >>> Vector(range(10)) Vector([0.0, 1.0, 2.0, 3.0, 4.0, ...]) Tests with two dimensions (same results as ``vector2d_v1.py``):: >>> v1 = Vector([3, 4]) >>> x, y = v1 >>> x, y (3.0, 4.0) >>> v1 Vector([3.0, 4.0]) >>> v1_clone = eval(repr(v1)) >>> v1 == v1_clone True >>> print(v1) (3.0, 4.0) >>> octets = bytes(v1) >>> octets b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@' >>> abs(v1) 5.0 >>> bool(v1), bool(Vector([0, 0])) (True, False) Test of ``.frombytes()`` class method: >>> v1_clone = Vector.frombytes(bytes(v1)) >>> v1_clone Vector([3.0, 4.0]) >>> v1 == v1_clone True Tests with three dimensions:: > >> v1 = Vector([3, 4, 5]) >>> x, y, z = v1 >>> x, y, z (3.0, 4.0, 5.0) >>> v1 Vector([3.0, 4.0, 5. 0]) >>> v1_clone = eval(repr(v1)) >>> v1 == v1_clone True >>> print(v1) (3.0, 4.0, 5.0) >> abs(v1) # doctest:+ELLIPSIS 7.071067811... >>> bool(v1), bool(Vector([0, 0, 0])) (True, False) Tests with many dimensions:: >>> v7 = Vector(range(7)) >>> v7 Vector([0.0, 1.0, 2.0, 3.0, 4.0, ...]) >>> abs(v7) # doctest:+ELLIPSIS 9.53939201.. Test of ``.__bytes__`` and ``.frombytes()`` methods:: >>> v1 = Vector([3, 4, 5]) >>> v1_clone = Vector.frombytes(bytes(v1)) >>> v1_clone Vector([3.0, 4.0, 5.0]) >>> v1 == v1_clone True Tests of sequence behavior:: >>> v1 = Vector([3, 4, 5]) >>> len(v1) >>> v1[0], v1[len(v1)-1], v1[-1] (3.0, 5.0, 5.0) Test of slicing:: >>> v7 = Vector(range(7)) >>> v7[-1] 6.0 >>> v7[1:4] Vector([1.0, 2.0, 3.0]) >>> v7[-1:] Vector([6.0]) >>> v7[1,2] Traceback (most recent call last): ... TypeError: Vector indices must be integers Tests of dynamic attribute access:: >>> v7 = Vector(range(10)) >>> v7.x 0.0 >>> v7.y, v7.z, v7.t (1.0, 2.0, 3.0) Dynamic attribute lookup failures:: >>> v7.k Traceback (most recent call last): ... AttributeError: 'Vector' object has no attribute 'k' >>> v3 = Vector(range(3)) >>> v3.t Traceback (most recent call last): ... AttributeError: 'Vector' object has no attribute 't' >>> v3.spam Traceback (most recent call last): ... AttributeError: 'Vector' object has no attribute 'spam' Tests of hashing:: >>> v1 = Vector([3, 4]) >>> v2 = Vector([3.1, 4.2]) >>> v3 = Vector([3, 4, 5]) >>> v6 = Vector(range(6)) >>> hash(v1), hash(v3), hash(v6) (7, 2, 1) Most hash values of non-integers vary from a 32-bit to 64-bit CPython build:: >>> import sys >>> hash(v2) == (384307168202284039 if sys.maxsize > 2**32 else 357915986) True Tests of ``format()`` with Cartesian coordinates in 2D:: >>> v1 = Vector([3, 4]) >>> format(v1) '(3.0, 4.0)' >>> format(v1, '.2f') '(3.00, 4.00)' >>> format(v1, '.3e') '(3.000e+00, 4.000e+00)' Tests of ``format()`` with Cartesian coordinates in 3D and 7D:: >>> v3 = Vector([3, 4, 5]) >>> format(v3) '(3.0, 4.0, 5.0)' >>> format(Vector(range(7))) '(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0)' Tests of ``format()`` with spherical coordinates in 2D, 3D and 4D:: >>> format(Vector([1, 1]), 'h') # doctest:+ELLIPSIS '<1.414213..., 0.785398...>' >>> format(Vector([1, 1]), '.3eh') '<1.414e+00, 7.854e-01>' >>> format(Vector([1, 1]), '0.5fh') '<1.41421, 0.78540>' >>> format(Vector([1, 1, 1]), 'h') # doctest:+ELLIPSIS '<1.73205..., 0.95531..., 0.78539...>' >>> format(Vector([2, 2, 2]), '.3eh') '<3.464e+00, 9.553e-01, 7.854e-01>' >>> format(Vector([0, 0, 0]), '0.5fh') '<0.00000, 0.00000, 0.00000>' >>> format(Vector([-1, -1, -1, -1]), 'h') # doctest:+ELLIPSIS '<2.0, 2.09439..., 2.18627..., 3.92699...>' >>> format(Vector([2, 2, 2, 2]), '.3eh') '<4.000e+00, 1.047e+00, 9.553e-01, 7.854e-01>' >>> format(Vector([0, 1, 0, 0]), '0.5fh') '<1.00000, 1.57080, 0.00000, 0.00000>' """
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
淺析Python的web.py框架中url的設(shè)定方法
web.py是Python的一個輕量級Web開發(fā)框架,這里我們來淺析Python的web.py框架中url的設(shè)定方法,需要的朋友可以參考下2016-07-07Python 2.x如何設(shè)置命令執(zhí)行的超時時間實例
這篇文章主要給大家介紹了關(guān)于Python 2.x如何設(shè)置命令執(zhí)行超時時間的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考借鑒,下面來一起看看吧。2017-10-10Python中常見的數(shù)據(jù)類型小結(jié)
這篇文章主要對Python中常見的數(shù)據(jù)類型進行了總結(jié)歸納,很有參考借鑒價值,需要的朋友可以參考下2015-08-08python數(shù)據(jù)處理之如何選取csv文件中某幾行的數(shù)據(jù)
這篇文章主要給大家介紹了關(guān)于python數(shù)據(jù)處理之如何選取csv文件中某幾行的數(shù)據(jù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用python具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-09-09Python模型聚合查詢\Q查詢\F查詢\分組查詢操作技巧解析
這篇文章主要介紹了模型查詢中的一些操作技巧,主要包括模型聚合查詢,Q查詢,F(xiàn)查詢,分組查詢,有需要的朋友可以借鑒參考下,希望可以有所幫助2021-09-09