浅いコピー、深いコピージェネレータ反復

6215 ワード

Pythonでの付与(コピー)、浅いコピー、深いコピーの違い
1.割り当て:新しいオブジェクトの参照をコピーしただけで、新しいメモリ領域は開かれません.2.浅いコピー:新しいオブジェクトを作成します.その内容は元のオブジェクトの参照の浅いコピーです.3つの形式があります.1.スライス操作2.工場関数3.copyモジュールのcopy関数.
スライス操作:lst 1=lst[:]またはlst 1=[each for each in lst]ファクトリ関数:lst 1=list(lst)copy関数:lst 1=copy.copy(lst)浅いコピーが浅いコピーと呼ばれるのは、それが1層だけコピーされているためであり、lstにはネストされたlistがある[4,5].修正すれば状況は異なる.
3.深いコピー:copyモジュールのdeepcopy関数の形式は1つだけです.浅いコピーに対応して、オブジェクトのすべての要素を深くコピーし、多層ネストされた要素を含む.深くコピーされたオブジェクトは新しいオブジェクトであり、元のオブジェクトとは何の関係もありません.
説明:1.割り当てオブジェクトは元のリストとともに変化します
2.外層に要素を追加する場合、浅いコピーは元のリストの変化に従って変化しません.内層listが要素を追加すると、浅いコピーが変化します.
3.元のリストaがどのように変化しても、深いコピーは変わらない
リスト内の各要素の出現回数を統計する


1.     
    dict     
a = [1, 2, 3, 1, 1, 2]
dict = {}
for key in a:
    dict[key] = dict.get(key, 0) + 1
print dict

2.     
  Python collection  Counter  
from collections import Counter
a = [1, 2, 3, 1, 1, 2]
result = Counter(a)
print result

3.     
Python pandas   value_counts  
mport pandas as pd
a = [1, 2, 3, 1, 1, 2]
result = pd.value_counts(a)
print result

ジェネレータとは?(generator)
Pythonでは完全なlistを作成する必要がなく、大量の空間を節約する.このような循環しながら計算するメカニズムをジェネレータと呼ぶ.generatorジェネレータは特殊なプログラムであり、循環を制御する反復動作として使用することができる.pythonではジェネレータは反復器の一種であり、yield戻り値関数を使用してyieldを呼び出すたびに一時停止する.ではnext()関数とsend()関数を使用してジェネレータを復元できます.
ジェネレータは戻り値が配列の関数に似ています.この関数はパラメータを受け入れることができ、呼び出すことができますが、一般的な関数とは異なり、すべての数値を含む配列を一度に返します.ジェネレータは一度に1つの値しか生成できません.これにより、消費されるメモリの数が大幅に減少し、呼び出し関数が最初のいくつかの戻り値を迅速に処理することができます.したがって、ジェネレータは関数のように見えますが、反復器のように表現されています.
     generator,      ,        ,           []     ()   ,     generator
#     
lis = [x*x for x in range(10)]
print(lis)
#   
generator_ex = (x*x for x in range(10))
print(generator_ex)
   for   next(   )      




         ,          ,                
def fib(max):
    n,a,b =0,0,1
    while n < max:
        a,b =b,a+b
        n = n+1
        print(a)
    return 'done'
a,b = b ,a+b        t =a+b ,a =b ,b =t  ,             t
             N   

    ,    ,fib                    ,          ,
          ,          generator。

             generator   ,      ,print(b)          ,
   ,        ,          ,   yield。  :
def fib(max):
    n,a,b =0,0,1
    while n < max:
        yield b
        a,b =b,a+b
        n = n+1
    return 'done'
a = fib(10)
print(fib(10))

           ,       :


          ,     generator        ,generator   ,   
  next()     ,  yield    ,   next()          yield  
     ,      ,   ,    。

print(a.__next__())
print("         ")
print(next(a))

                   ,          ,              
#         
 [ x ** 3 for x in range(5)]
 [0, 1, 8, 27, 64]

 #       
 (x ** 3 for x in range(5))
  at 0x000000000315F678>

 #       
list(x ** 3 for x in range(5))
[0, 1, 8, 27, 64]
              



反復器(Iterator)
反復はループ
      ,       for            :
         , list,tuple,dict,set,str 
   generator,       yield generator function
         for              :Iterable
    isinstance()          Iterable  

from collections import Iterable
>>>isinstance([], Iterable)
True
>>>isinstance({}, Iterable)
True
>>>isinstance(100, Iterable)
False

   next()                     :Iterator。

           for  ,    next()             ,      
StopIteration               。

     Iterator  , list、dict、str   Iterable(     ),   Iterator(   )

 list、dict、str Iterable  Iterator    iter()  :
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True





なぜlist、dict、strなどのデータ型がIteratorではないのかと聞かれるかもしれません.
これは、PythonのIteratorオブジェクトが を表しているためであり、Iteratorオブジェクトはnext()関数によって呼び出され、データがないときにStopIterationエラーが投げ出されるまで次のデータを繰り返し返すことができる.このデータストリームは秩序あるシーケンスと見なすことができるが,シーケンスの長さを事前に知ることはできず,next()関数を介して次のデータをオンデマンドで計算するしかないため,Iteratorの計算は不活性であり,次のデータを返す必要がある場合にのみ計算される.Iterator 、例えば全体自然数.list を使います
from collections import Iterator  #   
from collections import Iterable  #     
 
print(isinstance(s,Iterator))     #        
print(isinstance(s,Iterable))       #          

#            
print(isinstance(iter(s),Iterator))

まとめ:
1.forループに作用するオブジェクトはすべてIterable(反復可能オブジェクト)タイプである.2.next()関数に作用するオブジェクトは、不活性計算のシーケンスを表すIterator(反復器)タイプである.3.リスト、dict、strなどの集合データ型はIterableですが、Iteratorではありませんが、iter()関数でIteratorオブジェクトを取得できます.
Python3 for             next()     ,  :

for x in [1, 2, 3, 4, 5]:
    pass

        

#     Iterator  :
it = iter([1, 2, 3, 4, 5])
#   :
while True:
    try:
        #       :
        x = next(it)
    except StopIteration:
        #   StopIteration     
        break




yieldのまとめ(1):通常のfor..in...ループでは、inの後ろに配列があり、この配列は反復可能なオブジェクトであり、チェーンテーブル、文字列、ファイルも似ています.彼はa=[1,2,3]であってもよいし、a=[x*x for x in range(3)]であってもよい.
その欠点も明らかで、すべてのデータがメモリの中にあり、大量のデータがあれば、メモリを非常に消費します.
(2)ジェネレータは反復可能であるが,一度だけ読み取ることができる.A=(x*x for x in range(3))など、使うときに生成されるからです.!!!!ここでは角カッコではなく括弧に注意してください.
(3)ジェネレータ(generator)が反復できる鍵は、異常をキャプチャするまでnext()メソッドを繰り返し呼び出すことであるnext()メソッドを持つことである.
(4)yield付き関数は一般的な関数ではなく,反復に使用できるジェネレータgeneratorである.
(5)yieldはreturnのようなキーワードであり,yieldに遭遇するとyieldの後ろまたは右の値を反復する.そして次の反復では、前回の反復で出会ったyieldの後ろのコードから実行します.
(6)yieldはreturnが返す値であり,この返す位置を記憶する.次の反復はこの位置から始まります.
(7)yieldを有する関数は、forループのみに用いられるだけでなく、ある関数のパラメータにも用いられ、この関数のパラメータが反復パラメータを許容する限り、用いることができる.
(8)send()とnext()の違いはsendがyield式にパラメータを渡すことであり,このときに渡されるパラメータはyield式の値となり,yieldのパラメータは呼び出し者に返される値,すなわちsendは前のyield式の値を強引に修正することができる.
(9)send()とnext()には戻り値があり、彼らの戻り値が現在の反復で遭遇したyieldの場合、yieldの後式の値は、実際には現在の反復yieldの後のパラメータである.
(10)最初に呼び出すときはnext()またはsend()を先にしなければならない.そうしないとエラーが報告されるが,send後にNoneとなるのはこのときyieldが1つもないため,next()はsend(None)に等しいと考えられる.
               ,                  

            

   (   ):      
myiterator = [x*x for x in range(3)]
>>> for x in myiterator:
...     print(x)

   (   ):      

>>> mygenerator = (x*x for x in range(3))
>>> for x in  mygenerator:
...     print(x)