C#與python的迭代器比較:
|
迭代器 |
|
|
C# |
Python |
|
一個物件可迭代,需要實作IEnumerable(表示物件可數),IEnumerable就是要實作一個IEnumerator(迭代物件),
這樣的說法曾經一度讓我很迷,如果回傳一個已實作的類似于陣列array、串列list型別的IEnumerator,那實作介面IEnumerable不就很雞肋了? |
學習一個新語言,就會重新認識一些語言特性,這個程序是很有趣的,
Python的迭代器叫Iterator,可迭代就要實作迭代器__iter__(self),和下一項內容__next__(self),這個設計上,顆粒感更強一些, |
|
IEnumerator GetEnumerator(); |
__iter__ __next__ 注: 1.可以將__iter__和__next__呼叫替換為python內置函式iter()和next() 2.在python2中實作的方法名是next,為了兼容性,python3中要同時實作next(self) |
public class TestGenerable : IEnumerable
{
private int n;
private int a;
private int b;
public TestGenerable(int n)
{
this.n = n;
this.a = 1;
this.b = 1;
}
public IEnumerator GetEnumerator()
{
for (int i = 0; i < n; i++)
{
yield return a;
int t = a;
a = b;
b = t + b;
}
}
}
foreach (var value in new TestGenerable(10))
{
WriteLine(value.ToString());
}
|
>>> def fbnq(n): ... a, b = 1,1 ... while n > 0: ... yield a ... a, b = b, a+1 ... n -= 1 ... >>> fbnq(1) <generator object fbnq at 0x0000000002D58E08> >>> list(fbnq(3)) [1, 1, 2]
|
|
狹隘的我竟然從來沒有想一想斐波那契數列更好的實作方式,可以說非常沒有靈魂了, 這個實體非常好的說明了yield return 怎么使用,Generator是個什么東西, |
|
|
|
Tips: 1.Python沒有for(int i; i <n; i++)這樣的回圈,python風格是使用range(n),像這樣: for i in range(5):
pass..
2.generator是可以傳遞的, iterator = (‘hello’ for i in rang(3)) 注意,加了最外邊的圓括號就是生成器物件了,當然,最好避免嵌套兩層以上的生成器運算式, |
補充:
|
Python的迭代器 |
|
熱身: >>> class RepeaterIterator:
... def __init__(self,source):
... self.source = source
... def __next__(self):
... return self.source
...
>>> repeater = tt('Hello')
>>> next(repeater)
'Hello'
使用next(variable)函式, 解釋器會呼叫variable實作的__next__函式, 所以會有執行內容, |
|
然而: >>> for i in repeater: ... print(str(i)) ... Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'RepeaterIterator' object is not iterable for in回圈中,解釋器會找in后面物件實作的__iter__, 沒有實作解釋器會認為其不可迭代,于是報錯; 可以補充一下: class Repeater:
... def __init__(self, value1):
... self.value1 = value1
... def __iter__(self):
... return RepeaterIterator(self)
...
>>> class RepeaterIterator:
... def __init__(self,source):
... self.source = source
... def __next__(self):
... return self.source.value1
...
>>> test = Repeater('hello')
>>> a = 1
>>> for i in test:
... if a < 5:
... print(str(i))
... a += 1
... else:
... break
...
hello
hello
hello
hello
|
|
上例看著還是挺“復雜”的, 其實iter和next可以寫在同一個類里面: class Repeater: ... def __init__(self, value1): ... self.value1 = value1 ... def __iter__(self): ... return self ... def __next__(self): ... return self.value |
|
配合語法糖yield服用: >>> def repeater(value): ... while True: ... yield value |
>>> a = repeater('hi')
>>> a
<generator object repeater at 0x0000000002DC1E60>
只要使用了yield來回傳項的,解釋器認為這是個generator型別; 它和iterator差不多,只不是概念上的區別, generator是“生成器”, 它的下一項更趨向于經過了復雜的計算處理而出來, 而iterator更“輕”一些, |
|
序列過濾(查詢) |
|
|
C# |
Python |
|
LINQ (本質是使用lambda運算式) |
list切片 lambda 生成器運算式 |
|
懶得寫 |
切片: 精髓就一句: >>> lst = [1,2,3,4,5] >>> lst[-2::-1] [4, 3, 2, 1] >>> lst[-2::-2] [4, 2] list是個序列,a:b:c, a表示第幾個開始,加-號表示倒數數起; c表示取數跨度,加了-號表示序列反向,
切片,目前我體驗來說, 僅 lst[-1] 表示“取最后一項”是香的; 有些硬用切片進行資料篩選,比較非人哉: dataSet[nonzero(dataSet[:,feature] > value)[0],:] (康康這啥玩意 %#@$%#@$%4@!!) 要從最里面的方括號開始看,[:,feature]取所有行的下標為feature的列(輸出n行1列的陣列),如果陣列元素大于value,對應位置為true否則為false; Nonzero結果第一行是入參非0元素的行位置(python的0等價false,1等價true) 最后取dataset中feature列上值大于value的所有行,
用物件,用lambda就不香了? |
|
lambda和內置函式filter一起用,就比較LINQ思想了, 下例,以取第4列大于3的所有行: >>> c
array([[1, 2, 3, 5, 0],
[0, 1, 2, 1, 1]])
>>> list(filter(lambda line:line[3]>3, c[:,:]))
[array([1, 2, 3, 5, 0])]
如果需要轉換為numpy.array型別,可以這樣處理: >>> np.array(list(ex)) |
|
|
生成器運算式,格式: genexpr = (expression for item in collection if condition) [注意,最外一定要有圓括號] [expression是item輸出處理] >>> c
array([[1, 2, 3, 5, 0],
[0, 1, 2, 1, 1]])
>>> ex = (line for line in c[:,:] if line[3] > 3)
>>> for i in ex:
... print(i)
...
[1 2 3 5 0]
如果需要轉換為numpy.array型別,可以這樣處理 >>> np.array(list(ex)) 注:generator是單向不可逆的,next()后就釋放當前項了, |
|
|
疑問:C#linq靈魂的鏈式方法(拓展方法),在python是怎么表現的呢 |
|
python的變數適用范圍,python的裝飾器,此類都是大區別與C#的,下集整理,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/96404.html
標籤:Python
上一篇:洗掉單元格,列,行
下一篇:Python判斷身份證是否合法
