Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The answer is found in the two types of class that Python has.</p> <p>The first code-snippet you provided uses a legacy "old-style" class (you can tell because it doesn't subclass anything - there's nothing before the colon). Its semantics are peculiar. In particular, you can add a special method to an instance:</p> <pre><code>class Foo: def __init__(self, num): self.num = num def _fn(other): return self.num + other.num self.__add__ = _fn </code></pre> <p>and get a valid response:</p> <pre><code>&gt;&gt;&gt; f = Foo(2) &gt;&gt;&gt; g = Foo(1) &gt;&gt;&gt; f + g 3 </code></pre> <p>But, subclassing <code>dict</code> means you are generating a new-style class. And the semantics of operator overloading are different:</p> <pre><code>class Foo (object): def __init__(self, num): self.num = num def _fn(other): return self.num + other.num self.__add__ = _fn &gt;&gt;&gt; f = Foo(2) &gt;&gt;&gt; g = Foo(1) &gt;&gt;&gt; f + g Traceback ... TypeError: unsupported operand type(s) for +: 'Foo' and 'Foo' </code></pre> <p>To make this work with new-style classes (which includes subclasses of <code>dict</code> or just about any other type you will find), you have to make sure the special method is defined on the class. You can do this through a metaclass:</p> <pre><code>class _MetaFoo(type): def __init__(cls, name, bases, args): def _fn(self, other): return self.num + other.num cls.__add__ = _fn class Foo(object): __metaclass__ = _MetaFoo def __init__(self, num): self.num = num &gt;&gt;&gt; f = Foo(2) &gt;&gt;&gt; g = Foo(1) &gt;&gt;&gt; f+g 3 </code></pre> <p>Also, the semantic difference means that in the very first case I could define my local add method with one argument (the <code>self</code> it uses is captured from the surrounding scope in which it is defined), but with new-style classes, Python expects to pass in both values explicitly, so the inner function has two arguments.</p> <p>As a previous commenter mentioned, best to avoid old-style classes if possible and stick with new-style classes (old-style classes are removed in Python 3+). Its unfortunate that the old-style classes happened to work for you in this case, where new-style classes will require more code.</p> <hr> <p>Edit: </p> <p>You can also do this more in the way you originally tried by setting the method on the <em>class</em> rather than the <em>instance</em>:</p> <pre><code>class Foo(object): def __init__(self, num): self.num = num setattr(Foo, '__add__', (lambda self, other: self.num + other.num)) &gt;&gt;&gt; f = Foo(2) &gt;&gt;&gt; g = Foo(1) &gt;&gt;&gt; f+g 3 </code></pre> <p>I'm afraid I sometimes think in Metaclasses, where simpler solutions would be better :)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload