Scrapy Item类分析

class BookItem(Item):
    name=Field()
    price=Field()
book=BookItem(name='abc',price=43)

在这里BookItem 继承Item类,并且有2个类属性:name和price。都是类Field的实例。

@six.add_metaclass(ItemMeta)
class Item(DictItem):
    pass

这里表示Item继承于DictItem。并且使用元类ItemMeta创建Item这个类实例。

class ItemMeta(ABCMeta):

    def __new__(mcs, class_name, bases, attrs):
        classcell = attrs.pop('__classcell__', None)
        new_bases = tuple(base._class for base in bases if hasattr(base, '_class'))
        _class = super(ItemMeta, mcs).__new__(mcs, 'x_' + class_name, new_bases, attrs)

        fields = getattr(_class, 'fields', {})
        new_attrs = {}
        for n in dir(_class):
            v = getattr(_class, n)
            if isinstance(v, Field):
                fields[n] = v
            elif n in attrs:
                new_attrs[n] = attrs[n]

        new_attrs['fields'] = fields
        new_attrs['_class'] = _class
        if classcell is not None:
            new_attrs['__classcell__'] = classcell
        return super(ItemMeta, mcs).__new__(mcs, class_name, bases, new_attrs)

在这里__new__的参数传入分别是(ItemMeta,BookItem,Item,( ('name',{}),('price',()) ))    PS:可参考 www.cnblogs.com/solakevon/p/8894822.html

因为在使用元类创建类实例时,会把类名,父类名,类属性传入。和使用type创建类实例一样。

new_bases是个空元祖。_class是x_item类。类属性和BookItem一样.

在for循环里面会把在attrs里面Field的实例给传到fields这个字典里面。其他非Field实例的类属性都放到new_attrs里面

最后把fields这个字典也放到new_attrs里面。此时fields里面有name和price。

class DictItem(MutableMapping, BaseItem):

    fields = {}

    def __init__(self, *args, **kwargs):
        self._values = {}
        if args or kwargs:  # avoid creating dict for most common case
            for k, v in six.iteritems(dict(*args, **kwargs)):
                self[k] = v

    def __getitem__(self, key):
        return self._values[key]

    def __setitem__(self, key, value):
        if key in self.fields:
            self._values[key] = value
        else:
            raise KeyError("%s does not support field: %s" %
                (self.__class__.__name__, key))

    def __delitem__(self, key):
        del self._values[key]

    def __getattr__(self, name):
        if name in self.fields:
            raise AttributeError("Use item[%r] to get field value" % name)
        raise AttributeError(name)

    def __setattr__(self, name, value):
        if not name.startswith('_'):
            raise AttributeError("Use item[%r] = %r to set field value" %
                (name, value))
        super(DictItem, self).__setattr__(name, value)

    def __len__(self):
        return len(self._values)

    def __iter__(self):
        return iter(self._values)

    __hash__ = BaseItem.__hash__

    def keys(self):
        return self._values.keys()

    def __repr__(self):
        return pformat(dict(self))

    def copy(self):
        return self.__class__(self)

在DictItem将会实现Item对象的一些功能。

 

posted @ 2018-04-21 00:23  solakevon  阅读(1810)  评论(0编辑  收藏  举报