Classmethods are evil

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Ivan Illarionov

    Classmethods are evil

    After re-reading "Python is not Java" I finally came to conclusion that
    classmethods in Python are a very Bad Thing.

    I can't see any use-case of them that couldn't be re-written more clearly
    with methods of metaclass or plain functions.

    They have the following issues:
    1. You mix instance-level and class-level functionality in one place
    making your code a mess.
    2. They are slower than metaclass methods or plain functions.

    I really want to hear your opinions on the subject.

    -- Ivan
  • Marc 'BlackJack' Rintsch

    #2
    Re: Classmethods are evil

    On Sat, 17 May 2008 04:01:50 +0000, Ivan Illarionov wrote:
    After re-reading "Python is not Java" I finally came to conclusion that
    classmethods in Python are a very Bad Thing.
    >
    I can't see any use-case of them that couldn't be re-written more clearly
    with methods of metaclass or plain functions.
    *The* use case IMHO are alternative constructors. They belong to the
    class, so functions are not as clear and it's possible to have more than
    one class in a module with class methods of the same name, e.g.
    `A.from_string( )` and `B.from_string( )` vs. `create_a_from_ string()` and
    `create_b_from_ string()`.

    And I don't see how functions can be inherited by sub classes like class
    methods can.

    Metaclasses are more clear than class methods? You must be joking!?
    They have the following issues:
    1. You mix instance-level and class-level functionality in one place
    making your code a mess.
    Writing meta classes just for alternative constructors seems to be more of
    a mess to me. Too much magic for such a simple case for my taste.

    Ciao,
    Marc 'BlackJack' Rintsch

    Comment

    • Carl Banks

      #3
      Re: Classmethods are evil

      On May 17, 12:01 am, Ivan Illarionov <ivan.illario.. .@gmail.com>
      wrote:
      After re-reading "Python is not Java" I finally came to conclusion that
      classmethods in Python are a very Bad Thing.
      >
      I can't see any use-case of them that couldn't be re-written more clearly
      with methods of metaclass or plain functions.
      I am probably one of the bigger advocates of metaclasses here, but
      given a problem that could equally well be solved by the two I would
      choose classmethods every time. Classmethods are more
      straightforward , easier to follow (especially by people who aren't
      used to working with metaclasses), and they hinder reusability less.

      Classmethods have practical advantages. One thing you can do with a
      classmethod that you can't directly do with a metaclass instancemethod
      is to call it with an instance:

      Python 2.5 (r25:51908, Apr 19 2007, 15:29:43)
      [GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
      Type "help", "copyright" , "credits" or "license" for more
      information.
      >>class A(type):
      ... def hello(self):
      ... print "hello"
      ...
      >>class B(object):
      ... __metaclass__ = A
      ... @classmethod
      ... def world(self):
      ... print "world"
      ...
      >>b = B()
      >>b.world()
      world
      >>b.hello()
      Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      AttributeError: 'B' object has no attribute 'hello'

      Though I can imagine some people would argue this is an advantage of
      metaclasses.

      They have the following issues:
      1. You mix instance-level and class-level functionality in one place
      making your code a mess.
      2. They are slower than metaclass methods or plain functions.
      >
      I really want to hear your opinions on the subject.
      I think neither of these reasons are very compelling. I don't even
      agree with the premise of #1, but even granting that it's messy to do
      that, I disagree that the mess would outweigh the drawbacks in
      complexity and reusability that a metaclass would bring. As for #2, I
      don't believe "class-level functionality" is often found in bottleneck
      situations, so what does it matter what speed it is?


      Carl Banks

      Comment

      • Hans Nowak

        #4
        Re: Classmethods are evil

        Ivan Illarionov wrote:
        After re-reading "Python is not Java" I finally came to conclusion that
        classmethods in Python are a very Bad Thing.
        >
        I can't see any use-case of them that couldn't be re-written more clearly
        with methods of metaclass or plain functions.
        I agree with your sentiments, although I'm not sure I would pick metaclasses
        over class methods... or over anything at all, for that matter. :-)
        They have the following issues:
        1. You mix instance-level and class-level functionality in one place
        making your code a mess.
        2. They are slower than metaclass methods or plain functions.
        The way I see it, a class method is really just sugar for a function operating
        on the class, living in the class namespace. As such, they are basically
        redundant, and as you point out, they can always be replaced by a function
        outside the class (and in fact, this was what people did before they came along
        in 2.2). Personally, I don't use them... but some people like them. Different
        strokes, and all that...

        --Hans

        Comment

        • Duncan Booth

          #5
          Re: Classmethods are evil

          Hans Nowak <zephyrfalcon!N O_SPAM!@gmail.c omwrote:
          The way I see it, a class method is really just sugar for a function
          operating on the class, living in the class namespace. As such, they
          are basically redundant, and as you point out, they can always be
          replaced by a function outside the class (and in fact, this was what
          people did before they came along in 2.2). Personally, I don't use
          them... but some people like them. Different strokes, and all that...
          >
          In exactly the same way you could claim that a method is just sugar for a
          function operating on the instance living in the instance namespace. As
          such, you might think that they too are basically redundant, but they
          aren't: with instance methods you get the ability to override the method in
          a subclass without the caller needing to know whether they are calling the
          original method or an overridden version.

          With class methods you also get the ability to override the method in a
          subclass, and again the caller doesn't need to know or care which variant
          when they call it.

          Say you have a class hierarchy with a from_keys() class method. If you want
          to construct a new Foo you might call Foo.from_keys() without caring
          whether the method is the original one defined in one of Foo's base classes
          or a modified version specific to a Foo. If you were using functions then
          you would need to define a new from_keys() function for every class in a
          hierarchy, or at least for every different implementation in the hierarchy
          and the caller would need to be careful to call the correct one. So we end
          up with functions from_keys_Foo_o r_Baz(cls) and from_keys_Bar() which is an
          unmaintainable mess.

          --
          Duncan Booth http://kupuguy.blogspot.com

          Comment

          • Bruno Desthuilliers

            #6
            Re: Classmethods are evil

            Ivan Illarionov a écrit :
            After re-reading "Python is not Java" I finally came to conclusion that
            classmethods in Python are a very Bad Thing.
            >
            I can't see any use-case of them that couldn't be re-written more clearly
            with methods of metaclass or plain functions.
            Plain functions don't give you polymorphic dispatch and can't be
            overriden. Using metaclass methods requires a custom metaclass, which 1/
            adds boilerplate code and cognitive load and 2/may bring problems,
            specially wrt/ MI.
            They have the following issues:
            1. You mix instance-level and class-level functionality in one place
            making your code a mess.
            May I remind you that every name defined at the top-level of a class
            statement becomes a class attribute ?

            Anyway : most of the use case I've had so far for classmethods required
            collaboration between the instance and the class, and I definitively
            prefer to have related functionalities defined in one place.
            2. They are slower than metaclass methods or plain functions.
            Slower than plain functions, indeed - but so are instancemethods . Slower
            that metaclass methods ? I never benchmarked this, but I don't see any
            reason that should be the case. Anyway, you could also argue that
            properties are slower than plain attributes, which are slower than local
            vars etc...
            I really want to hear your opinions on the subject.

            Mine is that classmethods are a GoodThing that make simple thing easy.

            Comment

            • Raymond Hettinger

              #7
              Re: Classmethods are evil

              On May 16, 9:01 pm, Ivan Illarionov <ivan.illario.. .@gmail.comwrot e:
              After re-reading "Python is not Java" I finally came to conclusion that
              classmethods in Python are a very Bad Thing.
              Sounds like a serious case of mis-learning.

              Class methods are the preferred way to implement alternate
              constructors. For good examples, see dict.fromkeys() or any of the
              various datetime constructors.

              Raymond

              Comment

              • Bruno Desthuilliers

                #8
                Re: Classmethods are evil

                Ivan Illarionov a écrit :
                On Mon, 19 May 2008 13:53:31 -0700, bruno.desthuill iers@gmail.com wrote:
                >
                >On 17 mai, 11:50, Ivan Illarionov <ivan.illario.. .@gmail.comwrot e:
                >(snip)
                >>How did I come to this:http://code.djangoproject.com/changeset/7098
                >>>
                >>I measured this and there was a marginal speed increase when
                >>classmethod s wher moved to metaclass.
                >IIRC (please correct me if I'm wrong), this part of code is only called
                >when the class is created - in which case it makes sense to move it
                >where it belongs, ie to the metaclass. This is by no mean a use case for
                >classmethods .
                >
                Yes, this is not the use case for class methods, but they where used
                there.
                Don't blame the tool for being misused.
                The whole point of my post was to say that classmethods are used
                in a wrong way too often
                I think it's the first time I see such a misuse of classmethods, and I
                have read quite a lot of (sometimes pretty hairy) Python code.
                and most of Python programmers don't know that
                the same thing can be implemented with metaclass methods.
                I'd say that most Python programmers using metaclasses know when to use
                a metaclass method and when to use a classmethod. One case of (slight)
                misuse is certainly not enough to infer a general rule, and that doesn't
                make classmethods bad in anyway. And while we're at it, I'd consider
                using a custom metaclass only to implement the equivalent of a
                classmethod a misuse too - and in this case, kind of a WTF.

                As a last point, there's at least one very big difference between a
                metaclass method and a classmethod, which is that you cannot call a
                metaclass method on an instance:

                class MyMeta(type):
                def bar(cls):
                print "%s.bar()" % cls

                class Foo(object):
                __metaclass__ = MyMeta

                @classmethod
                def baaz(cls):
                print "%s.baaz()" % cls

                Foo.baaz()
                Foo.bar()

                f = Foo()
                f.baaz()
                f.bar()

                =>

                <class '__main__.Foo'> .baaz()
                <class '__main__.Foo'> .bar()
                <class '__main__.Foo'> .baaz()
                Traceback (most recent call last):
                File "<stdin>", line 1, in <module>
                File "/tmp/python-18506gCT.py", line 17, in <module>
                f.bar()
                AttributeError: 'Foo' object has no attribute 'bar'

                I've had use case where I needed to call classmethods on instances,
                using a metaclass method would have required an explicit call, ie
                type(obj).some_ method() instead of obj.some_method (), which would have
                uselessly exposed this knowledge to client code.



                Comment

                Working...