编程语言
首页 > 编程语言> > 用于加强自定义类型不变性的Python元类

用于加强自定义类型不变性的Python元类

作者:互联网

在寻找一种实现自定义类型不变性的方法之后,并没有找到令人满意的答案,我想到了自己以元类形式提出的解决方案:

class ImmutableTypeException( Exception ): pass

class Immutable( type ):
   '''
   Enforce some aspects of the immutability contract for new-style classes:
    - attributes must not be created, modified or deleted after object construction
    - immutable types must implement __eq__ and __hash__
   '''

   def __new__( meta, classname, bases, classDict ):
      instance = type.__new__( meta, classname, bases, classDict )

      # Make sure __eq__ and __hash__ have been implemented by the immutable type.
      # In the case of __hash__ also make sure the object default implementation has been overridden. 
      # TODO: the check for eq and hash functions could probably be done more directly and thus more efficiently
      #       (hasattr does not seem to traverse the type hierarchy)
      if not '__eq__' in dir( instance ):
         raise ImmutableTypeException( 'Immutable types must implement __eq__.' )

      if not '__hash__'  in dir( instance ):
         raise ImmutableTypeException( 'Immutable types must implement __hash__.' )

      if _methodFromObjectType( instance.__hash__ ):
         raise ImmutableTypeException( 'Immutable types must override object.__hash__.' )

      instance.__setattr__ = _setattr
      instance.__delattr__ = _delattr

      return instance

   def __call__( self, *args, **kwargs ):

      obj = type.__call__( self, *args, **kwargs )
      obj.__immutable__ = True

      return obj

def _setattr( self, attr, value ):

   if '__immutable__' in self.__dict__ and self.__immutable__:
      raise AttributeError( "'%s' must not be modified because '%s' is immutable" % ( attr, self ) )

   object.__setattr__( self, attr, value )

def _delattr( self, attr ):
   raise AttributeError( "'%s' must not be deleted because '%s' is immutable" % ( attr, self ) )

def _methodFromObjectType( method ):
   '''
   Return True if the given method has been defined by object, False otherwise.
   '''
   try:
      # TODO: Are we exploiting an implementation detail here? Find better solution! 
      return isinstance( method.__objclass__, object )
   except:
      return False

但是,尽管通用方法似乎工作得很好,但仍然存在一些难以实现的实现细节(另请参见代码中的TODO注释):

>如何检查类型层次结构中任何地方是否已实现特定方法?
>如何检查方法声明的来源是哪种类型(即,已定义方法的一部分)?

解决方法:

特殊方法总是在类型而不是实例上查找.因此,必须将hasattr应用于该类型.例如.:

>>> class A(object): pass
... 
>>> class B(A): __eq__ = lambda *_: 1
... 
>>> class C(B): pass
... 
>>> c = C()
>>> hasattr(type(c), '__eq__')
True

检查hasattr(c,’__eq__’)可能会产生误导,因为它可能错误地“捕获” c本身定义的按实例属性__eq__,这不能用作特殊方法(请注意,在__eq__的特定情况下,您会总是从hasattr看到True结果,因为祖先类对象定义了它,并且继承只能“添加”属性,而不能“减去”任何属性;-).

要检查哪个祖先类首先定义了一个属性(以及仅在类型上查找时将使用哪个确切的定义):

import inspect

def whichancestor(c, attname):
  for ancestor in inspect.getmro(type(c)):
    if attname in ancestor.__dict__:
      return ancestor
  return None

最好对此类任务使用检查,因为它的工作范围比直接访问type(c)上的__mro__属性要广泛.

标签:metaclass,immutability,python
来源: https://codeday.me/bug/20191106/2000635.html