代码之家  ›  专栏  ›  技术社区  ›  Pavel Minaev

python有匿名类吗?

  •  63
  • Pavel Minaev  · 技术社区  · 15 年前

    我想知道python是否有类似c匿名类的特性。为了澄清,这里有一个示例C片段:

    var foo = new { x = 1, y = 2 };
    var bar = new { y = 2, x = 1 };
    foo.Equals(bar); // "true"
    

    在python中,我可以想象这样的情况:

    foo = record(x = 1, y = 2)
    bar = record(y = 2, x = 1)
    foo == bar  # true
    

    特定的要求是能够在表达式上下文中创建具有指定字段的对象(例如,在lambda和不允许使用语句的其他位置中可用),不需要额外的外部声明,并且能够通过普通成员访问语法按名称访问单个组件。 foo.bar . 创建的对象还应实现结构比较 按组件名称 (不是按位置,就像元组那样)。

    尤其是:元组不是因为它们的组件没有命名;类不是因为它们需要声明;dict不是因为它们不需要声明 foo["bar"] 访问组件的语法。

    namedtuple 不是吗,因为它仍然需要一个名称,即使您定义了类型inline,并且比较是基于位置的,而不是基于名称的。特别地:

     def foo(): return namedtuple("Foo", "x y")(x = 1, y = 2)
     def bar(): return namedtuple("Foo", "y x")(x = 1, y = 2)
     foo() == bar()   # False because fields are compared in order, and not by name
                      # True would be desired instead
    

    如果需要的话,我知道如何用Python编写这样的东西。但我想知道,在Python标准库或任何流行的第三方库中是否有类似的东西。

    [编辑]

    为了这个目的,这里有一个单一的表达式解决方案,它结合了ken和alanlcode提供的两个非常有用的答案,在没有任何额外的外部声明的情况下产生了结构平等:

    type("", (), { \
        "__init__": (lambda self, **kwargs: self.__dict__.update(kwargs)), \
        "__eq__": (lambda self, other: self.__dict__ == other.__dict__) } \
    )(x = 1, y = 2)
    

    从技术上讲,它满足了问题的所有要求,但我真诚地希望没有人使用它(我绝对不会)。

    8 回复  |  直到 15 年前
        1
  •  47
  •   dF.    15 年前

    蟒蛇的方法是用 dict :

    >>> foo = dict(x=1, y=2)
    >>> bar = dict(y=2, x=1)
    >>> foo == bar
    True
    

    满足你所有的要求,除了你还必须做 foo['x'] 而不是 foo.x .

    如果这是一个问题,您可以很容易地定义一个类,例如:

    class Bunch(object):
        def __init__(self, **kwds):
            self.__dict__.update(kwds)
    
        def __eq__(self, other):
            return self.__dict__ == other.__dict__
    

    或者,一个又好又短的

    class Bunch(dict):
        __getattr__, __setattr__ = dict.get, dict.__setitem__
    

    (但请注意,正如亚历克斯在他的评论中指出的,第二个问题是有问题的!)

        2
  •  36
  •   alanlcode    15 年前

    1)见 http://uszla.me.uk/space/blog/2008/11/06 . 通过使用 type 内置功能:

     anon_object_2 = type("", (), {})()
    

    其中第三个参数是将包含对象字段的dict。

     foo = type("", (), dict(y=1))()
     foo.y == 1
    

    2)Peter Norvig在 http://norvig.com/python-iaq.html . 这也与Ken发布的答案相似。

    class Struct:
        def __init__(self, **entries): self.__dict__.update(entries)
    
    >>> options = Struct(answer=42, linelen = 80, font='courier')
    >>> options.answer
    42
    

    这个方法的好处是,您可以通过dict的内容实现相等,而第一个选项没有。

        3
  •  33
  •   Pavel Minaev    12 年前

    似乎python 3.3已经以 types.SimpleNamespace 班级。

        4
  •  6
  •   ars    15 年前

    类型(…)表单将不符合结构比较要求(不会变得非常难看)。dict(…)表单不满足属性访问器要求。

    这个 attrdict 似乎落在中间的某个地方:

    class attrdict(dict):
        def __init__(self, *args, **kwargs):
            dict.__init__(self, *args, **kwargs)
            self.__dict__ = self
    
    a = attrdict(x=1, y=2)
    b = attrdict(y=2, x=1)
    
    print a.x, a.y
    print b.x, b.y
    print a == b
    

    但这意味着要定义一个特殊的类。

    好的,我刚注意到问题的更新。我注意到你可以指定 dict 对于bases参数,只需要指定构造函数即可(在icky类型表达式中)。我更喜欢Attrdict。-)

        5
  •  6
  •   Tom Ken    10 年前

    我不记得是否有内置的,但自己写比键入问题要短。:-)

    class record(object):
      def __init__(self, **kwargs): self.__dict__ = kwargs
      def __eq__(self, r2): return self.__dict__ == r2.__dict__
      def __ne__(self, r2): return self.__dict__ != r2.__dict__
    
    foo = record(x=1, y=2)
    bar = record(y=2, x=1)
    foo == bar  # => true
    
        6
  •  4
  •   skyking    9 年前

    如果希望实例也是匿名的(直接在表达式中使用对象),那么就必须使用类型表达式。但是,在许多情况下,实例不会是匿名的,而是被分配给一个变量。在Python中,可以通过使用元类或修饰符以合理的方式处理这种情况。

    使用decorator的示例:

    def anonymous(cls):
        return cls()
    
    @anonymous
    class foo:
         x = 42
    
         def bar(self):
              return self.x
    

    本例中的decorator导致类 foo 在变量中实例化一个Put 而不是类本身。类本身将无法从任何命名空间访问,尽管它有一个名称:

    >>> foo
    <__main__.foo instance at 0x7fd2938d8320>
    >>> foo.bar()
    42
    

    python中的另一个特性可以适应许多用例,那就是在本地定义类是合法的,这意味着它们将成为该函数本地的一个符号,这反过来又给了它一定程度的匿名性。

        7
  •  4
  •   Jean-François Fabre    6 年前

    引用自 this page :

     class Struct:
         def __init__(self, **entries): self.__dict__.update(entries)
         def __eq__(self, other): return self.__dict__ == other.__dict__
         def __ne__(self, other): return self.__dict__ != other.__dict__
    
     options = Struct(answer=42, linelen = 80, font='courier')
     options.answer
     >>> 42
     options.answer = 'plastics'
     vars(options)
     >>> {'answer': 'plastics', 'font': 'courier', 'linelen': 80}
    
        8
  •  0
  •   TooGeeky    6 年前

    enter image description here

    如上所示,我从Pycharm那里得到了一个很好的智能感知,我喜欢这个解决方案…

    >>> def anonymous(cls):
    ...     return cls()
    >>> class fooo:
    ...     @anonymous
    ...     class c:
    ...             D=10
    >>> fooo.c.D
    10