Reputation: 912
Say I have a (normal bound) method in my class that has to access class variables (like a counter in __init__
). If I want to modify class varaibles, I see three possibilities:
type(self)
or self.__class__
(after reading this, I chose type
over __class__
, as I'm using Python 3 so "old-style" classes don't apply)@classmethod
specifically for changing class variables. This is the most complicated, but also the most clear (IMO) approach.The three methods would be written like this:
class MyClass:
counter = 0
def f1(self):
type(self).counter += 1
def f2(self):
MyClass.counter += 1
def f3(self):
self._count()
@classmethod
def _count(cls):
cls.counter += 1
Is there a clear "best" option and which one is it or are they all more or less equivalent and it's just "what I like most"? Does inheritance change anything?
Upvotes: 2
Views: 250
Reputation: 39758
If you derive classes from the one defining your variable (and presumably the method assigning to it), using type(self)
stores (the new value of) the attribute on the object’s actual class. That can be quite useful, but in your example is surely wrong.
Using a class method is just the same, except that the subclass could override the method: this might make the complex case work, but does nothing to fix the simple inheritance case.
Using the name of the class is the simple, idiomatic answer and avoids any confusion from subclasses. In the absence of concern over rebinding that name, this should be the default even without any inheritance. If that is a concern, you can stash the class object in a couple of different ways:
class A:
counter=0
# use the magic behind super():
def _count1(): __class__.counter+=1
# inject the class object:
@staticmethod
def _count2(cls): cls.counter+=1
A._count2.__defaults__=A,
# inject via a closure:
def capture(cls):
def _count(): cls.counter+=1
return _count
A._count3=staticmethod(capture(A))
The __class__
trick can of course be used directly, without a wrapper method, but it’s a bit ugly; internally, it’s very similar to the last approach with capture
. One thing that doesn’t work is trying to make a function that refers to the class’s dictionary, since those are protected for optimization reasons.
Upvotes: 2