python ——__ slots __ / @ property / __ str __ / __ repr __()__ iter__和__next__ __getitem__ __getattr__ __call_

目次

__slots__

@propertyを使用する

__str__および__repr __()

__iter__および__next__

__getitem__

__getattr__

 __コール__


__slots__

不是在class中创建方法而是创建了一个链接把外部的set_age 方法用链接指到Student内

__slots__:実際には、クラス内の名前をロックし、オブジェクトをインスタンス化し、割り当てと呼び出しのみが可能であり、属性の削除と新しい属性の追加はできません。

__slots__内容:これはクラス変数であり、変数値はリスト、プリミティブ祖先、反復可能オブジェクト、または文字列(すべてのインスタンスが1つのデータ属性のみを持つことを意味します)にすることができます。

パブリックセクション:

from types import MethodType 
#创建一个方法
def set_age(self, arg):
    self.age = arg    
#创建一个类    
class Student(object):
    pass

属性インスタンスにバインドます

>>> s = Student()
>>> s.name = 'Michael' # 动态给实例绑定一个属性
>>> print(s.name)
Michael

メソッドインスタンスにバインドます

>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25

あるインスタンスにバインドされたメソッドは、別のインスタンスでは機能しません

メソッドをすべてのインスタンスにバインドするために、メソッドをクラスにバインドできます。

Student.set_score = set_score
Student.set_age = MethodType(set_age,Student)

インスタンスの属性を制限する場合は、クラスを定義するときに、クラスインスタンスが追加できる属性制限する特別な__slots__変数定義します

class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'

__slots__定義された属性は、現在のクラスインスタンスでのみ機能し、継承されたサブクラスには影響しません。

__slots__このように、サブクラスも定義されていない限り、サブクラスインスタンスが定義できる属性は、それ自体__slots__と親クラス__slots__です。

 

@propertyを使用する

スコアの範囲を制限するために、1つのset_score()方法使用してスコアを設定し、次に1つの方法使用してスコアget_score()を取得できます。このように、この方法ではset_score()、次のパラメーターを確認できます。

class Student(object):
    def get_score(self):
        return self._score
    def set_score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

上記の呼び出しメソッドは少し複雑で、属性を直接使用するほど簡単ではありません。クラスメソッドの場合、デコレータも機能します。Pythonの組み込み@propertyデコレータは、メソッドを属性呼び出しに変換する役割を果たします。

class Student(object):
    @property
    def score(self):
        return self._score
    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value
#使用
>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
  ...
ValueError: score must between 0 ~ 100!

静的プロパティプロパティの本質は、get、set、およびdeleteの3つのメソッドを実装することです。

シンタックスシュガーを使用して、プロパティの同様のプロパティを設定および削除できます。これは、一般的なプロパティの設定および削除と同じです。

getterメソッドをプロパティに変換するには、@propertyそれを追加するだけです。この時点で、setterメソッドをプロパティ割り当てに変換する別のデコレータが@property独自作成されるため、制御可能なプロパティ操作が可能になります。@score.setter

あなたもできる読み取り専用のプロパティを定義して、唯一のゲッターメソッドを定義しますが、setterメソッドを定義しない場合、それは読み取り専用のプロパティです。

class Student(object):
    @property
    def birth(self):
        return self._birth
    @birth.setter
    def birth(self, value):
        self._birth = value
    @property
    def age(self):
        return 2014 - self._birth

上記birthは読み取りと書き込みが可能な属性ですがage読み取り専用の属性です

 

__str__および__repr __()

__str__変更オブジェクトを制御する文字列表示ですか

そのprint(obj)/'%s'%obj/str(obj)とき、了obj.__str__メソッドは実際には内部的に呼び出されます。strメソッドが持っている場合は、文字列を返す必要があります。__str__メソッドがない場合は、このクラスのメソッドが最初__repr__検索され、親クラス(オブジェクト)は検索されません。再度検索しました__str__

Studentクラスを定義し、インスタンスを出力します。

>>> class Student(object):
...     def __init__(self, name):
...         self.name = name
...
>>> print(Student('Michael'))
<__main__.Student object at 0x109afb190>

それは束<__main__.Student object at 0x109afb190>印刷し、それはよく見えません。

どうすればうまく印刷できますか?__str__()メソッドを定義して、素敵な文字列を返すだけです。

>>> class Student(object):
...     def __init__(self, name):
...         self.name = name
...     def __str__(self):
...         return 'Student object (name: %s)' % self.name
...
>>> print(Student('Michael'))
Student object (name: Michael)

 ただし、変数を直接入力し、printを使用せずに出力すると、見栄えが悪くなります。変数呼び出しは直接表示されるため__repr__()、2つの違いは__str__()、ユーザーが表示する文字列と、ユーザーが表示する文字列を返すことです。__repr__()プログラム開発者、つまり、__repr__()デバッグサービスです。

コードに追加できます

 __repr__ = __str__

__repr__また、repr(object)を使用してオブジェクトの名前を表示する方法でもあります。または、 "%r"%objectが__repr__メソッドを呼び出します。

reprはstrのスペアタイヤですが、strをreprのスペアタイヤにすることはできません。

class Foo:
​
    def __str__(self):
        return "控制打印对象时的显示形式"
​
    def __repr__(self):
        print("在执行repr")
        return "repr Foo"
    pass
f = Foo()
print("%r"%f)
print(f)

#这里print("%r"%f) 调用重新定义的__repr__方法,print(f)调用__str__方法
class Foo:
​
    def __str__(self):
        return "控制打印对象时的显示形式"
​
    # def __repr__(self):
    #     print("在执行repr")
    #     return "repr Foo"
    pass
f = Foo()
print(repr(f)) #输出结果 <__main__.Foo object at 0x002EB550>

上記のコードでは、__repr__メソッドを呼び出す必要があります。このクラスには__repr__メソッドがありません。親クラスのメソッドは、__str__メソッドを実行せずに直接借用されます。したがって、reprはstrのスペアタイヤですが、strをreprのスペアタイヤにすることはできません。

__iter__および__next__

あなたがのためのクラスになりたい場合はfor ... in、そのリストやタプルに似たサイクル、あなたが実装しなければならない__iter__()メソッドをメソッドは、イテレータオブジェクトを返し、その後、ループ反復のためのPythonは、オブジェクトの呼び出しを継続する__next__()次のサイクルを取得する方法をStopIterationエラーが発生したときにループを終了するまでの値

フィボナッチ数列を例にとると、forループで使用できるFibクラスを記述します。

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1 # 初始化两个计数器a,b

    def __iter__(self):
        return self # 实例本身就是迭代对象,故返回自己

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b # 计算下一个值
        if self.a > 100000: # 退出循环的条件
            raise StopIteration()
        return self.a # 返回下一个值
#使用
>>> for n in Fib():
...     print(n)
1
1
2
3
5
...
46368
75025
class Range:
    def __init__(self, n, stop, step):
        self.n = n
        self.stop = stop
        self.step = step

    def __next__(self):
        if self.n >= self.stop:
            raise StopIteration
        x = self.n
        self.n += self.step
        return x

    def __iter__(self):
        return self


for i in Range(1, 7, 3):
    print(i)

__getitem__

Fibインスタンスはforループで使用できますが、それでもリストとして使用することはできません。たとえば、5番目の要素を考えてみましょう。

>>> Fib()[5]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'Fib' object does not support indexing

下付き文字に従って要素を抽出するリストのよう動作するには、__getitem__()メソッドを実装する必要があります。

class Fib(object):
    def __getitem__(self, n):
        a, b = 1, 1
        for x in range(n):
            a, b = b, a + b
        return a
#使用
>>> f = Fib()
>>> f[0]
1

ただし、リストのスライス方法:Fibのエラーが報告されます。その理由は__getitem__()、渡されるパラメーターがintまたはsliceオブジェクトである可能性があるsliceため、次のことを判断する必要があるためです。

class Fib(object):
    def __getitem__(self, n):
        if isinstance(n, int): # n是索引
            a, b = 1, 1
            for x in range(n):
                a, b = b, a + b
            return a
        if isinstance(n, slice): # n是切片
            start = n.start
            stop = n.stop
            if start is None:
                start = 0
            a, b = 1, 1
            L = []
            for x in range(stop):
                if x >= start:
                    L.append(a)
                a, b = b, a + b
            return L
#使用
>>> f = Fib()
>>> f[0:5]
[1, 1, 2, 3, 5]

 あなたがのような物体を捉えた場合また、オブジェクトdict__getitem__()パラメータもキーとして使用することができますオブジェクトでもよいです。たとえばstr

これに対応するの__setitem__()は、オブジェクトをリストまたはdictとして扱い、コレクションに値を割り当てるメソッドです。最後に、__delitem__()要素を削除する方法があります。

要するに、上記のメソッドを通じて、私たち自身が定義するクラスは、Pythonに付属するリスト、タプル、およびdictと同じです。

__getattr__

クラスのメソッドまたは属性を呼び出すと、存在しない場合はエラーが報告されます。このエラーを回避するには、score属性を追加するだけでなく、属性を動的に返すメソッド記述して、__getattr__()機能も完全に可能です:

class Student(object):

    def __init__(self):
        self.name = 'Michael'

    def __getattr__(self, attr):
        if attr=='score':
            return 99

 属性が見つからない場合にのみ呼び出されることに注意してください__getattr__

などの呼び出しはすべてs.abcを返すことに注意してくださいNone。これは、定義した__getattr__デフォルトの戻り値がであるためですNoneクラスがいくつかの特定の属性のみに応答するようにするには、規則に従ってAttributeErrorエラーをスローする必要があります。

class Student(object):

    def __getattr__(self, attr):
        if attr=='age':
            return lambda: 25
        raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)

SDKを記述し、各URLに対応するAPIにメソッドを記述したい場合、それは使い果たされます。さらに、APIが変更されたら、SDKを変更する必要があります。

完全に動的なを使用し__getattr__て、チェーン呼び出しを記述できます。

class Chain(object):

    def __init__(self, path=''):
        self._path = path

    def __getattr__(self, path):
        return Chain('%s/%s' % (self._path, path))

    def __str__(self):
        return self._path

    __repr__ = __str__
>>> Chain().status.user.timeline.list
'/status/user/timeline/list'

GitHubのAPIなど、URLにパラメーターを配置するRESTAPIもいくつかあります。

GET /users/:user/repos

電話をかけるとき:userは、実際のユーザー名置き換える必要があります次のようなチェーン呼び出しを記述できる場合:

Chain().users('michael').repos

 __コール__

どのクラスでも__call__()、インスタンスを直接呼び出すためのメソッドを定義するだけで済みます。例を見てください:

class Student(object):
    def __init__(self, name):
        self.name = name

    def __call__(self):
        print('My name is %s.' % self.name)

呼び出しメソッドは次のとおりです。

>>> s = Student('Michael')
>>> s() # self参数不要传入
My name is Michael.

__call__()パラメータを定義することもできます。インスタンスを直接呼び出すことは、関数を呼び出すことに似ています

callable()関数介して、オブジェクトが「呼び出し可能な」オブジェクトであるかどうかを判断できます。たとえば、関数や上記で定義し__call__()たクラスインスタンスなどです

>>> callable(Student())
True
>>> callable(max)
True
>>> callable([1, 2, 3])
False
>>> callable(None)
False
>>> callable('str')
False

おすすめ

転載: blog.csdn.net/zangba9624/article/details/106249735