日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

rust python对比_Python Rust 迭代器对比

發(fā)布時(shí)間:2023/12/1 python 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 rust python对比_Python Rust 迭代器对比 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

迭代是數(shù)據(jù)處理的基石,而 Python 中所有集合都可以迭代,這是 Python 讓使用者感到非常方便的特征之一。

下面是一些在 Python 中經(jīng)常使用的迭代模式

# 列表

for i in [1, 2, 3, 4]:

print(i)

# 字典

di = {'a': 1, 'b': 2, 'c': 3}

# 迭代鍵

for k in di.keys():

print(k)

# 迭代鍵值

for k, v in di.items():

print('{}: {}'.format(k, v))

除了基本數(shù)據(jù)類型,Python 也支持為自定義的數(shù)據(jù)類型實(shí)現(xiàn)迭代器協(xié)議。Python 解釋器在需要迭代對象 x 時(shí)會自動調(diào)用 iter(x)。

內(nèi)置的 iter 函數(shù)有如下作用。

檢查對象是否實(shí)現(xiàn)了 __iter__ 方法,如果實(shí)現(xiàn)了就調(diào)用它,__iter__ 方法返回一個(gè)迭代器

如果沒有實(shí)現(xiàn) __iter__ 方法,但是實(shí)現(xiàn)了 __getitem__ 方法,Python 會創(chuàng)建一個(gè)迭代器,嘗試按順序(從索引0)獲取元素。

如果上述兩個(gè)嘗試失敗,Python 會拋出 TypeError 異常,提示該元素不可迭代。

所以如果我們要讓某個(gè)對象是可迭代對象,只需要實(shí)現(xiàn) __iter__,這個(gè)方法要求返回一個(gè)迭代器,那什么是迭代器呢? Python 中標(biāo)準(zhǔn)的迭代器接口有兩個(gè)方法。

__next__

返回下一個(gè)可用的元素,如果元素,拋出 StopIteration 異常。

__iter__

返回迭代器自身,即 self,以便在應(yīng)該使用可迭代對象的地方使用迭代器,如 for 循環(huán)中。

這里需要說明的一點(diǎn)是,可迭代對象與迭代器是不同的,《流暢的 Python》這樣定義可迭代對象

> 使用 iter 內(nèi)置函數(shù)可以獲取迭代器的對象。如果對象實(shí)現(xiàn)了能返回迭代器的 iter 方法,那么對象就是可迭代的。序列都可以迭代;實(shí)現(xiàn)了 getitem 方法,而且其參 數(shù)是從零開始的索引,這種對象也可以迭代

>

而迭代器則定義為

> 迭代器是這樣的對象:實(shí)現(xiàn)了無參數(shù)的 next 方法,返回序列中的下一個(gè)元素;如 果沒有元素了,那么拋出 StopIteration 異常。Python 中的迭代器還實(shí)現(xiàn)了 iter 方 法,因此迭代器也可以迭代。

也就是說每次對可迭代對象調(diào)用 iter(x) 都將返回一個(gè)新的迭代器。

那如果為一個(gè)可迭代對象實(shí)現(xiàn) __next__ 方法,即把這個(gè)可迭代對象變成自身的可迭代對象會怎樣呢?沒人阻止你這樣做,但當(dāng)你真正為這個(gè)對象實(shí)現(xiàn)這兩個(gè)方法時(shí),你會發(fā)現(xiàn)麻煩不斷。舉個(gè)例子

class MyData:

def __init__(self, values):

# 假設(shè) value 為列表

self.values = values

def __iter__(self):

return self

def __next__(self):

# ???

raise NotImplementedError()

按照協(xié)議 __next__ 應(yīng)該返回下一個(gè)元素或者拋出 StopIteration,顯然我們需要一個(gè)屬性存儲當(dāng)前迭代位置,所以應(yīng)該似乎應(yīng)該這樣寫

class MyData:

def __init__(self, values):

self.values = values

# 記錄當(dāng)前迭代位置

self.current = 0

def __iter__(self):

# 每次調(diào)用重頭開始迭代

self.current = 0

return self

def __next__(self):

if self.current < len(self.values):

value = self.values[self.current]

self.current += 1

return value

else:

raise StopIteration

但考慮這樣一種情況,我們調(diào)用2次 iter,交替迭代獲得的2個(gè)迭代器,預(yù)期行為應(yīng)該是2個(gè)迭代器不會干涉,但如果按上述代碼實(shí)現(xiàn) MyData 對象行為并不符合預(yù)期。

data = MyData([1, 2, 3, 4, 5])

data_iter1 = iter(data)

print(next(data_iter1)) # 結(jié)果為1

print(next(data_iter1)) # 結(jié)果為2

data_iter2 = iter(data)

print(next(data_iter2)) # 結(jié)果為1

print(next(data_iter1)) # 預(yù)期為3,但得到2

如果把 current 屬性變?yōu)榱斜?#xff0c;每次調(diào)用 iter 增加一個(gè)元素表示新的迭代器當(dāng)前位置呢?但又會導(dǎo)致 __next__ 變得非常復(fù)雜,因?yàn)樗仨氄业讲煌鲗?yīng)當(dāng)前位置,這樣才能保證正確的迭代行為。為什么我們的迭代實(shí)現(xiàn)如此復(fù)雜呢?根本原因在于 __iter__ 總是返回自身,換言之,調(diào)用 iter 的迭代器都是一樣,這其實(shí)破壞了 每次調(diào)用 iter 返回新的迭代器 這一設(shè)計(jì)。

解決難題辦法很簡單,遵循設(shè)計(jì),把可迭代對象和迭代器拆開。

class MyData:

def __init__(self, values):

self.values = values

def __iter__(self):

return DataIterator(list(self.values))

class DataIterator:

def __init__(self, values):

self.values = values

self.current = 0

def __iter__(self):

return self

def __next__(self):

if self.current < len(self.values):

value = self.values[self.current]

self.current += 1

return value

else:

raise StopIteration

現(xiàn)在 __iter__ 將會返回新的迭代器,每個(gè)迭代器都保存著自身狀態(tài),這讓我們不必費(fèi)心費(fèi)力第維護(hù)迭代器狀態(tài)。

所以,把可迭代對象變成其自身的迭代器是條歧路,反設(shè)計(jì)的。

在 Rust 中,迭代也遵循著相似的設(shè)計(jì),Rust 中實(shí)現(xiàn)了 Iterator 特性的結(jié)構(gòu)體就被認(rèn)為是可迭代的。

我們可以像 Python 那樣使用 for 循環(huán)迭代

let v1 = vec![1, 2, 3, 4, 5];

for item in v1 {

println!("{}", item);

}

std::iter::Iterator 只要求實(shí)現(xiàn) next 方法即可,下面是一個(gè)官方文檔中的例子

// 首先定義一個(gè)結(jié)構(gòu)體,作為“迭代器”

struct Counter {

count: usize,

}

// 實(shí)現(xiàn)靜態(tài)方法 new,相當(dāng)于構(gòu)造函數(shù)

// 這個(gè)方法不是必須的,但可以讓我更加方便

// 地使用 Counter

impl Counter {

fn new() -> Counter {

Counter { count: 0 }

}

}

// 實(shí)現(xiàn) Iterator 特性

impl Iterator for Counter {

// 確定迭代器的返回值類型

type Item = usize;

// 只有 next() 是必須實(shí)現(xiàn)的方法

// Option 也可以寫成 Option<:item>

fn next(&mut self) -> Option {

// 增加計(jì)數(shù)

self.count += 1;

// 到 5 就返回 :)

if self.count < 6 {

Some(self.count)

} else {

None

}

}

}

let mut counter = Counter::new();

let x = counter.next().unwrap();

println!("{}", x);

let x = counter.next().unwrap();

println!("{}", x);

let x = counter.next().unwrap();

println!("{}", x);

let x = counter.next().unwrap();

println!("{}", x);

let x = counter.next().unwrap();

println!("{}", x);

與 for 循環(huán)使用時(shí),Python 使用 StopIteration 告訴編譯是時(shí)候定制循環(huán)了,在 Rust 則是 None,所以 next 方法返回值為 Option<:item>。其實(shí)使用 for 循環(huán)是一種語法糖

let values = vec![1, 2, 3, 4, 5];

for x in values {

println!("{}", x);

}

去掉語法糖后相當(dāng)于

let values = vec![1, 2, 3, 4, 5];

{

let result = match IntoIterator::into_iter(values) {

mut iter => loop {

let next;

match iter.next() {

Some(val) => next = val,

None => break,

};

let x = next;

let () = { println!("{}", x); };

},

};

result

}

編譯器會對 values 調(diào)用 into_iter 方法,獲取迭代器,接著匹配迭代器,一次又一次地調(diào)用迭代器的 next 方法,直到返回 None,這時(shí)候終止循環(huán),迭代結(jié)束。

這里又涉及到另一個(gè)特性 std::iter::IntoIterator,這個(gè)特性可以把某些東西變成一個(gè)迭代器。

IntoInterator 聲明如下:

pub trait IntoIterator

where

<:intoiter as iterator>::Item == Self::Item,

{

type Item;

type IntoIter: Iterator;

fn into_iter(self) -> Self::IntoIter;

}

類比于 Python 中的概念,可以做出以下結(jié)論:

實(shí)現(xiàn)了 IntoIterator 特性的結(jié)構(gòu)體是一個(gè)“可迭代對象”

實(shí)現(xiàn)了 Iterator 特性的結(jié)構(gòu)體一個(gè)“迭代器”

for 循環(huán)會嘗試調(diào)用結(jié)構(gòu)的 into_iter 獲得一個(gè)新的“迭代器”,當(dāng)?shù)鞣祷?None 時(shí)提示迭代結(jié)束

基于以上結(jié)論,我們可以實(shí)現(xiàn) Python 例子中類似的代碼

#[derive(Clone)]

struct MyData{

values: Vec,

}

struct DataIterator {

current: usize,

data: Vec,

}

impl DataIterator {

fn new(values: Vec) -> DataIterator {

DataIterator {

current: 0,

data: values

}

}

}

impl Iterator for DataIterator {

type Item = i32;

fn next(&mut self) -> Option {

if self.current < self.data.len() {

let ret = Some(self.data[self.current]);

self.current += 1;

ret

} else {

None

}

}

}

impl IntoIterator for MyData {

type Item = i32;

type IntoIter = DataIterator;

fn into_iter(self) -> DataIterator {

DataIterator::new(self.values)

}

}

fn main() {

let data = MyData { values: vec![1, 2, 3, 4] };

for item in data {

println!("{}", item);

}

}

總結(jié)

Rust 不愧是一門多范式的現(xiàn)代編程語言,如果你之前對某個(gè)語言有相當(dāng)深入的了解,在學(xué)習(xí) Rust 是總會有“喔,這不是xxx嗎”的感覺。雖然之前閱讀過 《流暢的Python》,但在可迭代對象與迭代器這一章并沒有太多影響,因?yàn)樵谑褂?Python 時(shí)真正要我實(shí)現(xiàn)迭代接口的場景非常少;直到最近學(xué)習(xí) Rust,在嘗試使用 Rust 的 Iterator 特性為我的結(jié)構(gòu)實(shí)現(xiàn)與 for 循環(huán)交互時(shí)被 Iterator 和 IntoInterator 特性高的有些蒙圈。最后是靠著 Python 和 Rust 相互對比,弄清迭代器與可迭代對象的區(qū)別后才感覺自己真正弄懂了迭代這一重要特性。

延申閱讀

《流暢的Python》 - 第14章,可迭代的對象、迭代器和生成器

《Rust 編程之道》 6.3 迭代器

總結(jié)

以上是生活随笔為你收集整理的rust python对比_Python Rust 迭代器对比的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。