ホームページ > バックエンド開発 > Python チュートリアル > Pythonのジェネレータ、イテレータ、動的に追加される属性、メソッドの詳細な説明

Pythonのジェネレータ、イテレータ、動的に追加される属性、メソッドの詳細な説明

WBOY
リリース: 2023-04-21 13:22:08
転載
1377 人が閲覧しました

1. ジェネレーター

1. ジェネレーターの定義

Python では、ループしながら計算するメカニズムをジェネレーターと呼びます: ジェネレーター

2. 生成デバイスの存在

リスト内のデータはすべてメモリ上にあるため、データ量が多いとメモリを大量に消費します。

例: 最初のいくつかの要素にのみアクセスする必要がある場合、後続のスペースはすべて無駄になります

リスト要素が特定のアルゴリズムに従って計算される場合、継続的に計算できます。ループ中に後続の要素が追加されるため、完全なリストを作成する必要がなく、スペースを大幅に節約できます。

3. ジェネレーターの作成方法 1 (ジェネレーター式)

ジェネレーター式は非常に簡単で、リスト内包表記の [] を () に変更するだけでジェネレーターを作成できます。

L = [x * x for x in range(10)]  #推导式
print(L)
g = (x * x for x in range(10)) #加成括号就是生成器
print(g)
#<generator object <genexpr> at 0x1022ef630>
&#39;&#39;&#39;L是一个list,而g则是一个 generator&#39;&#39;&#39;
ログイン後にコピー

4. ジェネレーターの作成方法 2 (ジェネレーター関数)

1. ジェネレーター関数
  • If a 関数に yield キーワードが含まれている場合、これはfunction は通常の関数ではなくなりました。関数を呼び出すとジェネレーター オブジェクトが作成されます。

  • ジェネレーター関数: キーを使用します。yield という単語はすぐに結果を返し、ブロックして再度開始します

2. ジェネレーター関数の仕組み
  • ジェネレーター関数は反復を返します for ループはこの反復子で __next__() 関数を継続的に呼び出し、続行します次の yield ステートメントまで実行し、yield ステートメントがなくなるまで各戻り値を一度に 1 つずつ取得し、最後に StopIteration 例外をトリガーします

  • yield は return と同等で、戻り値を返します。次の反復中に、コードは、next() と同様に、yield

  • send() の次のステートメント (次の行ではない) から実行を開始します。 send() はジェネレーターをさらに 1 ステップ先に進めることができます (次回 yield に遭遇したら停止します)。ただし、send() は、yield 式の全体的な結果として使用される値を渡すことができます

テスト ジェネレーターの動作 (yield)

&#39;&#39;&#39;
如果一个函数中包含 yield 关键字,那么这个函数就不再是一个普通函数,
调用函数就是创建了一个生成器(generator)对象
生成器函数:其实就是利用关键字 yield 一次性返回一个结果,阻塞,重新开始
原理
1. 函数有了yield之后,调用它,就会生成一个生成器
2. 下次从下一个语句执行,切记不是下一行(tmp = yield i)
3. return在生成器中代表生成器种植,直接报错:StopIeratation
4. next方法作用:唤醒并继续执行
&#39;&#39;&#39;
def test():
    print("start")
    i = 0
    while i<3:
        &#39;&#39;&#39;yield i #第一次执行,此处挂起;同时将i的值返回到i
                   #第二次执行,从挂起的地方往下执行&#39;&#39;&#39;
        temp = yield i #下次迭代时,代码从`yield`的下一条语句(不是下一行)开始执行
        print(f"i:{i}")
        i += 1
    print("end")
    return "done"
if __name__ == &#39;__main__&#39;:
    a = test()
    print(type(a))
    print(a.__next__())
    print(a.__next__())
    print(a.__next__())
    print(a.__next__())# 抛出异常:StopIteration
&#39;&#39;&#39;
<class &#39;generator&#39;>
start
0
temp:None
1
temp:None
2
temp:None
end
Traceback (most recent call last):
 in <module>
    print(a.__next__())# 抛出异常:StopIteration
StopIteration: done
&#39;&#39;&#39;
ログイン後にコピー

テスト ジェネレーターの動作 (送信)

&#39;&#39;&#39;
send的作用是唤醒并继续执行,发送一个信息到生成器内部
&#39;&#39;&#39;
def foo():
    print("start")
    i = 0
    while i < 2:
        temp = yield i
        print(f"temp:{temp}")
        i += 1
    print("end")
 
g = foo()
print(next(g))  #等同g.__next__(),next是内置函数
print("*"*20)
print(g.send(100))
print(next(g))
# for a in g:#g所返回的值是yield处的i
#     print(a)
&#39;&#39;&#39;
start
0
********************
temp:100
1
temp:None
end
Traceback (most recent call last):
    print(next(g))
StopIteration
&#39;&#39;&#39;
ログイン後にコピー

5. まとめ

1. ジェネレーターとは何ですか
ジェネレーターは、値を生成するための一連のアルゴリズムを保存するだけであり、アルゴリズムの実行を今すぐ開始するわけではありませんが、ジェネレーターを呼び出すと、新しい値の計算が開始され、

2. ジェネレーターの機能
  • ジェネレーター関数は、一連の結果を生成します。 yield キーワードを通じて値を返した後は、終了した場所から実行を継続できるため、いつでも一連の値を生成できます。

  • ジェネレーターと反復には密接な関係があり、反復には __next__() メンバー メソッドがあり、反復の次の項目を返すか、例外を発生させて反復を終了します。

  • #ジェネレーターは、ループの反復動作を制御するために使用できる特別なプログラムです。 ##1. 概念
  • 反復は Python の最も強力な関数の 1 つであり、コレクション要素にアクセスする方法です

反復子トラバースした位置を記憶できるオブジェクト

  • #イテレータ オブジェクトは、コレクションの最初の要素からすべての要素にアクセスされるまでアクセスを開始します

  • #イテレータは前方にのみ移動でき、後方には移動できません。
  • #イテレータには 2 つの基本メソッドがあります:
  • iter()
  • netx( )

  • 2. 反復可能オブジェクトと反復子の違い
  • 反復メソッドを実装するオブジェクトは、「反復可能」オブジェクト Ieratable と呼ばれます"

    next メソッドを実装し反復可能なオブジェクトは「イテレータ」 Iterator と呼ばれます。つまり、iter メソッドと next メソッドを実装するオブジェクトはイテレータです

# ######!

Generators はすべて
    Iterator
  • オブジェクトですが、

    list

  • dict
  • str

    はすべて
  • Iterable
(Iterable object) ではありますが、Iterator (Iterator) ではありません。

&#39;&#39;&#39;
生成器一定是迭代器
可迭代对象不一定是迭代器,使用iter([])封装后可转为迭代器
&#39;&#39;&#39;
from collections.abc import Iterator
from collections.abc import Iterable
a = isinstance([], Iterator) #list、dict、str虽然是Iterable(可迭代对象),却不是Iterator(迭代器)
print(a)
a = isinstance([], Iterable) #可迭代对象
print(a)
"""
执行结果:
False
True
"""
ログイン後にコピー
&#39;&#39;&#39;list、dict、str 等 Iterable 变成 Iterator,可以使用 iter() 函数:&#39;&#39;&#39;
b = isinstance(iter([]), Iterator)
print(b)
b = isinstance(iter(&#39;花非人陌&#39;), Iterator)
print(b)
 
"""
执行结果:
True
True
"""
ログイン後にコピー
Python の Iterator オブジェクトは データ フローを表します 。このデータは順序付けされたシーケンスとみなすことができますが、シーケンスの長さを事前に知ることはできません。次のデータは next() 関数を通じてオンデマンドで計算することしかできないため、Iterator

の計算は遅延され、次のデータを返す必要があるときにのみ計算されます。

したがって、ジェネレーターはイテレーターである必要があります。 Pythonのジェネレータ、イテレータ、動的に追加される属性、メソッドの詳細な説明

3. for ループの本質

#Python3 的 for 循环本质就是通过不断调用 next() 函数实现的。
 
for x in [1,2,3,4,5]:
    pass
 
&#39;&#39;&#39;本质是:&#39;&#39;&#39;
#首先获得Iterator对象:
it = iter([1,2,3,4,5])
#循环
while True:
    try:
        # 获得下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration 就退出循环
        break
ログイン後にコピー
4. イテレータの作成クラスをイテレータとして使用するには、クラスに 2 つのメソッドを実装する必要があります __iter__() および __next__()

##__iter__()
メソッドは特別な反復子オブジェクトを返します。この反復子オブジェクトは、

__next__()

メソッドを使用し、StopIteration 例外を通じて反復の完了を識別します

  • __next__() 方法会返回下一个迭代器对象

  • #创建一个依次返回10,20,30,...这样数字的迭代器
    class MyNumbers:
        def __iter__(self):
            self.num = 10
            return self
     
        def __next__(self):
            if self.num < 40:
                x = self.num
                self.num += 10
                return x
            else:
                raise StopIteration
     
    myclass = MyNumbers()
    myiter = iter(myclass)
    print(next(myiter))
    print(next(myiter))
    print(next(myiter))
    print(next(myiter))
    """
    执行结果:
    10
    20
    30
    Traceback (most recent call last):
        raise StopIteration
    StopIteration
    """
    """
    程序解析:
    在这段代码中,MyNumbers 类定义了一个迭代器。该迭代器的作用是生成一系列数字,从 10 开始,每次增加 10,直到 40,然后停止。
    在程序中,通过 iter(myclass) 方法获取 MyNumbers 类的迭代器对象 myiter,然后调用 next(myiter) 方法获取下一个数字。
    在第一次调用 next(myiter) 方法时,迭代器会执行 __next__() 方法,返回 self.num 的值 10,然后将 self.num 的值增加 10,变为 20。
    在第二次、第三次调用 next(myiter) 方法时,迭代器会再次执行 __next__() 方法,返回 20 和 30,然后将 self.num 的值分别增加 10,变为 30 和 40。
    在第四次调用 next(myiter) 方法时,迭代器再次执行 __next__() 方法,发现 self.num 的值已经大于等于 40,于是抛出 StopIteration 异常,表示迭代已经结束。
    """
    ログイン後にコピー

    三、动态添加属性和方法

    1、动态编程语言定义

    指在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,

    已有的函数可以被删除或是其他结构上的变化

    2、运行过程中给对象添加属性和方法

    #coding=utf-8
    import types
    class Person():
        def __init__(self, name, age):
            self.name = name
            self.age = age
     
    p1 = Person("zhangsan", 20)
    p2 = Person("lisi", 18)
    #动态给对象添加属性和方法
    p1.score = 100
    print(p1.score) #加给p1的只能p1用,对象的也是一样
     
    #动态给对象添加方法
    def run(self):
        print(f"{self.name}, running...")
    p1.run = types.MethodType(run, p1)
    #而types.MethodType(run,p1)则是告诉解释器,self指的就是p1
    p1.run()
    """
    执行结果:
    100
    zhangsan, running...
    """
    ログイン後にコピー

    3、给类动态添加静态方法以及类方法

    #encoding=utf-8
    class Person():
        __slots__ = {"name", "age"}
        def __init__(self, name, age):
            self.name = name
            self.age = age
     
    @staticmethod
    def staticfunc():
        print("--- static method ---")
     
    Person.staticfunc = staticfunc
    Person.staticfunc()
    Person.score = 1000 #动态给对象静态方法
    print(Person.score)
     
    @classmethod
    def clsfunc(cls):
        print(&#39;--- cls method ---&#39;)
    Person.clsfunc = clsfunc    #动态增加类方法
    Person.clsfunc()
    ログイン後にコピー

    四、限制动态添加

    1、slots

    1. __slots__的作用
    • __slots__ 对动态添加成员变量、成员方法有限制。对动态添加类属性、类方法没有限制

    • __slots__ 只对本类有限制,不限制子类

    2. 对动态添加成员变量、成员方法有限制
    &#39;&#39;&#39;
    MyClass 类使用 __slots__ 属性限制了实例对象的属性,只允许动态添加 x 属性。
    因此,obj.x = 1 可以成功,但是 obj.y = 2 会抛出 AttributeError 异常
    &#39;&#39;&#39;
    class MyClass:
        __slots__ = [&#39;x&#39;]
     
    obj = MyClass()
    obj.x = 1  # 可以动态添加 x 属性
    obj.y = 2  # 报错,__slots__ 限制了不能动态添加 y 属性
    """
    执行结果:
    AttributeError: &#39;MyClass&#39; object has no attribute &#39;y&#39;
    """
    ログイン後にコピー
    3. 对动态添加类属性、类方法没有限制
    class MyClass:
        __slots__ = [&#39;x&#39;]
        classattr = 1
     
        @classmethod
        def myclassmethod(cls):
            print("class method")
     
     
    MyClass.newclassattr = 2  # 可以动态添加类属性
    print(MyClass.newclassattr)
    MyClass.mynewclassmethod = lambda cls: print("new class method")  # 可以动态添加类方法
    MyClass.mynewclassmethod(MyClass)   #传递类本身作为参数
    obj = MyClass()
    obj.x  = 3    # 可以动态添加实例属性
    print(obj.x)  # 可以动态添加 x 属性
    """
    执行结果:
    2
    new class method
    3
    """
    ログイン後にコピー

    以上がPythonのジェネレータ、イテレータ、動的に追加される属性、メソッドの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    関連ラベル:
    ソース:yisu.com
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    最新の問題
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート