Name Error: Global name 'r' is not defined - python

Ive been working on this sample code for a while and cant seem to wrap my head around this seemingly simple error.
The code is as follows:
class area :
r=5
l=2
b=3
def __init__(self,r,l,b):
print "parent constructor"
self.r=r
self.l=l
self.b=b
def __del__(self):
print "parent deconstructor"
def circle(self):
circle_area= 3.14 * r * r
print "area of circle is :",circle_area
def rectangle(self):
rect_area=l*b
print "area of rectangle :",rect_area
obj=area(4,5,4)
obj2=area(2,5,4)
obj.circle()
The error message says :
File "yaa.py", line 18, in circle
circle_area= 3.14 * r * r
NameError: global name 'r' is not defined.

You need to use the self for refering class attributes:
def circle(self):
circle_area= 3.14 * self.r * self.r
print "area of circle is :",circle_area
In case you want to use the r within the class, not the instance you have to use the name of the class then:
def circle(self):
circle_area= 3.14 * area.r * area.r
print "area of circle is :",circle_area

You probably need to change your method circle(self) from
circle_area= 3.14 * r * r
to
circle_area= 3.14 * self.r * self.r
because r is an attribute of the class, not a global variable.
The same goes for your method rectangle(self):
rect_area = self.l * self.b

Related

AttributeError in python unit-test circle

I have to make unit-test for circle in python, but for the life of me cant figure out why I am getting this error :
Traceback (most recent call last):
File "c:\Users\User\Desktop\Domaci\Preadvanje 8\circle_unittest.py", line 6, in test_area
self.assertEqual(circle.area (2),12.564)
File "c:\Users\User\Desktop\Domaci\Preadvanje 8\class_circle.py", line 5, in area
return (self.radius * self.radius) * 3.141
AttributeError: 'int' object has no attribute 'radius'
Code for circle :
class circle:
def __init__(self,radius):
self.radius = radius
def area(self):
return (self.radius * self.radius) * 3.141
def perimeter(self):
return (2 * self.radius) * 3.141
r = int(input("Input r: "))
newcircle = circle(r)
print ("Area of the circle is: ", newcircle.area())
print("Perimeter of the circle is: ", newcircle.perimeter())
Code for test:
import unittest
from unittest.case import TestCase
from class_circle import circle
class test_circle(unittest.TestCase):
def test_area(self):
self.assertEqual(circle.area (2),12.564)
def test_perimeter(self):
self.assertEqual(circle.perimeter(2), 12.564)
if __name__ == '__main__':
unittest.main()
You are using the method "area" directly without instantiating a new object.
class test_circle(unittest.TestCase):
def test_area(self):
c = circle(2)
self.assertEqual(c.area (2),12.564)
def test_perimeter(self):
c = circle(2)
self.assertEqual(c.perimeter(2), 12.564)
In the above code, we create a circle called "c" first, and then test the method area on it, which fixes the issue.

Hard time understanding the concept of return and multiple returns in python

def calc_circle_area(circle_diameter):
pi_val = 3.14159265
circle_radius = circle_diameter / 2.0
circle_area = pi_val * circle_radius * circle_radius
return circle_area
def pizza_calories(pizza_diameter):
calories_per_square_inch = 16.7
total_calories = calc_circle_area(pizza_diameter) * calories_per_square_inch
return total_calories
print('12 inch pizza has %.2f calories.'% pizza_calories(12.0))
print('14 inch pizza has %.2f calories.'% pizza_calories(14.0))
So with this, I am confused of how the order of "returning" works ...
help? :(
There is no "order" to returning in the sense I believe you may be thinking of. Each function is a separate piece of code, to which I think your notion of "order" does not apply. For example, if you run a Python script simply containing:
def calc_circle_area(circle_diameter):
pi_val = 3.14159265
circle_radius = circle_diameter / 2.0
circle_area = pi_val * circle_radius * circle_radius
return circle_area
The Python script will make a function called calc_circle_area, but it does not execute the function. The function is only executed when the function is called. So similarly, if I execute the following:
def func_a():
return 'Function A'
def func_b():
return 'Function B'
both functions are defined, but are not called. All that Python cares about is whether the function is defined before it is called. So:
def func_a():
return 'Function A'
def func_b():
return 'Function B'
print(func_a)
print(func_b)
gives exactly the same output as:
def func_b():
return 'Function B'
def func_a():
return 'Function A'
print(func_a)
print(func_b)
The order of definition does not matter here. So here, your code does the following:
define calc_circle_area
define pizza_calories
call pizza_calories, and use the returned value in a print statement
call pizza_calories, and use the returned value in a print statement
When pizza_calories is called, it uses the function calc_circle_size to produce total_calories. So, it calls calc_circle_size, and uses the return value to produce total_calories. If it's easier, you can think of the following equivalent code:
def pizza_calories(pizza_diameter):
calories_per_square_inch = 16.7
###
# Here, I am using the same code as is used in calc_circle_area,
# but with consistent variable names as is used in pizza_calories.
pi_val = 3.14159265
circle_radius = pizza_diameter / 2.0
calc_circle_area_value = pi_val * circle_radius * circle_radius
###
total_calories = calc_circle_area_value * calories_per_square_inch
return total_calories
print('12 inch pizza has %.2f calories.'% pizza_calories(12.0))
print('14 inch pizza has %.2f calories.'% pizza_calories(14.0))
I hope that makes more sense.

Sharing a piece of code with methods inside a class in Python

I started making a draft for one of the classes that are supposed to be used in my programm and I first wrote this piece of code:
import math
import numpy as np
R = 6.371e6
phi_src, theta_src = 10, 40
phi_det,theta_det = -21, 10
depth_src, depth_det = 0,0 # both on the surface
l = 0
class Trajectory:
def __init__(self,
phi_src,
theta_src,
phi_det,
theta_det,
depth_src,
depth_det,
l):
self.phi_src = phi_src
self.theta_src = theta_src
self.phi_det = phi_det
self.theta_det = theta_det
self.depth_src = depth_src
self.depth_det = depth_det
self.l = l
#property
def r(self):
r_src = R - self.depth_src
r_det = R - self.depth_det
x_src = r_src * math.cos(self.phi_src) * math.cos(self.theta_src)
y_src = r_src * math.cos(self.phi_src) * math.sin(self.theta_src)
z_src = r_src * math.sin(self.phi_src)
x_det = r_det * math.cos(self.phi_det) * math.cos(self.theta_det)
y_det = r_det * math.cos(self.phi_det) * math.sin(self.theta_det)
z_det = r_det * math.sin(self.phi_det)
coord_src = np.array((x_src, y_src, z_src))
coord_det = np.array((x_det, y_det, z_det))
L = np.linalg.norm(coord_src - coord_det)
return math.sqrt(r_src**2 + self.l * (1.0 - L - (r_src - r_det) * (r_src + r_det)/L))
def phi(r):
pass
trajectory = Trajectory(phi_src,theta_src,phi_det,theta_det,depth_src,depth_det,l)
print(trajectory.r)
But then realized that the
r_src = R - self.depth_src
r_det = R - self.depth_det
x_src = r_src * math.cos(self.phi_src) * math.cos(self.theta_src)
y_src = r_src * math.cos(self.phi_src) * math.sin(self.theta_src)
z_src = r_src * math.sin(self.phi_src)
x_det = r_det * math.cos(self.phi_det) * math.cos(self.theta_det)
y_det = r_det * math.cos(self.phi_det) * math.sin(self.theta_det)
z_det = r_det * math.sin(self.phi_det)
coord_src = np.array((x_src, y_src, z_src))
coord_det = np.array((x_det, y_det, z_det))
L = np.linalg.norm(coord_src - coord_det)
part is common for all the methods of the class and hence there's no point in calculating it numerous times in every method, this piece should be shared with all the methods.
What would be the best way to do that? Do I have to put it into the __init__ method? I've heard it's not a good practice to make any calculations inside the __init__ method.
The common way of declaring a function in a class that does not depend on the state of the object itself is to use the #staticmethod decorator, followed by the function definition. You only pass the function parameters.
If you need to use class level parameters, use #classmethod instead and note that you pass cls instead of self to the function (one could use any variable, so really it doesn't matter. The point is that you are now accessing class attributes and methods instead of those of the object).
class Trajectory:
c = 10 # <<< Class level property.
def __init__(self):
self.c = 5 # <<< Object level property.
#staticmethod
def foo(a, b):
return a * b
#classmethod
def bar(cls, a, b):
return cls.foo(a, b) * cls.c # <<< References class level method and property.
def baz(self, a, b):
return self.foo(a, b) * self.c # <<< References object level method and property.
t = Trajectory()
>>> t.foo(3, 5)
15
>>> t.bar(3, 5)
150
>>> t.baz(3, 5)
75
Hmmm, not totally sure if I get what you want, but quoting you a bit...
def r(self):
r_src = R - self.depth_src
r_det = R - self.depth_det
....
L = np.linalg.norm(coord_src - coord_det)
This is common, you say because methods like def r(self) always some of these variables, like r_src, L:
def r(self):
return math.sqrt(r_src**2 + self.l * (1.0 - L - (r_src - r_det) * (r_src + r_det)/L))
This, imho, tells me that, if you want to reuse those computations then they should be part of __init__ (or called from __init__). But mostly, you need to set all those variables to self.
...whereever you compute them in a common location...
self.r_src = R - self.depth_src
self.r_det = R - self.depth_det
....
self.L = np.linalg.norm(coord_src - coord_det)
Note that as you depend on instance variables such as self.depth_src in the above, this method can't be a class method, it needs to be an instance method.
Now, change your other methods to point to those precomputed attributes.
def r(self):
return math.sqrt(self.r_src**2 + self.l * (1.0 - self.L ....
Now, you could get fancy and only compute those attributes on demand, via properties. But if you are asking a fairly basic Python question, which I think you are, then worry about optimization later and do the easiest for now. I.e. compute them all in the __init__ or from a method called from there.
Now, there are perfectly good reasons to break them out of init, but it mostly has to do with code clarity and modularity. If that chunk of code has some specific math/business domain meaning, then create a method that is named appropriately and call it from main.
On the other hand, some IDEs and code analyzers are better at figuring instance variables when they see them assigned in __init__ and with Python being as dynamic as it is the poor things need all the help they can get.

Having trouble calling Classes in Python

I'm trying to teach myself how to use classes and I'm trying an example I found in a book that asks you to create two classes and then print out some information. Here is my code:
import math
import turtle
import urllib.request
class Shape:
def __init__(self,x=0,y=0):
self.x = x
self.y = y
def calc_area(self):
pass
def calc_perim(self):
pass
def get_shape_type(self):
return "s"
def to_string(self):
return "%s %f %f" % (self.get_shape_type(), self.x, self.y)
def get_draw_params(self):
return [self.x, self.y]
class Circle(Shape):
def __init__(self,x=0,y=0,rad=0):
super().__init__(x,y)
self.radius = rad
def calc_area(self):
area = math.pi * self.radius * self.radius
return area
def calc_perim(self):
perim = 2 * math.pi * self.radius
return perim
def calc_circumference(self):
return self.calc_perim()
def get_shape_type(self):
return "c"
def to_string(self):
return "%s %f %f %f" % (super().to_string(), self.radius, self.calc_area(),self.calc_perim())
def get_draw_params(self):
result = super().get_draw_params()
result.extend([self.radius])
return result
cir = Circle(0,0,150)
print(cir)
When I try to run it, it prints this:
<__main__.Circle object at 0x103d19ef0>
I'm not sure what I'm doing wrong when I'm calling the Circle class. I was hoping that after putting in the values that the init function asks for, there would be some data to print out. Any help would be greatly appreciated.
Try calling the to_string() method that you added to your classes:
>>> cir = Circle(0,0,150)
>>> print(cir)
<__main__.Circle object at 0x7fba2851b400>
>>> print(cir.to_string())
c 0.000000 0.000000 150.000000 70685.834706 942.477796
If you are wanting a customised string representation, try adding __unicode__() and/or __str__() methods to your classes:
def __str__(self):
return self.to_string()
Now you can do this:
>>> c = Circle(0,0,150)
>>> print(c)
c 0.000000 0.000000 150.000000 70685.834706 942.477796
It's actually quite right, this is how python prints your object,
if you want your print(object) print something else, define __str__ method in your class, something like this (it should return an string):
class Circle(Shape):
# your stuff
# ...
def __str__(self):
return "radius: " + self.radius
cir = Circle(0,0,150)
print(cir)
# radius: 150
There is nothing wrong with what you did. Everything is working fine.
This: <__main__.Circle object at 0x103d19ef0>
is indicating to you have you have an object of Circle. So, if you add this:
print(cir.calc_area())
You will end up getting the area result you expect.
Furthermore, a neat bit of information that can help you is if you want to find out more information about what is inside your objects, you can do this:
print(dir(cir))
This will tell you what is housed inside your 'cir' object and you will also see that your methods you created should be there as well. Always handy to find out what is available to you even when you import other modules when you dive deeper in to Python.
Documentation on dir
Well, that is the default representation of a Circle object when you print it.
Now you can call the methods of cir, like
print(cir.calc_area())

Make all variables in a Python function global

Is there a simple way to make all variables in a function global?
I have 20 odd variables in a function and naming them global one by one doesn't make nice code... to me anyway :)
Warning: Don't try this at home, you might burn it down.
There is no legitimate reason to do the following in the course of normal day-to-day programming. Please review the other answers to this question for more realistic alternatives.
I can barely imagine why you would want to do this, but here is a way to do it:
def f(a, b, c):
d = 123
e = 'crazy, but possible'
globals().update(locals())
def g():
print a, b, c, d ,e
>>> globals()
{'g': <function g at 0x875230>, 'f': <function f at 0x8751b8>, '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, '__name__': '__main__', '__doc__': None}
>>> g()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in g
NameError: global name 'a' is not defined
>>> f(10, 20, 'blah')
>>> g()
10 20 blah 123 crazy, but possible
>>> globals()
{'a': 10, 'c': 'blah', 'b': 20, 'e': 'crazy, but possible', 'd': 123, 'g': <function g at 0x875230>, 'f': <function f at 0x8751b8>, '__builtins__': <module '__builtin__' (built-in)>, '__package__': None, '__name__': '__main__', '__doc__': None}
The pythonic way to do this is either to keep the variables in local scope (i.e. define them within each function) and pass them between the functions as arguments / return values; or to keep your variables as attributes of an object or class making your "functions" methods in that class. Either way is OK, but the global keyword is designed specifically to put you off using it in the way you describe. Global variables are not just "bad style" but they make your code very difficult to maintain, as any invariants that your variables need to stick to need to be checked in every function.
Here is an example of good style (with functions):
def quads(a, b, c):
x1 = (-1.0 * b + math.sqrt(b * b - 4.0 * a * c)) / (2.0 * a)
x2 = (-1.0 * b - math.sqrt(b * b - 4.0 * a * c)) / (2.0 * a)
return x1, x2
def pretty(a, b, c, x1, x2):
eqn = "%fx^2 + %fx + %c" % (a, b, c)
print "The first solution to the equation %s is: %f" % (eqn, x1)
print "The second solution to the equation %s is: %f" % (eqn, x2)
return
def main():
a = 100
b = 200
c = 300
x1, x2 = quads(a, b, c)
pretty(a, b, c, x1, x2)
return
if __name__ == '__main__':
main()
Here is an example of good style (with OOP):
class Quadratic(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
self.x1 = None
self.x2 = None
self.solve() # Set x1 and x2 to correct values
# To maintain the invariant between a, b, c and x1, x1
# we should override __setattr__ or use descriptors or
# properties so that self.solve() is called every time
# a, b, or c are updated.
return
def solve(self):
self.x1 = (-1.0 * self.b +
math.sqrt(self.b * self.b - 4.0 * self.a * self.c)) / (2.0 * self.a)
self.x2 = (-1.0 * self.b -
math.sqrt(self.b * self.b - 4.0 * self.a * self.c)) / 2.0 * self.a
return
def pretty(self):
eqn = "%fx^2 + %fx + %c" % (self.a, self.b, self.c)
print "The first solution to the equation %s is: %f" % (eqn, self.x1)
print "The second solution to the equation %s is: %f" % (eqn, self.x2)
return
def main():
quad = Quadratic(100, 200, 300)
quad.pretty()
return
if __name__ == '__main__':
main()
There's no way to declare them all as global, and you really don't want to. Those 20 variables probably should be turned into an object with 20 attributes instead.
The simplest solution is to have only a single global — or, better yet, to figure out how to pass it in to the function. Using it as a global would look like this (again, I am showing the simplest possible case, not necessarily the best use of Python):
class Info(object): # or whatever you want to name the container
"""Holder for global information."""
info = Info() # single instance we will use
def my_function():
print "Here is some info:"
print info.a, info.b, info.c
info.a = 3
info.b = 8
info.c = []
if __name__ == '__main__':
my_function()
Again, I would probably pass info to the function instead. But since your question was about a global, it's shown here as a global.
A niche example where I wanted to do this: use a function for importing.*
def temp():
a = "stays local value"
old_locs = locals().copy()
b = "is global value"
import math
new_locs = locals()
new_vars = {k: new_locs[k] for k in set(new_locs) - set(old_locs)
if k != 'old_locs'}
globals().update(new_vars)
temp()
print(b)
print(math.sqrt(3))
print(a)
gives
is global value
1.7320508075688772
NameError: name 'a' is not defined
This way only the specific 20 or so variables would get update the global namespace and intermediate variable names in the function wouldn't.
*I needed to import from a .ipynb file, and the process for doing so depends if called from google Collaboratory, a desktop .ipynb, or a desktop .py file; this involved the use of magics which are treated as invalid syntax in situation which wouldn't call those branches, so by importing my import function I can escape that issue.

Categories

Resources