代码之家  ›  专栏  ›  技术社区  ›  mpen

如何将iter添加到动态类型?

  •  2
  • mpen  · 技术社区  · 15 年前

    def flags(*opts):
        keys = [t[0] for t in opts]
        words = [t[1] for t in opts]
        nums = [2**i for i in range(len(opts))]
        attrs = dict(zip(keys,nums))
        choices = iter(zip(nums,words))
        return type('Flags', (), dict(attrs))
    
    Abilities = flags(
        ('FLY', 'Can fly'),
        ('FIREBALL', 'Can shoot fireballs'),
        ('INVISIBLE', 'Can turn invisible'),
    )
    

    问题

    如何添加 __iter__ Abilities 这样我就可以重复 choices ?

    这样我就可以使用

    hero.abilities = Abilities.FLY | Abilities.FIREBALL
    
    if hero.abilities & Abilities.FIREBALL:
    
    for k, v in Abilities:
        print k, v
    

    在我的代码中,不必使用任何幻数或字符串,我还可以将标志集保存为单个int,或以可读格式显示列表。

    5 回复  |  直到 15 年前
        1
  •  4
  •   Glenn Maynard    15 年前

    这里不需要使用动态类型;我将它重新构造为一个简单的类,例如:

    class flags(object):
        def __init__(self, *opts):
            keys = [t[0] for t in opts]
            words = [t[1] for t in opts]
            nums = [2**i for i in range(len(opts))]
            self.attrs = dict(zip(keys,nums))
            self.choices = zip(nums,words)
    
        def __getattr__(self, a):
            return self.attrs[a]
    
        def __iter__(self):
            return iter(self.choices)
    
    Abilities = flags(
        ('FLY', 'Can fly'),
        ('FIREBALL', 'Can shoot fireballs'),
        ('INVISIBLE', 'Can turn invisible'),
    )
    
    print Abilities.FLY
    for k, v in Abilities:
        print k, v
    
        2
  •  1
  •   msw    15 年前

    dict 具有 __getattr__ 为什么不从一开始:

    class Flags(dict):
        def __init__(self, *args):
            dict.__init__(self, args)
        def __getattr__(self, name):
             return self[name]
    ...
    

    dict.__iter__() 生成键和 dict.iteritems()

        3
  •  0
  •   Alex Martelli    15 年前

    flags 应该是:

    choices = iter(zip(nums,words))
    attrs['__iter__'] = lambda self: choices
    return type('Flags', (), dict(attrs))()
    

    注意,我添加了一个行设置 __iter__ , () return 类型(在 类型

    最后一行

    return type('Flags', (), attrs)()
    

    因为没有理由复制 attrs ,这已经是 dict (但这是无伤大雅的冗余,不是致命的错误;-)。

        4
  •  0
  •   Andrey Vlasovskikh    15 年前

    __getattr__ 通过访问动态字段而不是处理元类的方法 type .

    编辑:

    class Abilities(object):
        def __init__(self, abilities):
            self.abilities = abilities
    
        def __getattr__(self, name):
            a = [x for x in self.abilities if x[0] == name]
            if len(a) != 1:
                raise AttributeError('attribute {0} not found'.format(name))
            title, id, help = a[0]
            return id
    
        def __iter__(self):
            return (id, help for title, id, help in self.abilities)
    
    SPEC = [
        ('FLY', 10, 'Can fly'),
        ('FIREBALL', 13, 'Can shoot fireballs'),
        ('INVISIBLE', 14, 'Can turn invisible'),
    ]
    
    abitilies = Abilities(SPEC)
    
    hero.abilities = abilities.FLY | abilities.FIREBALL
    for k, v in abilities:
        print k, v
    
        5
  •  0
  •   mpen    15 年前

    根据你们的建议,我想到了这个:

    来源

    class enumerable(object):
        def __init__(self, func, *opts):
            keys = func(len(opts))
            self.attrs = dict(zip([t[0] for t in opts], keys))
            self.opts = zip(keys, [t[1] for t in opts])
        def __getattr__(self, a):
            return self.attrs[a] 
        def __len__(self):
            return len(self.opts)
        def __iter__(self):
            return iter(self.opts)
        def __deepcopy__(self, memo):
            return self
    
    class enum(enumerable):
        def __init__(self, *opts):
            return super(enum, self).__init__(range, *opts)
    
    class flags(enumerable):
        def __init__(self, *opts):
            return super(flags, self).__init__(lambda l: [1<<i for i in range(l)], *opts)
    
    ### tests:
    
    Abilities = enum(
        ('FLY', 'Can fly'),
        ('FIREBALL', 'Can shoot fireballs'),
        ('INVISIBLE', 'Can turn invisible'),
        ('FROST_NOVA', 'Can call down an ice storm'),
        ('BLINK', 'Can teleport short distances'),
    )
    
    print 'Fireball = %d' % Abilities.FIREBALL
    print 'Number of options = %d' % len(Abilities) 
    for k, v in Abilities:
        print '%d: %s' % (k, v)
    

    Fireball = 1
    Number of options = 5
    0: Can fly
    1: Can shoot fireballs
    2: Can turn invisible
    3: Can call down an ice storm
    4: Can teleport short distances
    

    不管出于什么原因,我的特殊应用程序需要 __deepcopy__ self .