zoukankan      html  css  js  c++  java
  • robot 源码解读6【元类和描述符类】

    1. robot中比较难理解的【元类和描述符类】
    • 【重点1】with_metaclass,initnew
    • 【重点2】getset

    with_metaclass见如下文章:

    
    import copy
    
    
    class setter(object):   # 将类中的方法变成类的属性【属性名:_setter__方法名】
    
        def __init__(self, method):
            self.method = method
            self.attr_name = '_setter__' + method.__name__
            self.__doc__ = method.__doc__
    
        def __get__(self, instance, owner):
            if instance is None:
                return self
            try:
                return getattr(instance, self.attr_name)
            except AttributeError:
                raise AttributeError(self.method.__name__)
    
        def __set__(self, instance, value):
            if instance is None:
                return
            setattr(instance, self.attr_name, self.method(instance, value))
    
    
    def with_metaclass(meta, *bases):   # 虚拟元类,参数元类meta,返回元类metaclass 【更正20210421】返回的不是元类,正常的类见【相当于 1,2】
        """Create a base class with a metaclass."""
        # This requires a bit of explanation: the basic idea is to make a
        # dummy metaclass for one level of class instantiation that replaces
        # itself with the actual metaclass.
    
        class metaclass(type):
            def __new__(cls, name, this_bases, d):
                return meta(name, bases, d)  # 常规的return type(name, bases, attr)
    
        print(type.__new__(metaclass, 'temporary_class', (), {}))
        return type.__new__(metaclass, 'temporary_class', (), {})  # return __new__的情况 , 返回【类】,【参数:当前准备创建的类的对象,类的名字,类继承的父类集合,类的方法集合】
    
    
    class SetterAwareType(type):    # 元类 ,将被setter修饰的属性添加到__slots__
    
        def __new__(cls, name, bases, dct):
            slots = dct.get('__slots__')
            if slots is not None:
                for item in dct.values():
                    if isinstance(item, setter):
                        slots.append(item.attr_name)
            return type.__new__(cls, name, bases, dct)
    
        def test1(self):
            print('test1 ok')
    
    
    # 不是元类了,定义Message的父类,copy相关的函数
    class ModelObject(with_metaclass(SetterAwareType, object)):  # 还是元类? 不是元类20210420, 不明白为什么要with_metaclass(SetterAwareType, object)弄一下
    
        def copy(self, **attributes):
            copied = copy.copy(self)
            for name in attributes:
                setattr(copied, name, attributes[name])
            return copied
    
        def test2(self):
            print('test2 ok')
    
    
    # 相当于 1  【重点】函数方法的话可以灵活修改base类
    class temporary_class2(object, metaclass=SetterAwareType):
        pass
    
    # 相当于 2  【重点】这种写法类名写死了
    class ModelObject2(temporary_class2):
    
        def copy(self, **attributes):
            copied = copy.copy(self)
            for name in attributes:
                setattr(copied, name, attributes[name])
            return copied
    
        def test2(self):
            print('test2 ok')
    
    # 相当于 3
    class Message2(ModelObject2):
    
        def test3(self):
            print('test3 ok')
    
    # 相当于 4
    # m2 = Message2()
    # m2.test3()
    
    class Message(ModelObject):
        """A message created during the test execution.
    
        Can be a log message triggered by a keyword, or a warning or an error
        that occurred during parsing or test execution.
        """
    
        @setter
        def parent(self, parent):
            if parent and parent is not getattr(self, 'parent', None):
                self._sort_key = getattr(parent, '_child_sort_key', -1)
            return parent
    
        def test3(self):
            print('test3 ok')
    
    
    m = Message()        # <class '__main__.temporary_class'>
    # m.test1()    # 错误 AttributeError: 'Message' object has no attribute 'test1'
    m.test2()            # test2 ok
    m.test3()            # test3 ok
    
    print(SetterAwareType)       # <class '__main__.SetterAwareType'>
    print(type(SetterAwareType)) # <class 'type'>
    print(ModelObject)           # <class '__main__.ModelObject'>
    print(type(ModelObject))     # 1. <class '__main__.SetterAwareType'>
    print(Message)               # <class '__main__.Message'>
    print(type(Message))         # 1. <class '__main__.SetterAwareType'>
    print(m)                     # <__main__.Message object at 0x000001BFAB6D1108>
    
    '''
    <class '__main__.temporary_class'>
    test2 ok
    test3 ok
    <class '__main__.SetterAwareType'>
    <class 'type'>
    <class '__main__.ModelObject'>
    <class '__main__.SetterAwareType'>
    <class '__main__.Message'>
    <class '__main__.SetterAwareType'>
    <__main__.Message object at 0x000001BFAB6D1108>
    '''
    
    
    1. Store 类也有【with_metaclass】 20210624
    https://stackoverflow.com/questions/18513821/python-metaclass-understanding-the-with-metaclass
    
    from six import with_metaclass
    
    class Store(with_metaclass(ABCMeta, object)):
        """ Store abstraction.
    
        Every store implementation must inherit from this class, in order to be
        accepted by LookupHandler.
        """
    
        @abstractmethod
        def __len__(self):
            raise NotImplementedError
    
        @abstractmethod
        def add(self, instance, alias):
            """ Remember instance by given alias. """
            raise NotImplementedError
    
        @abstractmethod
        def get(self, alias):
            """ Return instance remembered by given alias. """
            raise NotImplementedError
    
        @abstractmethod
        def remove(self, alias):
            """ Forget given alias. """
            raise NotImplementedError
    
        @abstractmethod
        def remove_object(self, instance):
            """ Forget every alias that this instance is remembered by. """
            raise NotImplementedError
    
        @abstractmethod
        def reset(self):
            """ Forget everything and revert to starting state. """
    
    
    class AliasStore(Store):
        """ Basic lookup store implementation.
    
    
    
    
    # 理解
    from six import with_metaclass
    
    class Meta(type):
        pass
    
    class Base(object):
        pass
    
    class MyClass(with_metaclass(Meta, Base)):
        pass
    
    
    # 也可以这样
    import six
    
    @six.add_metaclass(Meta)
    class MyClass(Base):
        pass
    
    
  • 相关阅读:
    baidu 地图 鼠标移上显示标签 鼠标离开隐藏标签
    ci框架 用框架自带db 添加括号,比如 like 等等左右添加括号 解决办法
    layDate 闪现 循环一个以上会闪现
    typescript定义函数类型
    typescript中的类与接口的关系
    typescript中的类
    typescript中的接口
    mac 上配置 ssh 免密登录服务器 【非常简单】
    Go语言中的map(十一)
    Go语言中的切片(十)
  • 原文地址:https://www.cnblogs.com/amize/p/14667177.html
Copyright © 2011-2022 走看看