- robot中比较难理解的【元类和描述符类】
- 【重点1】with_metaclass,init,new
- 【重点2】get,set
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>
'''
- 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