[英]Restricting attribute type with metaclass
我正在嘗試使用Python進入元類編程,我想知道如何使用元類限制屬性類型。 使用描述符很容易,但是元類呢?
這是一個簡短的例子:
>>> class Image(Object):
... height = 0
... width = 0
... path = '/tmp'
... size = 0
>>> img = Image()
>>> img.height = 340
>>> img.height
340
>>> img.path = '/tmp/x00.jpeg'
>>> img.path
'/tmp/x00.jpeg'
>>> img.path = 320
Traceback (most recent call last):
...
TypeError
Python版本是2.7
只需覆蓋元類中的__setattr__
,並在初始化期間檢查每個屬性的默認類型:
>>> class Meta(type):
def __new__(meta, name, bases, dict):
def _check(self, attr, value):
if attr in self.defaults:
if not isinstance(value, self.defaults[attr]):
raise TypeError('%s cannot be %s' % (attr, type(value)))
else:
self.defaults[attr] = type(value)
def _setattr(self, attr, value):
_check(self, attr, value)
object.__setattr__(self, attr, value)
cls = type.__new__(meta, name, bases, dict)
# Set up default type for every attribute
cls.defaults = {name: type(value) for name, value in dict.items()}
cls.__setattr__ = _setattr
return cls
>>> class Image(object):
__metaclass__ = Meta
height = 0
width = 0
path = '/tmp'
size = 0
>>> i = Image()
>>> i.height = 240
>>> i.height
240
>>> i.size
0
>>> i.size = 7
>>> i.size
7
>>> i.path = '/tmp/subdir'
>>> i.path
'/tmp/subdir'
>>> i.path = 23
TypeError: path cannot be <type 'int'>
替代(也許更優雅)的方法:
class MetaBase(object):
def _check(self, attr, value):
if attr in self.defaults:
if not isinstance(value, self.defaults[attr]):
raise TypeError('%s cannot be %s' % (attr, type(value)))
else:
self.defaults[attr] = type(value)
def __setattr__(self, attr, value):
self._check(attr, value)
super(MetaBase, self).__setattr__(attr, value)
class Meta(type):
def __new__(meta, name, bases, dict):
cls = type.__new__(meta, name, (MetaBase,) + bases, dict)
cls.defaults = {name: type(value) for name, value in dict.items()}
return cls
class Image(object):
__metaclass__ = Meta
height = 0
width = 0
path = '/tmp'
size = 0
行為與以前相同
覆蓋元類中的__setattr__
。 請注意,您必須分別檢查初始值(示例中為height=0, path = '/tmp'
):
class RestrictAttrs(type):
def __new__(mcs, name, bases, dct):
def _checkattr(k, v):
if k == 'path':
if not isinstance(v, str):
raise TypeError('path must be a str!')
def _setattr(self, k, v):
_checkattr(k, v)
self.__dict__[k] = v
# Check of initial values (optional)
for k,v in dct.items():
_checkattr(k, v)
res = type.__new__(mcs, name, bases, dct)
res.__setattr__ = _setattr
return res
class Image(object):
__metaclass__ = RestrictAttrs
path = '/tmp'
i = Image()
i.path = 32
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.