In my endeavours as a python-apprentice i got recently stuck at some odd (from my point of view) behaviour if i tried to work with class attributes. I'm not complaining, but would appreciate some helpful comments to shed some light on this issue.
To reduce a complex matter into a more concise question i would formulate it like this:
What is the "pythonic" way to ensure that a class-attribute behaves more like a static variable in an inheritance tree?
It seems to me like a class-attribute behaves like a "copy on read" default value with polymorphic characteristics. As long as i do "read-only" operations it stays a "singleton", but as soon, as i access the class-attribute with an assignment through the derived class or instance it gets morphed into a new reference loosing the relation to the inherited base-reference.
(It has sure potential for some interessting features, but you have to understand it to embrace it, so some insight is highly appreciated.)
class A(object):
classvar = 'A'
def setclassvar(self, value):
A.classvar = value
def __str__(self):
return "%s id(%s) " %(A.classvar, hex(id(A.classvar))[2:-1].upper())
class A1(A):
pass
class B(object):
classvar = 'B'
def setclassvar(self, value):
self.__class__.classvar = value
def __str__(self):
cvar = self.__class__.classvar
return "%s id(%s) " %(cvar, hex(id(cvar))[2:-1].upper())
class B1(B):
def setclassvar(self, value):
self.__class__.classvar = value
a, a1 = A(), A1()
a1.setclassvar('a')
print "new instance A: %s" %a
print "new instance A1: %s" %a
b, b1 = B(), B1()
b1.setclassvar('bb')
print "new instance B: %s" %b
print "new instance B1: %s" %b1
a1.setclassvar('aa')
print "new value a1: %s" %a
print "new value a: %s" %a
a1.classvar = 'aaa'
print "direct access a1: %s id(%s)" %(a1.classvar, hex(id(a1.classvar))[2:-1].upper())
print "method access a1: %s" %a1
print "direct access a: %s" %a
produces the following:
new instance A: a id(B73468A0) new instance A1: a id(B73468A0) new instance B: B id(B73551C0) new instance B1: bb id(AD1BFC) new value a1: aa id(AD1BE6) new value a: aa id(AD1BE6) direct access a1: aaa id(A3A494) method access a1: aa id(AD1BE6) direct access a: aa id(AD1BE6)
So either the direct (assigning) access object.classvar
or mediated through self.__class__.classvar
are not the same as BASECLASS.classvar
.
Is this a scope issue or somethin totaly different.
Looking forward to your answers and thanks in forward. :-)
Edit: There was an answer for a very short time suggesting the use of class-descriptors like: How to make a class property?.
Unfortunatly that doesn't seem to work:
class Hotel(Bar):
def __init__(self):
Hotel.bar += 1
hotel = Hotel()
assert hotel.bar == 51
assert hotel.bar == foo.bar
The 2nd assertion fails! hotel.bar doesn't reference the same object as foo.bar
and hotel.bar
references somethin other then Hotel.bar!
2nd Edit: I'm quite aware that singletons are considered an "antipattern" and i didn't intend to use them (extensivly). Therefore i didn't mention them in the question-titel. Even so there are many solutions discussing and providing solutions with and about singletons, my question stays: Why can a class-variable detach it's reference so easily? Ruby behaves more the way it feels natural to me: http://snippets.dzone.com/posts/show/6649
It's good when you want to establish a subtype from an existing object. Objects are defined by classes, classes can inherit attributes and behavior from pre-existing classes. The resulting classes are known as derived classes or subclasses. A subclass “inherits” all the attributes (methods, etc) of the parent class.
Polymorphism and Inheritance Like in other programming languages, the child classes in Python also inherit methods and attributes from the parent class. We can redefine certain methods and attributes specifically to fit the child class, which is known as Method Overriding.
while you can access class attributes using an instance it's not safe to do so. In python, the instance of a class is referred to by the keyword self. Using this keyword you can access not only all instance attributes but also the class attributes.
Use dot notation or setattr() function to set the value of a class attribute. Python is a dynamic language. Therefore, you can assign a class variable to a class at runtime. Python stores class variables in the __dict__ attribute.
a1.classvar = 'aaa'
This is not a "reference" to a class variable.
That is a new instance variable in the object 'a1'.
An expression like A.classvar
is the class variable. The class object (and it's superclasses) all have a class level dictionary (A.__dict__
) with class-level objects defined in it. Name resolution works by checking the class, then all the super-classes in Method Resolution Order (MRO).
An expression like a.classvar
is resolved by a search through the object's namespace. When this is a "reading" reference, the object and the class (and the superclasses) are searched.
When this appears on the left side of assignment, the instance variable ("classvar") is simply created on the referenced object ("a"). No searching through parent namespaces to resolve a name, since there's nothing to resolve. It's being created.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With