目次
__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