python 3-cookbookノート:第8章クラスとオブジェクト
13844 ワード
python 3-cookbookの各セクションでは,ある種の問題におけるPython 3の最適な解決方法,あるいはPython 3自体のデータ構造,関数,クラスなどの特性がある種の問題でどのようによりよく使用されるかを検討した.この本はPython 3の理解を深め、Pythonのプログラミング能力を向上させるのに役立ちます.特に、Pythonプログラムの性能をどのように向上させるかに役立ちます.時間があれば、強くお勧めします.本文はノートを学ぶため、文の中の内容はただ自分の仕事の必要とふだん使って本の中の部分の内容を書いただけで、しかも文の中のサンプルのコードの多くは直接貼る原文のコードで、もちろん、コードの多くはPython 3にあります.6の環境で検証されました.分野によってプログラミングの注目点も異なり、興味のある人は全文を見ることができます.python3-cookbook:https://python3-cookbook.readthedocs.io/zh_CN/latest/index.html
8.4大量のオブジェクトを作成する際のメモリ節約方法
大量のオブジェクトを作成するのは非常にメモリを占めており、数百万もある可能性があります.この場合、クラスの__を使用することも考えられます.slots__プロパティ.辞書ではなく、クラスのインスタンスを固定サイズの配列として表します.
しかし、定義後に新しい属性の追加がサポートされなくなり、継承などの特性をサポートしないクラスもあるので、この属性をできるだけ少なく使用する必要があります.
8.6管理可能な属性の作成
オブジェクトのプロパティに値を割り当てると、タイプチェックや正当性検証などの追加の論理処理を行う場合は、property装飾器を使用して定義できます.propertyプロパティを定義する場合は、メソッド名(つまりプロパティ名)が同じである必要があることに注意してください.
ダイナミックなプロパティを定義する場合は、get/setメソッドを使用するよりもpropertyを使用して定義するとPythonコードが優雅になります.
propertyベースの使用例:
動的プロパティを定義するには、次の手順に従います.
8.11データ構造の初期化の簡略化
データ構造として使用されるクラスを大量に書く必要がある場合、各クラスに1つの__を定義したくない.init__方法の場合、以下の例を参考にすることができます.
8.16クラス内の複数のコンストラクタの定義
クラスメソッドclassmethodの主な用途は、複数のコンストラクタを定義することです.
8.25キャッシュインスタンスの作成
単例モードと同様に、オブジェクトを一度だけ作成したいか、loggingモジュールのように前に作成したオブジェクトを使用したい場合は、同じ名前を取得したloggerは永遠に1つしかありません.この問題はメタクラスなどの方法のほか、weakrefモジュールを使用することもできます.でも保証が必要だWeakValueDictionary()キャッシュ内のオブジェクトは他の場所でまだ使用されており、削除されずに回収されています.
8.4大量のオブジェクトを作成する際のメモリ節約方法
大量のオブジェクトを作成するのは非常にメモリを占めており、数百万もある可能性があります.この場合、クラスの__を使用することも考えられます.slots__プロパティ.辞書ではなく、クラスのインスタンスを固定サイズの配列として表します.
しかし、定義後に新しい属性の追加がサポートされなくなり、継承などの特性をサポートしないクラスもあるので、この属性をできるだけ少なく使用する必要があります.
import sys
class Date:
__slots__ = ['year', 'month', 'day']
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
d = Date(1, 2, 3)
try:
# sys.getsizeof(d) d , __dict__
# __slots__ , __dict__ ,
print(sys.getsizeof(d.__dict__))
except Exception as e:
print(e)
8.6管理可能な属性の作成
オブジェクトのプロパティに値を割り当てると、タイプチェックや正当性検証などの追加の論理処理を行う場合は、property装飾器を使用して定義できます.propertyプロパティを定義する場合は、メソッド名(つまりプロパティ名)が同じである必要があることに注意してください.
ダイナミックなプロパティを定義する場合は、get/setメソッドを使用するよりもpropertyを使用して定義するとPythonコードが優雅になります.
propertyベースの使用例:
class Person:
def __init__(self, first_name):
# self.first_name , property
# self.first_name , setter
self.first_name = first_name
@property
def first_name(self):
"""getter : , getter , setter """
return self._first_name
# property ,
@first_name.setter
def first_name(self, value):
""" property , """
if not isinstance(value, str):
raise TypeError('Expected a string!!!')
self._first_name = value
@first_name.deleter
def first_name(self):
raise AttributeError("Can't delete attribute!!!")
a = Person('Guido')
print(a.first_name)
try:
a.first_name = 42
except TypeError as e:
print(e)
try:
del a.first_name
except AttributeError as e:
print(e)
Guido
Expected a string!!!
Can't delete attribute!!!
動的プロパティを定義するには、次の手順に従います.
import math
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return math.pi * self.radius ** 2
@property
def diameter(self):
return self.radius * 2
@property
def perimeter(self):
return 2 * math.pi * self.radius
8.11データ構造の初期化の簡略化
データ構造として使用されるクラスを大量に書く必要がある場合、各クラスに1つの__を定義したくない.init__方法の場合、以下の例を参考にすることができます.
import math
class Structure1:
# ,
_fields = []
def __init__(self, *args):
if len(args) != len(self._fields):
raise TypeError('Expected {} arguments'.format(len(self._fields)))
# , _fields ,
for name, value in zip(self._fields, args):
setattr(self, name, value)
#
class Stock(Structure1):
_fields = ['name', 'shares', 'price']
class Point(Structure1):
_fields = ['x', 'y']
class Circle(Structure1):
_fields = ['radius']
def area(self):
return math.pi * self.radius ** 2
8.16クラス内の複数のコンストラクタの定義
クラスメソッドclassmethodの主な用途は、複数のコンストラクタを定義することです.
import time
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def today(cls):
""" """
t = time.localtime()
return cls(t.tm_year, t.tm_mon, t.tm_mday)
# __init__
a = Date(2012, 12, 21)
#
b = Date.today()
8.25キャッシュインスタンスの作成
単例モードと同様に、オブジェクトを一度だけ作成したいか、loggingモジュールのように前に作成したオブジェクトを使用したい場合は、同じ名前を取得したloggerは永遠に1つしかありません.この問題はメタクラスなどの方法のほか、weakrefモジュールを使用することもできます.でも保証が必要だWeakValueDictionary()キャッシュ内のオブジェクトは他の場所でまだ使用されており、削除されずに回収されています.
import weakref
class Spam:
def __init__(self, name):
self.name = name
# ,
# ,
_spam_cache = weakref.WeakValueDictionary()
# ,
def get_spam(name):
if name not in _spam_cache:
s = Spam(name)
_spam_cache[name] = s
else:
s = _spam_cache[name]
return s
a = get_spam('foo')
b = get_spam('bar')
c = get_spam('foo')
print(a is b) # False
print(a is c) # True