I've recently been experimenting with the use of class methods to get a better understanding of object-oriented programming. As part of a sample program I've got a short class called circle
, which can be used to create different circle
instances.
class circle():
def __init__(self):
self.radius = 10
self.color = 'blue'
def change_color(self, color):
self.color = color
@classmethod
def red_circle(cls):
circle.radius = 10
circle.color = 'red'
return cls
I've added in the class method red_circle
so that I can have a different default setting for circle
instances. The problem I have is that when I use the red_circle
method, the instance created is placed inside of mappingproxy()
? For example:
circle_one = circle()
circle_one.__dict__
Gives the output:
{'radius': 10, 'color': 'blue'}
But using
circle_two = circle.red_circle()
circle_two.__dict__
Gives:
mappingproxy({'__dict__': <attribute '__dict__' of 'circle' objects>,
'__doc__': None,
'__init__': <function __main__.circle.__init__>,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'circle' objects>,
'change_color': <function __main__.circle.change_color>,
'color': 'orange',
'radius': 10,
'red_circle': <classmethod at 0x7f0e94ab1a10>})
Is there a way that I can manipulate circle_two
so that it appears the same as the circle_one
instance? It's not causing any problems right now, but it would be good to understand what's going on with the mappingproxy()
.
The trouble with your existing code is that your red_circle
method, as it stands, is attempting to alter attributes of the circle
class rather than attributes of any one instance of the circle
class.
You can fix this by rewriting it like so:
class Circle:
def __init__(self):
self.radius = 10
self.color = 'blue'
def change_color(self, color):
self.color = color
@classmethod
def red_circle(cls):
new_circle = cls()
new_circle.change_color('red')
return new_circle
A few points to note here:
circle
class to Circle
. It's a strong convention in python code to capitalise names of classes, and you're likely to confuse other programmers if you don't do that.self
), a class method will always take the class itself as its first parameter (and there's a strong convention to always call that parameter cls
).mappingproxy
objects
mappingproxy
objects are (to simplify a little here) immutable dictionaries. While ordinary dictionaries are used for instance dictionaries, mappingproxy
objects are used for class dictionaries. There's a good explanation of why a different kind of dictionary is used for the class dict here: Why is a class __dict__ a mappingproxy?.
Class dicts vs instance dicts
In your circle
class, the radius
and color
attributes are instance attributes. Each instance of circle
has its own version of them, and keeps those versions in its own personalised instance dictionary. However, the methods in your circle
class — __init__
, change_color
and red_circle
— are class attributes. These methods are kept in the class dictionary — the mappingproxy
object you came across. All instances of circle
have access to the same class dictionary, and this is how they access these methods.
You can find a good introductory tutorial on the different kinds of python methods here.