# FAQ: Learn Python: Classes - Self

This community-built FAQ covers the “Self” exercise from the lesson “Learn Python: Classes”.

Paths and Courses
This exercise can be found in the following Codecademy content:

## Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply ( ) below!

Agree with a comment or answer? Like ( ) to up-vote the contribution!

Need broader help or resources? Head here.

Looking for motivation to keep learning? Join our wider discussions.

Learn more about how to use this guide.

Found a bug? Report it!

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

I’m getting an error on submit step 2 asking if the printed result is (diameter / 2)…

``````class Circle:
pi = 3.14
def __init__(self, diameter):
print("Creating circle with diameter {d}".format(d=diameter))
# Add assignment for self.radius here:
self.radius = diameter / 2
``````

But that only works when the instance method is above the print stament and referenced in the format statement.

``````class Circle:
pi = 3.14
def __init__(self, diameter):
self.radius = diameter / 2
print("Creating circle with diameter {d}".format(d=self.radius))
# Add assignment for self.radius here:
``````

What I’m a missing here?

1 Like

This section was really difficult! I think it’s gonna take some time for me to really understand OOP. Can anyone point me to any good books or somewhere to practice this?

I have a question about this assignment. I’m really struggling with it.

``````class Circle:
pi = 3.14
def __init__(self, diameter):
print("Creating circle with diameter {d}".format(d=diameter))
self.radius = diameter / 2
def circumference(self):
circumference = 2 * self.pi * self.radius
return circumference
``````

I get that self.pi refers to the variable pi in the Class. Why is there a self.radius, but there is no variable for it? It looks like the method circumference(self) is calling it even though it was defined in init (self, diameter). Is it because init is a special constructor?

In Python, it is an instance attribute constructor only, since the object exists the moment it is instantiated. Try removing the method and see if it prevents us from creating a new instance.

I can save you the trouble and tell you, no; it won’t have any bearing. A new instance can be created. It just won’t have any instance variables, only the methods and class variables it inherited.

One thing to note is that there is no record of `diameter` apart from its transient role in the instance intialization. Once that method has run its course, it no longer exists.

The variable that is preserved is `radius`, and every instance has the value set for this that was computed from the diameter when the instance was created. Because we are working with a singular code base serving multiple instances, we need to know which instance is accessing this code.

``````instance = Circle(10)
``````

The instance can access the `circumference` method with no arguments, since `self` creates a binding to it and is able to access its `radius` attribute, `5`.

``instance.circumference()    # 31.4``

Hi,

Is the ‘radius’ of your ‘Circle’ objects half the passed in ‘diameter’ ?

yes :)! And still I can’t get past step 2. What am I doing wrong?

``````class Circle:
pi = 3.14

def __init__(self, diameter):
print("Creating circle with diameter {d}".format(d=diameter))
# Add assignment for self.radius here:
self.radius = diameter / 2
print(self.radius)

medium_pizza = Circle(12)
teaching_table = Circle(36)
round_room = Circle(11.46)
``````

output:

``````Creating circle with diameter 12
6.0
Creating circle with diameter 36
18.0
Creating circle with diameter 11.46
5.73
``````

What am I missing? Thanks in advance.

Regards,
Andreas

sadly your workaround doesn’t work for me :(.

I am having trouble understanding why in:

def circumference(self):
return 2 * self.pi * self.radius

We use self.pi instead of just pi. I understand why we use self.radius because we have defined it above but not pi.

pi is a class variable:

``````class Circle:
pi = 3.14 # class variable

``````

class variables are automatically added to self.

if you intent to use `pi`, how is that defined within the scope of circumference method?

Why here need a () when I wrote print(medium_pizza.circumference())?
And since def init return none, why when I test print(medium_pizza.radius), it did return radius value? and why in there I don’t need a () after radius?

``````class Circle:
pi = 3.14
def __init__(self, diameter):
print("Creating circle with diameter {d}".format(d=diameter))
# Add assignment for self.radius here:
self.radius = diameter / 2
def circumference(self):
self.circumference= 2 * self.pi * self.radius
return self.circumference

medium_pizza = Circle(12)
teaching_table = Circle(36)
round_room = Circle(11460)
print(medium_pizza.circumference())
print(teaching_table.circumference())
print(round_room.circumference())
print(medium_pizza.radius())
``````

calling functions and methods require parentheses

init is a magic method, its automatically called when you create a new instance of a class. Within the init method, you can then declare the instance variable(s)

radius is instance variable, accessing variable, instance variable and class variables doesn’t require parentheses.

I think it may be that you are using 11.46 instead of 11460 for the “round_table”

Also, you have “print(self.radius)” and it should be a “return” returns the formula for the circumference .

Hey, if you (like me) are having trouble with “classes” and “self” I found these videos to be very helpful.

Youtube channel - CS Dojo:

Youtube channel - Corey Schafer

2 Likes

I wonder why it is written this way:

``````class Circle:
pi = 3.14
def __init__(self, diameter):
print("Creating circle with diameter {d}".format(d=diameter))
# Add assignment for self.radius here:
self.radius = diameter / 2

def circumference(self):
return self.radius * Circle.pi * 2
``````

Instead of this way?:

``````class Circle:
pi = 3.14
radius = 0  #<----------------
def __init__(self, diameter):
print("Creating circle with diameter {d}".format(d=diameter))
# Add assignment for self.radius here:
self.radius = diameter / 2

def circumference(self):
return self.radius * Circle.pi * 2
``````

I think maybe @aorchowski was asking the same thing. It seems to me that there is a variable scope issue in the former. Right?

Or will there be an inheritance issue with placing “radius = 0” as a Class level attribute?

Will it create two attributes, one for self and one for the “Circle” class?

There won’t be a scope related issue and setting `radius` as a class variable has no effect since the instance variable overrides that.

No, just the one will exist, the instance variable. Instances all inherit the same class variables but any one instance can assign a new value to the variable since it is accessed the same way.

``````instance.radius = new_radius
``````

Now that instance has its own unique value for the radius, making it essentially an instance variable.

I see. That makes sense.

What if “Circle.radius” is used? Will it now be a class level attribute and be inherited by instances ?

``````class Circle:
pi = 3.14
radius = 0
def __init__(self, diameter):
print("Creating circle with diameter {d}".format(d=diameter))
# Add assignment for self.radius here:
Circle.radius = diameter / 2  #<-----------------------

def circumference(self):
return Circle.radius * Circle.pi * 2  #<-----------------------
``````

It seems to me that constants pi and radius (when expressed as half the diameter) should be class level attributes

That would be non-standard. It should be an instance variable with `self`.

Interesting. In this video the instructor talks about both instance variables and class variables and why you would use them. Maybe I’m confusing the use case.

When do you create a new method and when do you put it in the `__init__`? I understand that if it’s a long method it’s better but when you can return it in a single function is there any reason why we would make more methods? I think this looks a lot cleaner:

``````
class Diameter():
pi = 3.14159
def __init__(self, diameter):
self.radius = diameter/2
self.area = Diameter.pi * self.radius ** 2
self.circumference = Diameter.pi * self.radius * 2

pizza = Diameter(12)

print(f"Pizza radius: {pizza.radius}")
print(f"Pizza area: {pizza.area}")
print(f"Pizza circumference: {pizza.circumference}")
``````

`__init__()` is called when you instantiate a class:

``````Diameter() # create class instance which will trigger the init method
``````

separation of concerns, easier to test.

also, what if you change the diameter:

``````class Diameter():
pi = 3.14159
def __init__(self, diameter):
self.radius = diameter/2
self.area = Diameter.pi * self.radius ** 2
self.circumference = Diameter.pi * self.radius * 2

pizza = Diameter(12)

print(f"Pizza radius: {pizza.radius}")
print(f"Pizza area: {pizza.area}")
print(f"Pizza circumference: {pizza.circumference}")

pizza.radius = 500

print(f"Pizza radius: {pizza.radius}")
print(f"Pizza area: {pizza.area}")
print(f"Pizza circumference: {pizza.circumference}")
``````

then you have a bug. instance properties can change, thus you can’t rely on the fact that you can instantiate a class once and that everything will stay the same, so you can’t push everything in the init method

1 Like

Thank you, you made it very clear!