Question: I have tried everything and my code seems to be very close but i keep getting a name error when i have defined the variable. 

```
from math import *

class Spheres:
    def __init__(self, radius):
        self.radius = r
        self.area = 0
        self.volume = 0

    def getRadius(self):
        return self.radius

    def surfaceArea(self):
        self.area = 4 * 3.14 * (r*r)
        return (self.area)

    def getVolume(self):
        self.volume = (4/3) * 3.14 * (r * r * r)
        return (self.volume)

def main():
    r = input("Enter the radius of the sphere: ")
    s = Spheres(r)
    print("The volume of the sphere is: ", s.surfaceArea())
    print("The surface area of the sphere is: ", s.volume())

if __name__ == '__main__':
    main()

```

The error message I get is:

```
Traceback (most recent call last): 
  File "/local/files/jfult001/CSC221/lab10/9ball.py", line 30, in <module> main() 
  File "/local/files/jfult001/CSC221/lab10/9ball.py", line 26, in main print("The volume of the sphere is: ", s.surfaceArea()) 
  File "/local/files/jfult001/CSC221/lab10/9ball.py", line 15, in surfaceArea self.area = 4 * 3.14 * (r*r) 
NameError: global name 'r' is not defined 

```

Answer: 
Let me tell you about *scopes*:

In Python, variables are *scoped*, or limited, to the code that they are defined in. Take the below code for example:

```
def my_function():
    r = 1234

print r

```

This will give you a `NameError`, because `r` is *local* to `my_function()` and doesn't exist outside of `my_function()`.

Similarly:

```
class MyClass(object):

    def __init__(self, r):
        self.radius = r

    def access_r(self):
        return r

m = MyClass(1234)
m.access_r()

```

This code will also give you a `NameError` because `r` is only defined in the scope of `__init__()`. 

Notice, however that in the above example, you have `self.radius = r`. It just so happens that `self` is accessible in *both* functions. The value of `r` is stored in `self.radius` for the express purpose of accessing it from within other functions inside the same class. Take the following modification, for example:

```
class MyClass(object):

    def __init__(self, r):
        self.radius = r

    def access_r(self):
        return self.radius

m = MyClass(1234)
print m.access_r()

```

This code will run smoothly *and* return `1234`, the value of `r`.
It looks like 'r' is input as a string.

I would write r=float(input("Enter radius:"))