What are the differences between instance variables and class variables, or why do I need to use `self.pi`?

class test:
  def init(self,name):
    self.name = name
  def func(self):
    return self.name

foo = test('trial_name')
print (foo.func())    # trial_name

Can you explain this again?
How are we able to get self.radius?
It is because we have diameter as an argument in method?
Or we just can create any instance variable with the value we define.

radius would be a computed value if the parameter is diameter. I would write a separate method since we want the radius to reflect the currrent diameter, and we may want our class to allow that to be changeable.

def  get_radius(self):
    return self.diameter / 2

I’ll need to be apprised of the exercise, so please post a link and we can look at this a little further.

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

Ah, so the instructions stipulate writing the radius as a part of the initialization. This will be okay if the circle instance is to be static, and unchangeable.

Note that the instance has no diameter attribute, only a radius computed from the parameter.

1 Like

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?

Two questions if I may:

  1. Why do we write self.radius and self.pi the same when we are creating the circumference method? pi is a class parameter and self.radius is an instance variable, no?

  2. Why can’t def circumference(self): be at the same indentation as the self.radius code?

TIA!

to access class variables, instance variables and methods within a method you need self.

class variable and methods are automatically added to self

Why would you want to do that? You want to add the method to the class, not the constructor

1 Like

It simply depends upon how you want to construct the class, and what you want each object to do. In real life, i.e., when not following a lesson plan, you can do it almost any way that you want.

In this particular design,
self.radius sets an attribute of the particular Circle object.
circumference() is a method of the Circle object.

Since the circumference (and area) of a given circle are fixed, self.circumference and self.area could indeed be included in the constructor to establish those values as object attributes. However, presumably in order to easily illustrate attributes and methods, the course author chose not to do it that way.

4 Likes

I’m having some issues with classes but as i go over it more it gets more understandable. I think just a bit more practice than other topics is fine.

its not as complex as you think but at the start it is a bit dodgy

3 Likes

To reiterate, there is a case for using self on all variables, whether class or instance.

Consider,

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

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

>>> this = Circle(10)
Creating circle with diameter 10
>>> this.circumference()
31.400000000000002
>>> that = Circle(100)
Creating circle with diameter 100
>>> that.circumference()
314.0
>>> this.circumference()
314.0
>>> this.radius
50.0
>>> 

Notice that this is no longer what it was initialized as? That is because the class variable radius has been overwritten with the new computed that value.

Now let’s see it when we use self

>>> 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):
    return self.radius * self.pi * 2

>>> this = Circle(10)
Creating circle with diameter 10
>>> that = Circle(100)
Creating circle with diameter 100
>>> this.circumference()
31.400000000000002
>>> that.circumference()
314.0
>>> this.radius
5.0
>>> that.radius
50.0
>>> 

Each instance is unique to the point that even the value for pi can be set in each.

6 Likes

Thanks @mtf. your explanations are extremely helpful!

1 Like

You raise an interesting questions

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  #<-----------------------

when you use name of class => Circle instead on name of instance when you create object from Class you are changing Class variable based on your last instance creation of class and value of radius will depend on value of your last instance you created .
let say you created instance with and pass arguments to init method as 12 now Circle.radius has value of 6 and since every instance have access to all variables of mother class it inherit varibales of Class . what you do by doing Cricle.radius = “value” is saying == > I change object factory (which is class) 's radius variable every time I create instance of it .

you could take a look at an expm :

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  

  
circle_one = Circle(12) # here I changed Class variable Circle to be value of 6
print(circle_one.radius) # since instance of Class inherit all variables form Class this will print 6

circle_two = Circle(16)  # now I change class variable radius to be 8
print(circle_two.radius) # this will print 8
print(circle_one.radius) # this will also will print 8 , (return the value was 6 before creation of last instance 

can we create object without creating Class ? like what we do in JS ? In JS the reason behind idea of classes was create a blueprint to save us time from re-creating common methods and variables for certain entity like animals(as class) and cat or dog 's are objects inherit all methods and variables of animals(class).
I did search google and could not find an answer.

In Python, everything is an object. Only thing is they can only inherit from their parent class.

str

cannot inherit from,

list

which cannot inherit from,

dict

and so on. It’s up to us to extend the parent class to give our custom objects additional methods that it might need for our purposes.

Just as we can define a literal in JS,

obj = {
    key: 'value'
}

we can define a literal in Python,

obj = {
    'key': 'value'
}

which will create an instance of the dict class.

could we say classes in python are more extended then classes in JS ?
And class definition and class instance(object) in JS is only part of what python offers us which is dict class and dict object ?
And class definition in whole JS is like a small part of what classes are in python and it is Dict class and dict object.

and that’s why we could bypass creating of class and directly create class instance in Js which is instance of object class and if yes how we could create instance of class before creating class … in JS

sorry for asking this questions .

When it comes down to it there is nothing special about classes other than that they define a type of object.

>>> type({})
<class 'dict'>
>>> isinstance({}, dict)
True
>>> 

We can even make a class from a class…

>>> class Array(list):
    def __repr__(self):
        return str(type(self))
    def get(self, x):
        return self[x]         #  error prone

	
>>> arr = Array()
>>> print (arr)
<class '__main__.Array'>
>>> isinstance(arr, list)
True
>>> arr.extend([1,2,3,4,5])    #  Recognize this list method?
>>> arr.get(2)
3
>>> 

Or with a slight twist…

>>> class Array(list):
    def __repr__(self):
        return str(type(self))
    def get(self):
        return [*self]         #  less error prone

	
>>> arr = Array()
>>> print (arr)
<class '__main__.Array'>
>>> isinstance(arr, list)
True
>>> arr.get()
[]
>>> arr.extend([1,2,3,4,5])
>>> arr.get()
[1, 2, 3, 4, 5]
>>> 

Really no magic. Our class is an extension of the List class.

>>> other = Array()
>>> other.extend([6,7,8,9,10])
>>> arr.get()
[1, 2, 3, 4, 5]
>>> other.get()
[6, 7, 8, 9, 10]
>>> other.get()[2:]
[8, 9, 10]
>>> 

What’s neat here is that our object is not subscriptable. It can only be polled with its .get() method, which returns a normal list.

However, as we’ve already seen, we can still use list methods on the object.

>>> other.remove(8)
>>> other.get()
[6, 7, 9, 10]
>>> other.insert(2, 8)
>>> other.get()
[6, 7, 8, 9, 10]
>>> arr.extend(other.get())
>>> arr.get()
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> 
1 Like

The two languages are in a completely different environment even while it looks as though they do things the same way. Truth is, they don’t.

All we can compare is constructs and algorithms. We can emulate between languages by getting one language to do the same thing with the same inputs as the other. The best we can then determine is which language made it easier because of intuitive underpinning and/or human readability.

1 Like

2 posts were split to a new topic: Circle.radius ie a class variable