如何创建可以给类提供实例数组并提供"voodoo"信息的元类.对所有类实例起作用的实例? [英] How to create a metaclass that can give a class an array of instances and provide a "voodoo" instance that acts on all class instances?

查看:75
本文介绍了如何创建可以给类提供实例数组并提供"voodoo"信息的元类.对所有类实例起作用的实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道如何在Python中创建一个可以创建其他类的元类:

I'm wondering how to create a metaclass in Python that can create other classes that:

  • 自动将其实例存储在数组中
  • 具有一个特殊实例NonMetaClass.all,其属性为:
    • 设置后,请使用相同的键将所有类的实例设置为相同的值(例如,Foo.all.num = 3会使Foo的所有实例的num均为3)
    • 在访问(获取)时,返回该类实例的所有键值的数组(例如,Foo.all.num返回[5, 3, 2])
    • 无法删除.
    • 在调用(如果属性是函数)时,请在类的所有实例上调用该方法.
    • Store their instances in an array automatically
    • Have a special instance, NonMetaClass.all, whose properties:
      • When set, set all the class's instances with the same key to the same value (e.g., Foo.all.num = 3 makes all instances of Foo have a num of 3)
      • When accessed (get), returns an array of all of the class's instances's key values (e.g., Foo.all.num returns [5, 3, 2])
      • Cannot be deleted.
      • When called (if the attribute is a function), call that method on all the instances of a class.

      用Python来讲,我想打开一个像这样的类:

      In Python terms, I would like to turn a class that is like this:

      class Foo(object):
          BAR = 23
          def __init__(self):
              self.a = 5
      
          def pointless():
              print 'pointless.'
      
          def change_a(self):
              self.a = 52
      

      对此:

      class Foo(object):
          BAR = 23
          instances = []
          all = # Some black magic to create the special "all" instance
          def __init__(self):
              self.a = 5
              Foo.instances.append(self)
      
          def pointless(self):
              print 'pointless.'
      
          def change_a(self):
              self.a = 52
      

      并能够像这样使用它:

      >>> Foo()
      >>> Foo.instances[0]
      <__main__.Foo instance at 0x102ff5758>
      >>> Foo()
      >>> len(Foo.instances)
      2
      >>> Foo.all.a = 78
      78
      >>> Foo.all.a
      [78, 78]
      >>> Foo.all.change_a()
      >>> Foo.all.a
      [52, 52]
      >>> 
      

      推荐答案

      好吧,我想出了如何针对Python 2.7单独执行此操作.我认为这可能是最好的解决方案,尽管它可能不是唯一的解决方案.它允许您设置,获取和函数调用Class.all的属性.我已经将元类命名为InstanceUnifier,但是如果您认为可以想到一个更好的名称(简短,更具描述性),请发表评论.

      Ok, I figured out how to do this for Python 2.7 on my own. This is what I believe to be the best solution though it may not be the only one. It allows you to set, get, and function call on attributes of Class.all. I've named the metaclass InstanceUnifier, but please comment if you think there's a better (shorter, more descriptive) name you can think of.

      class InstanceUnifier(type):
          '''
              What we want: A metaclass that can give a class an array of instances and provide a static Class.all object, that, when a method is called on it, calls the same method on every instance of the class.
          '''
          def __new__(cls, name, base_classes, dct):
              dct['all'] = None
              dct['instances'] = []
              return type.__new__(cls, name, base_classes, dct)
          def __init__(cls, name, base_classes, dct):
              class Accessor(object):
                  def __getattribute__(self, name):
                      array = [getattr(inst, name) for inst in cls.instances]
                      if all([callable(item) for item in array]):
                          def proxy_func(*args, **kwargs):
                              for i in range(len(cls.instances)):
                                  this = cls.instances[i]
                                  func = array[i]
                                  func(*args, **kwargs)
                          return proxy_func
                      elif all([not callable(item) for item in array]):
                          return array
                      else:
                          raise RuntimeError('Some objects in class instance array for key "'+name+'" are callable, some are not.')
                  def __setattr__(self, name, value):
                      [setattr(inst, name, value) for inst in cls.instances]
                  def __delattr__(self, name):
                      [delattr(inst, name) for inst in cls.instances]
              cls.all = Accessor()
              return type.__init__(cls, name, base_classes, dct)
      
          def __call__(cls, *args, **kwargs):
              inst = type.__call__(cls, *args, **kwargs)
              cls.instances.append(inst)
              return inst
      

      这篇关于如何创建可以给类提供实例数组并提供"voodoo"信息的元类.对所有类实例起作用的实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆