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__プロパティ.辞書ではなく、クラスのインスタンスを固定サイズの配列として表します.
しかし、定義後に新しい属性の追加がサポートされなくなり、継承などの特性をサポートしないクラスもあるので、この属性をできるだけ少なく使用する必要があります.
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