Static variable vs Class variable

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • minkoo.seo@gmail.com

    #1

    Static variable vs Class variable

    Hi.

    I've got a question on the differences and how to define static and
    class variables. AFAIK, class methods are the ones which receives the
    class itself as an argument, while static methods are the one which
    runs statically with the defining class.

    Hence, my understanding is that static variables must be bound to the
    class defining the variables and shared by children of parent class
    where the variable is defined. But, please have a look at this code in
    which a guy told me that the variable a is static:
    >>class Foo:
    a = 1
    @classmethod
    def increment(cls):
    cls.a += 1
    print cls.a

    Here, I am defining variable a which, I believe is class variable,
    i.e., variable that is not bound to Foo itself. Rather, a is bound to
    the class which is accessing the variable. The code that corroborates
    this idea is as follows:
    >>class Child1(Foo):
    pass
    >>Child1.increm ent()
    4
    >>class Child2(Foo):
    pass
    >>Child2.increm ent()
    4

    This means that Child1 and Child2 does not share variable a which
    means that variable a is class variable rather than static variable.

    Could you please comment on this? Is a static or class variable?
    What's the most recent way of defining 'class' and 'static' variables?

    Thanks.
    - Minkoo

  • Laszlo Nagy

    #2
    Re: Static variable vs Class variable

    minkoo.seo@gmai l.com wrote:
    Hi.
    >
    I've got a question on the differences and how to define static and
    class variables. AFAIK, class methods are the ones which receives the
    class itself as an argument, while static methods are the one which
    runs statically with the defining class.
    >
    Hence, my understanding is that static variables must be bound to the
    class defining the variables and shared by children of parent class
    where the variable is defined. But, please have a look at this code in
    which a guy told me that the variable a is static:
    >
    >
    >>>class Foo:
    >>>>
    a = 1
    @classmethod
    def increment(cls):
    cls.a += 1
    print cls.a
    >
    In your increment() method, you do this:

    cls.a += 1

    It does the following thing:

    #1. read cls.a
    #2. add one
    #3. assign this value to cls.a

    In point #3, you really bind a name to a value. As you probably know, in
    Python, there are names and objects. The initial value of the name 'a'
    is 1. It is an immutable object. The "+=" operator usually increments a
    value of an object. However, because the 'int' type is immutable, the +=
    operator will rather rebind this variable to a newly created value. I
    believe this is what is happening here. Your question "is variable a
    static or class variable?" has no real answer. After running the
    increment() method on a descendant class, e.g. Child1 will rebind the
    name Child1.a, creating a new name in the namespace of the class. So the
    variable Foo.a is still there, but you are accessing Child1.a instead.

    If you want to HANDLE a as a static variable, you can handle it with a
    static method. That won't bind a new name in the descendant class.
    (However, you can still rebind it, e.g. "Child.a=42 ")


    Now here is a good question: how do you handle a variable as static,
    from a class (not static) method? Here is an example:
    >>class Foo(object):
    .... a = 1
    .... @classmethod
    .... def increment(cls):
    .... Foo.a += 1
    .... print cls.a
    ....
    >>class Child1(Foo):
    .... pass
    ....
    >>Child1.increm ent()
    2
    >>Child1.increm ent()
    3
    >>Foo.a
    3
    >>Child1.a = 10
    >>Child1.increm ent()
    10
    >>Child1.increm ent()
    10
    >>Child1.increm ent()
    10
    >>Foo.a
    6
    >>>


    However, the question is: why would you do this? :-)

    BTW you should use new style classes whenever it is possible. Old style
    classes will have gone...

    Hope this helps,

    Laszlo

    Comment

    • Marc 'BlackJack' Rintsch

      #3
      Re: Static variable vs Class variable

      On Tue, 09 Oct 2007 09:16:12 -0700, minkoo.seo@gmai l.com wrote:
      I've got a question on the differences and how to define static and
      class variables.
      First you have to define what you mean by "static".
      AFAIK, class methods are the ones which receives the
      class itself as an argument, while static methods are the one which
      runs statically with the defining class.
      `classmethod`\s receive the class as first arguments, `staticmethod`\ s are
      just functions bound to the class object.
      Hence, my understanding is that static variables must be bound to the
      class defining the variables and shared by children of parent class
      where the variable is defined. But, please have a look at this code in
      which a guy told me that the variable a is static:
      Ask the guy what he means by "static".
      >>>class Foo:
      a = 1
      @classmethod
      def increment(cls):
      cls.a += 1
      print cls.a
      >
      Here, I am defining variable a which, I believe is class variable,
      i.e., variable that is not bound to Foo itself.
      No you define a class attribute that *is* bound to the class `Foo`.
      Rather, a is bound to the class which is accessing the variable. The code
      that corroborates this idea is as follows:
      >
      >>>class Child1(Foo):
      pass
      >
      >>>Child1.incre ment()
      4
      Four!? Hard to believe.
      >>>class Child2(Foo):
      pass
      >
      >>>Child2.incre ment()
      4
      >
      This means that Child1 and Child2 does not share variable a which means
      that variable a is class variable rather than static variable.
      >
      Could you please comment on this? Is a static or class variable? What's
      the most recent way of defining 'class' and 'static' variables?
      There is no such thing as a "static" variable. Think of attributes that
      are bound to objects. All dynamically.

      What happens is: you bind a 1 to the attribute `Foo.a` in the `Foo` class
      definition.

      When you call `Child1.increme nt()` the class method will be called with
      `Child1` as first argument. Now ``cls.a += 1`` is executed which is
      somewhat like a short form of ``cls.a = cls.a + 1``. So this is reading
      the attribute `a` from `Child1` and then bind the result to `Child1`.
      `Child1` doesn't have an attribute `a`, so it is looked up in the parent
      class. But the result is then bound to `Child1`. So you are reading from
      `Foo` and writing to `Child1`. That's it.

      Ciao,
      Marc 'BlackJack' Rintsch

      Comment

      • Laszlo Nagy

        #4
        Re: Static variable vs Class variable

        Your question "is variable a
        static or class variable?" has no real answer. After running the
        increment() method on a descendant class, e.g. Child1 will rebind the
        name Child1.a, creating a new name in the namespace of the class. So the
        variable Foo.a is still there, but you are accessing Child1.a instead.
        >
        Please notice, that theoretically there is no way to "change the value"
        of Foo.a in any way, because this is a NAME that references to an
        IMMUTABLE OBJECT. It means that you can only rebind the variable. You
        cannot change its value, because when we are talking about its value, we
        mean the state of the referenced object. The object referenced by the
        name is an integer instance, namely it is "one". The object "one" always
        remains "one", this cannot be changed. You can add one to one, and you
        will get two, but that is another object.

        (I'm sorry, probably you already knew this.)

        Laszlo

        Comment

        • Matimus

          #5
          Re: Static variable vs Class variable

          On Oct 9, 9:16 am, "minkoo....@gma il.com" <minkoo....@gma il.com>
          wrote:
          Hi.
          >
          I've got a question on the differences and how to define static and
          class variables. AFAIK, class methods are the ones which receives the
          class itself as an argument, while static methods are the one which
          runs statically with the defining class.
          >
          Hence, my understanding is that static variables must be bound to the
          class defining the variables and shared by children of parent class
          where the variable is defined. But, please have a look at this code in
          which a guy told me that the variable a is static:
          >
          >class Foo:
          >
          a = 1
          @classmethod
          def increment(cls):
          cls.a += 1
          print cls.a
          >
          Here, I am defining variable a which, I believe is class variable,
          i.e., variable that is not bound to Foo itself. Rather, a is bound to
          the class which is accessing the variable. The code that corroborates
          this idea is as follows:
          >
          >class Child1(Foo):
          >
          pass
          >
          >Child1.increme nt()
          >
          4
          >
          >class Child2(Foo):
          >
          pass
          >
          >Child2.increme nt()
          >
          4
          >
          This means that Child1 and Child2 does not share variable a which
          means that variable a is class variable rather than static variable.
          >
          Could you please comment on this? Is a static or class variable?
          What's the most recent way of defining 'class' and 'static' variables?
          In Python `a' is considered a class variable. By modifying `a' using a
          class method though, you are essentially re-binding `a' to the class
          that it is called from. So, it will be shared by multiple instances of
          the same class, but not derivatives. The re-binding only occurs when
          `increment' is called. This makes for some very confusing behavior.
          I'm not aware of a way, in python, to explicitly specify a variable as
          static. For the behavior I think you are looking for you just need to
          modify it carefully. This can be done with a static, class or instance
          method. Though, using a class method is kind of silly. I'm sure some
          would argue that using an instance method is also silly.

          code:

          class C(object):
          a = 0
          def inc(self):
          C.a += 1 # directly modify the variable on the base class that it is
          attached to
          return C.a

          # or you could use a static method, which is fine since the instance
          isn't being used. This
          # will also allow the method to be called without instantiating the
          class.

          class C(object):
          a = 0
          @staticmethod
          def inc():
          C.a += 1
          return C.a

          Matt

          Comment

          • Diez B. Roggisch

            #6
            Re: Static variable vs Class variable

            In point #3, you really bind a name to a value. As you probably know, in
            Python, there are names and objects. The initial value of the name 'a'
            is 1. It is an immutable object. The "+=" operator usually increments a
            value of an object. However, because the 'int' type is immutable, the +=
            operator will rather rebind this variable to a newly created value. I
            believe this is what is happening here.
            Your believes aside, this is simply wrong. The statement

            a += x

            always leads to a rebinding of a to the result of the operation +. I
            presume you got confused by the somewhat arbitrary difference between

            __add__

            and


            __iadd__

            that somehow suggest there is an in-place-modification going on in case
            of mutables.

            but as the following snippet shows - that's not the case:


            class Foo(object):
            def __add__(self, o):
            return "__add__"

            def __iadd__(self, o):
            return "__iadd__"


            a = Foo()
            a += 1
            print a

            a = Foo()
            b = Foo()
            c = a + b
            print c

            So you see, the first += overrides a with the returned value of __iadd__.

            The reason for the difference though is most probably what you yourself
            expected: thus it's possible to alter a mutable in place.

            Diez

            Comment

            • Steven D'Aprano

              #7
              Re: Static variable vs Class variable

              On Tue, 09 Oct 2007 19:23:37 +0200, Diez B. Roggisch wrote:
              Your believes aside, this is simply wrong. The statement
              >
              a += x
              >
              always leads to a rebinding of a to the result of the operation +.
              Not true.
              >>L = []
              >>id(L)
              3083496716L
              >>L += [1]
              >>id(L)
              3083496716L

              It's the same L, not rebound at all.


              I presume you got confused by the somewhat arbitrary difference between
              >
              __add__
              >
              and
              >
              __iadd__
              >
              that somehow suggest there is an in-place-modification going on in case
              of mutables.
              The __iFOO__ methods are supposed to do in-place modification if
              possible, but it is up to the class writer to make them do so. In the
              case of your example, you specifically created an __iadd__ method that
              didn't even attempt in-place modification. What did you expect it to do?

              but as the following snippet shows - that's not the case:
              >
              >
              class Foo(object):
              def __add__(self, o):
              return "__add__"
              >
              def __iadd__(self, o):
              return "__iadd__"
              >
              >
              a = Foo()
              a += 1
              print a
              >
              a = Foo()
              b = Foo()
              c = a + b
              print c
              >
              So you see, the first += overrides a with the returned value of
              __iadd__.
              That's because you told it to do that. If you told it to do something
              more sensible, it would have done so. Lists know how to do in-place
              modification:
              >>id(L) # from above
              3083496716L
              >>L *= 5
              >>id(L)
              3083496716L
              >>L = L*5
              >>id(L)
              3083496972L


              --
              Steven.

              Comment

              • Laszlo Nagy

                #8
                Re: Static variable vs Class variable

                Steven D'Aprano wrote:
                On Tue, 09 Oct 2007 19:23:37 +0200, Diez B. Roggisch wrote:
                >
                >
                >Your believes aside, this is simply wrong. The statement
                >>
                >a += x
                >>
                >always leads to a rebinding of a to the result of the operation +.
                >>
                >
                Not true.
                >
                Hmm. Or you can write __iadd__ to rebind the name to the same object
                again? I think usually there is not much difference between "rebinding
                to the same object" and "not rebinding". But as we have seen, sometimes
                there is a difference. I think that Diez made his statement because it
                is possible to rebind from __iadd__ to a different object. So it is more
                safe to think that "inplace operations" will always rebind, than to
                think they will never rebind.

                I'm not sure about the language level. It is told that "+=" is an
                inplace operator, but how "in place" is defined? If we say "an inplace
                operator will change the state of an object, and will never create a new
                object" then "+=" is NOT an inplace operator. Well, at least not when
                you watch it from the language level. But what about the implementation
                level? Here is an example:

                a = 1
                a+= 1 # The compiler will probably optimize this and the Python bytecode
                interpreter will not rebind 'a' here, just increment the integer in memory.

                This topic starts to be very interesting. Language lawyers and
                developers, please help us! How "in place operator" is defined in
                Python? What makes it an "in place operator"? Is it the syntax, or what?

                Laszlo

                Comment

                • Marc 'BlackJack' Rintsch

                  #9
                  Re: Static variable vs Class variable

                  On Tue, 09 Oct 2007 18:08:34 +0000, Steven D'Aprano wrote:
                  >>>L = []
                  >>>id(L)
                  3083496716L
                  >>>L += [1]
                  >>>id(L)
                  3083496716L
                  >
                  It's the same L, not rebound at all.
                  It *is* rebound. To the same object, but it *is* assigned to `L` and not
                  just mutated in place.

                  In [107]: class A:
                  .....: a = list()
                  .....:

                  In [108]: class B(A):
                  .....: pass
                  .....:

                  In [109]: B.a += [42]

                  In [110]: A.a
                  Out[110]: [42]

                  In [111]: B.a
                  Out[111]: [42]

                  If it was just mutation then `B.a` would have triggered an `AttributeError `.

                  Ciao,
                  Marc 'BlackJack' Rintsch

                  Comment

                  • Diez B. Roggisch

                    #10
                    Re: Static variable vs Class variable

                    Steven D'Aprano schrieb:
                    On Tue, 09 Oct 2007 19:23:37 +0200, Diez B. Roggisch wrote:
                    >
                    >Your believes aside, this is simply wrong. The statement
                    >>
                    >a += x
                    >>
                    >always leads to a rebinding of a to the result of the operation +.
                    >
                    Not true.

                    Yes, it is.
                    >>>L = []
                    >>>id(L)
                    3083496716L
                    >>>L += [1]
                    >>>id(L)
                    3083496716L
                    >
                    It's the same L, not rebound at all.
                    Just because the __iadd__-operation in the list implemented chose to
                    returen a reference to itself - certainly a sensible choice, I never
                    doubted that - doesn't change the fact that python rebinds the name on
                    the left with whatever __iadd__ returned.

                    Diez

                    Comment

                    • Steven D'Aprano

                      #11
                      Re: Static variable vs Class variable

                      On Tue, 09 Oct 2007 19:46:35 +0000, Marc 'BlackJack' Rintsch wrote:
                      On Tue, 09 Oct 2007 18:08:34 +0000, Steven D'Aprano wrote:
                      >
                      >>>>L = []
                      >>>>id(L)
                      >3083496716L
                      >>>>L += [1]
                      >>>>id(L)
                      >3083496716L
                      >>
                      >It's the same L, not rebound at all.
                      >
                      It *is* rebound. To the same object, but it *is* assigned to `L` and
                      not just mutated in place.
                      Picky picky.

                      Yes, technically there is an assignment of L to itself. I was sloppy to
                      say "not rebound at all", because when you write an augmented assignment
                      method you have to return self if you want to implement in-place
                      mutation. But I hardly call "rebinding to itself" any sort of rebinding
                      worth the name :)

                      Diez is still wrong though, even though I overstated my case. See my
                      reply to his post.



                      [snip code]
                      If it was just mutation then `B.a` would have triggered an
                      `AttributeError `.
                      Why? Don't Python classes have inheritance?

                      (That's a rhetorical question. Yes they do, and no B.a would not raise
                      AttributeError because it would inherit from A.)


                      --
                      Steven.

                      Comment

                      • Steven D'Aprano

                        #12
                        Re: Static variable vs Class variable

                        On Tue, 09 Oct 2007 22:27:47 +0200, Diez B. Roggisch wrote:
                        Steven D'Aprano schrieb:
                        >On Tue, 09 Oct 2007 19:23:37 +0200, Diez B. Roggisch wrote:
                        >>
                        >>Your believes aside, this is simply wrong. The statement
                        >>>
                        >>a += x
                        >>>
                        >>always leads to a rebinding of a to the result of the operation +.
                        >>
                        >Not true.
                        >
                        >
                        Yes, it is.
                        I'm afraid not.

                        As I admitted in my reply to Marc, I overstated my case by saying that L
                        isn't rebound at all. Of course it is rebound, but to itself.

                        However, it is not true that += "always leads to a rebinding of a to the
                        result of the operation +". The + operator for lists creates a new list.
                        += for lists does an in-place modification:
                        >>L = []
                        >>M = L
                        >>L += [1]
                        >>M
                        [1]

                        Compare with:
                        >>L = []
                        >>M = L
                        >>L = L + [1]
                        >>M
                        []

                        You said:

                        "I presume you got confused by the somewhat arbitrary difference between
                        __add__ and __iadd__ that somehow suggest there is an in-place-
                        modification going on in case of mutables but as the following snippet
                        shows - that's not the case: ..."

                        That's an explicit denial that in-place modification takes place, and
                        that's *way* off the mark. I was concentrating so hard on showing in-
                        place modification that I glossed over the "return self" part.



                        --
                        Steven.

                        Comment

                        • Steven D'Aprano

                          #13
                          Re: Static variable vs Class variable

                          On Tue, 09 Oct 2007 21:25:38 +0200, Laszlo Nagy wrote:
                          a = 1
                          a+= 1 # The compiler will probably optimize this and the Python bytecode
                          interpreter will not rebind 'a' here, just increment the integer in
                          memory.
                          No. This is Python, not C. You can't increment integers in memory.
                          Integers are immutable objects, not raw bytes:
                          >>x = 1
                          >>id(x)
                          150830896
                          >>x += 1
                          >>id(x)
                          150830884




                          --
                          Steven.

                          Comment

                          • Marc 'BlackJack' Rintsch

                            #14
                            Re: Static variable vs Class variable

                            On Tue, 09 Oct 2007 22:43:16 +0000, Steven D'Aprano wrote:
                            On Tue, 09 Oct 2007 19:46:35 +0000, Marc 'BlackJack' Rintsch wrote:
                            >
                            >On Tue, 09 Oct 2007 18:08:34 +0000, Steven D'Aprano wrote:
                            >>
                            >>>>>L = []
                            >>>>>id(L)
                            >>3083496716L
                            >>>>>L += [1]
                            >>>>>id(L)
                            >>3083496716L
                            >>>
                            >>It's the same L, not rebound at all.
                            >>
                            >It *is* rebound. To the same object, but it *is* assigned to `L` and
                            >not just mutated in place.
                            >
                            Picky picky.
                            >
                            Yes, technically there is an assignment of L to itself. I was sloppy to
                            say "not rebound at all", because when you write an augmented assignment
                            method you have to return self if you want to implement in-place
                            mutation. But I hardly call "rebinding to itself" any sort of rebinding
                            worth the name :)
                            Maybe picky but that detail was the source of the OPs confusion because it
                            introduced a new attribute on the subclass.

                            Ciao,
                            Marc 'BlackJack' Rintsch

                            Comment

                            • Bruno Desthuilliers

                              #15
                              Re: Static variable vs Class variable

                              minkoo.seo@gmai l.com a écrit :
                              Hi.
                              >
                              I've got a question on the differences and how to define static and
                              class variables.
                              What's a "static" variable ? A variable that doesn't move ?-)
                              Hence, my understanding is that static variables must be bound to the
                              class defining the variables
                              You mean "class attributes". Thinking in terms of another language won't
                              help understanding Python's objec model.
                              and shared by children of parent class
                              where the variable is defined. But, please have a look at this code in
                              which a guy told me that the variable a is static:
                              Then don't listen what this guy says.
                              >>>>class Foo:
                              >
                              a = 1
                              @classmethod
                              def increment(cls):
                              cls.a += 1
                              print cls.a
                              >
                              Here, I am defining variable a which, I believe is class variable,
                              a class attribute
                              i.e., variable that is not bound to Foo itself.
                              Yes it is. It's an attribute of the class object Foo.
                              Rather, a is bound to
                              the class which is accessing the variable.
                              False.
                              >>dir(Foo)
                              ['__doc__', '__module__', 'a', 'increment']
                              >>Foo.__dict_ _
                              {'a': 1, '__module__': '__main__', '__doc__': None, 'increment':
                              <classmethod object at 0x402d141c>}
                              The code that corroborates
                              this idea is as follows:
                              >
                              >>>>class Child1(Foo):
                              pass
                              >
                              >>>>Child1.incr ement()
                              4
                              ???
                              >
                              >>>>class Child2(Foo):
                              pass
                              >
                              >>>>Child2.incr ement()
                              4
                              I don't have the same result here. But anyway: the increment method is
                              rebinding 'a', so the first time it's called on a child class, it
                              creates an attribute 'a' for this class. Just change your code this way
                              and you'll see what happens:

                              def increment(cls):
                              print dir(cls)
                              cls.a += 1
                              print dir(cls)


                              FWIW, if you don't get this, then you may encounter another common gotcha:

                              class Truc:
                              a = 1
                              def gotcha(self):
                              self.a += 1
                              print self.a

                              print Truc.a
                              t = Truc()
                              print t.a
                              t.gotcha()
                              print Truc.a
                              t2 = Truc()
                              print t2.a
                              t2.gotcha()
                              print Truc.a
                              t.gotcha()
                              print t.a
                              print t2.a
                              print Truc.a

                              Enjoy !-)

                              Now back to your snippet : if you don't want this behaviour, wrap 'a'
                              into a mutable container:

                              class Foo:
                              a = [1]

                              @classmethod
                              def increment(cls):
                              cls.a[0] += 1
                              print cls.a[0]


                              class Child(Foo):
                              pass

                              And if you want to hide that, use properties (warning: you need nex
                              style classes here):

                              class Foo(object):
                              _a = [1]

                              @classmethod
                              def increment(cls):
                              cls._a[0] += 1
                              print cls._a[0]

                              @apply
                              def a():
                              def fget(self):
                              return type(self)._a[0]
                              def fset(self, val):
                              type(self)._a[0] = val
                              return property(**loca ls())

                              class Child(Foo):
                              pass
                              This means that Child1 and Child2 does not share variable a which
                              means that variable a is class variable rather than static variable.
                              Nope. This only means that you don't understand the (somewhat peculiar)
                              semantics of bindings, immutable objects and attribute lookup rules in
                              Python.
                              Could you please comment on this? Is a static or class variable?
                              It's a class attribute.
                              What's the most recent way of defining 'class' and 'static' variables?
                              No 'static variable' in Python. And what you call a 'class variable' is
                              nothing else than an ordinary of the class object

                              Comment

                              Working...