Python Cookbook第八章主要介绍了一些类定义的技巧,在此对感兴趣的一些内容进行记录。
简化数据的初始化
可以通过定义一个通用基类来同一管理数据的初始化。
class Structure:
_fields = []
def __init__(self, *args):
if len(args) != len(self._fields):
raise TypeError('Excepted {} arguments'.format(len(self._fields)))
for name, value in zip(self._fields, args):
setattr(self, name, value)
使用如下:
class Stock(Structure):
_fields = ['name', 'shares', 'price']
def __str__(self):
str_tmp = 'name:{}, shares:{}, price:{}'.format(self.name, self.shares, self.price)
return str_tmp
tmp = Stock('hahaha', 1, 2)
print(tmp)
输入如下
name:hahaha, shares:1, price:2
创建一个可管理的属性
可以使用@property来创建属性,并对属性进行简单的管理
class Person:
def __init__(self, first_name):
self.first_name = first_name
@property
def first_name(self):
return self._first_name
@first_name.setter
def first_name(self, value):
if not isinstance(value, str):
raise TypeError('Excepted str')
self._first_name = value
@first_name.deleter
def first_name(self):
raise AttributeError('Can not delete attribute.')
对类输入参数进行约束
可以通过定义描述器来对输入参数进行一定的约束。如对参数的类型进行约束,对输入数据的长度进行约束。
class Descriptor:
def __init__(self, name=None, **opts):
self.name = name
for key, value in opts.items():
setattr(self, key, value)
def __set__(self, instance, value):
instance.__dict__[self.name] = value
class Typed(Descriptor):
excepted_type = type(None)
def __set__(self, instance, value):
if not isinstance(value, self.excepted_type):
raise TypeError('Excepted ' + str(self.excepted_type))
super().__set__(instance, value)
# 约束输入参数为int
class Integer(Typed):
excepted_type = int
# 要求输入为字符串
class String(Typed):
excepted_type = str
# 约束最大输入长度
class MaxSized(Descriptor):
def __init__(self, name=None, **opts):
if 'size' not in opts:
raise TypeError('missing size option')
super().__init__(name, **opts)
def __set__(self, instance, value):
if len(value) >= self.size:
raise ValueError('size must be < ' + str(self.size))
super().__set__(instance, value)
# 要求参数大于等于0
class Unsigned(Descriptor):
def __set__(self, instance, value):
if value < 0:
raise TypeError('Excepted >= 0')
super().__set__(instance, value)
# 要求输入为有长度限制的str
class SizedString(String, MaxSized):
pass
# 要求输入为大于等于0的int
class UnsignedInt(Integer, Unsigned):
pass
# 装饰器用于代替类似shares=UnsignedInteger('shares')的操作
def check_attributes(**kwargs):
def decorate(cls):
for key, value in kwargs.items():
if isinstance(value, Descriptor):
value.name = key
setattr(cls, key, value)
else:
setattr(cls, key, value(key))
return cls
return decorate
@check_attributes(name=SizedString(size=8),
shares=UnsignedInteger,
price=UnsignedInteger)
class Stock:
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price