I am trying to test a python method of a file-A which uses a variable in file-A.
My file-A method looks like this:
def rotate(self, rotation):
self.current_face = board.positions[(board.positions.index(self.current_face) + rotation) % 4]
Note: This is inside class A-1 in file-A
The main for file-A looks like this:
if __name__ == '__main__':
inp = Input("input.txt") # create Input object
board = Board(inp.lines[0]) # create board object -----> NOTE
rover_objects(inp.lines[1:]) # create rover objects
process_and_print() # process and print output
So, when I run file-A, it works exactly like I want it to work.
Now, I am trying to test def rotate(self, rotation) in file-A
My test code looks like:
class RoverTest(unittest.TestCase):
def setUp(self):
description = '1 2 N'
moves = 'LMLMLMLMM'
self.testRover = Rover(description, moves)
def test_coordinates(self):
self.testRover.rotate(rotation = 4) -----> Problem
self.assertEqual(self.testRover.current_face, 'N')
The issue is, rotate method in file-A uses the object board in the main in file-A
I am not sure how to pass board to the rotate function from the test.
If I run my test right now, I am thrown an error:
NameError: name 'board' is not defined
How can I fix this error?
If you are writing a class that depends on other classes existing, you should make it accept those dependencies as arguments to the initialisation, rather than just hoping they are defined globally. For example:
class A1(object):
def __init__(self, inputfile):
self.inp = Input(inputfile)
self.board = Board(self.inp.lines[0])
def rotate(self, rotation):
self.current_face = self.board.positions[(self.board.positions.index(self.current_face) + rotation) % 4]
Now in both your main and test files you can instantiate A1 directly by passing the input file.
This is just an example of course; you might want to instantiate the Board object outside the class and pass it in directly. Either way is fine, the important part is that you're passing in any dependencies.
Related
I have a class in Python that initializes the attributes of an environment. I am attempting to grab the topographyRegistry attribute list of my Environment class in a separate function, which when called, should take in the parameters of 'self' and the topography to be added. When this function is called, it should simply take an argument such as addTopographyToEnvironment(self, "Mountains") and append it to the topographyRegistry of the Environment class.
When implementing what I mentioned above, I ran into an error regarding the 'self' method not being defined. Hence, whenever I call the above line, it gives me:
print (Environment.addTopographyToEnvironment(self, "Mountains"))
^^^^
NameError: name 'self' is not defined
This leads me to believe that I am unaware of and missing a step in my implementation, but I am unsure of what that is exactly.
Here is the relevant code:
class EnvironmentInfo:
def __init__(self, perceivableFood, perceivableCreatures, regionTopography, lightVisibility):
self.perceivableFood = perceivableFood
self.perceivableCreatures = perceivableCreatures
self.regionTopography = regionTopography
self.lightVisibility = lightVisibility
class Environment:
def __init__(self, creatureRegistry, foodRegistry, topographyRegistery, lightVisibility):
logging.info("Creating new environment")
self.creatureRegistry = []
self.foodRegistry = []
self.topographyRegistery = []
self.lightVisibility = True
def displayEnvironment():
creatureRegistry = []
foodRegistry = []
topographyRegistery = ['Grasslands']
lightVisibility = True
print (f"Creatures: {creatureRegistry} Food Available: {foodRegistry} Topography: {topographyRegistery} Contains Light: {lightVisibility}")
def addTopographyToEnvironment(self, topographyRegistery):
logging.info(
f"Registering {topographyRegistery} as a region in the Environment")
self.topographyRegistery.append(topographyRegistery)
def getRegisteredEnvironment(self):
return self.topographyRegistry
if __name__ == "__main__":
print (Environment.displayEnvironment()) #Display hardcoded attributes
print (Environment.addTopographyToEnvironment(self, "Mountains"))#NameError
print (Environment.getRegisteredEnvironment(self)) #NameError
What am I doing wrong or not understanding when using 'self'?
Edit: In regard to omitting 'self' from the print statement, it still gives me an error indicating a TypeError:
print (Environment.addTopographyToEnvironment("Mountains"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Environment.addTopographyToEnvironment() missing 1 required positional argument: 'topographyRegistery'
Comments
Despite having def getRegisteredEnvironment(self): it wasn't indented, so it's not recognized as a class method.
self is a keyword used in conjunction with classes (class methods or attributes) - not functions. self is implied to be the instantiated object (eg a = Environment(...) -> self would refer to a) or the module's (I can't think of the proper term) class.
You didn't have your addTopographyToEnvironment class method defined.
In terms of your Environment class, you aren't using the variables you are passing to the class, so I made that change as well - I don't know if that was intentional or not.
As per your comment from the other answer, if you had def my_class_method(self) and you try to invoke it through an object with additional parameters, like so a = my_object(); a.my_class_method("Mountains"), you should get an error of the sorts, "2 positional arguments passed, expected 1.".
Your main problem is that you are doing Environment.class_method() and not creating an object from the class. Do a = Environment(whatever arguments here) to create an object from the class, then do a.addTopographyToEnvironment("Mountains") to do what you were going to do with "Mountains" and that object. What you have currently may be right, its just is missing the proper implementation, but the below article does a great job explaining the differences between all of them (Class Methods vs Static Methods vs Instance Methods), and is definitely worth the read.
class EnvironmentInfo:
def __init__(self, perceivableFood, perceivableCreatures, regionTopography, lightVisibility):
self.perceivableFood = perceivableFood
self.perceivableCreatures = perceivableCreatures
self.regionTopography = regionTopography
self.lightVisibility = lightVisibility
class Environment:
def __init__(self, creatureRegistry, foodRegistry, topographyRegistery, lightVisibility):
logging.info("Creating new environment")
self.creatureRegistry = creatureRegistry
self.foodRegistry = foodRegistry
self.topographyRegistery = topographyRegistery
self.lightVisibility = lightVisibility
def displayEnvironment(self):
creatureRegistry = []
foodRegistry = []
topographyRegistery = ['Grasslands']
lightVisibility = True
print (f"Creatures: {creatureRegistry} Food Available: {foodRegistry} Topography: {topographyRegistery} Contains Light: {lightVisibility}")
def addTopographyToEnvironment(self, environment):
return "Whatever this is supposed to return." + environment
def getRegisteredEnvironment(self):
return self.topographyRegistry
if __name__ == "__main__":
print (Environment.displayEnvironment()) #Display hardcoded attributes
print (Environment.addTopographyToEnvironment("Mountains"))#NameError
print (Environment.getRegisteredEnvironment()) #NameError
Object Instantiation In Python
With all that out of the way, I will answer the question as is posed, "Is there a way to grab list attributes that have been initialized using self and append data to them in Python?". I am assuming you mean the contents of the list and not the attributes of it, the attributes would be "got" or at least printed with dir()
As a simple example:
class MyClass:
def __init__(self, my_list):
self.my_list = my_list
if __name__ == "__main__":
a = MyClass([1, 2, 3, 4, 5])
print(a.my_list)
# will print [1, 2, 3, 4, 5]
a.my_list.append(6)
print(a.my_list)
# will print [1, 2, 3, 4, 5, 6]
print(dir(a.my_list))
# will print all object methods and object attributes for the list associated with object "a".
Sub Classing In Python
Given what you have above, it looks like you should be using method sub classing - this is done with the keyword super. From what I can guess, it would look like you'd implement that kind of like this:
class EnvironmentInfo:
def __init__(self, perceivableFood, perceivableCreatures, regionTopography, lightVisibility):
self.perceivableFood = perceivableFood
self.perceivableCreatures = perceivableCreatures
self.regionTopography = regionTopography
self.lightVisibility = lightVisibility
class Environment(EnvironmentInfo):
def __init__(self, creatureRegistry, foodRegistry, topographyRegistery, lightVisibility, someOtherThingAvailableToEnvironmentButNotEnvironmentInfo):
logging.info("Creating new environment")
super.__init__(foodRegistry, creatureRegistry, topographyRegistery, lightVisibility)
self.my_var1 = someOtherThingAvailableToEnvironmentButNotEnvironmentInfo
def displayEnvironment(self):
creatureRegistry = []
foodRegistry = []
topographyRegistery = ['Grasslands']
lightVisibility = True
print (f"Creatures: {creatureRegistry} Food Available: {foodRegistry} Topography: {topographyRegistery} Contains Light: {lightVisibility}")
def addTopographyToEnvironment(self, environment):
return "Whatever this is supposed to return." + environment
def getRegisteredEnvironment(self):
return self.topographyRegistry
def methodAvailableToSubClassButNotSuper(self)
return self.my_var1
if __name__ == "__main__":
a = Environment([], [], [], True, "Only accessible to the sub class")
print(a.methodAvailableToSubClassButNotSuper())
as the article describes when talking about super(), methods and attributes from the super class are available to the sub class.
Extra Resources
Class Methods vs Static Methods vs Instance Methods - "Difference #2: Method Defination" gives an example that would be helpful I think.
What is sub classing in Python? - Just glanced at it; probably an okay read.
Self represents the instance of the class and you don't have access to it outside of the class, by the way when you are calling object methods of a class you don't need to pass self cause it automatically be passed to the method you just need to pass the parameters after self so if you want to call an object method like addTopographyToEnvironment(self, newVal) you should do it like:
Environment.addTopographyToEnvironment("Mountains")
and it should work fine
I know there are many questions that touch upon this area, but none have clearly answered the problem I'm facing (or perhaps I'm just really thick).
So I'm transferring functional python code to OOP python, and I have some code
class fake_class:
def __init__(self, data_type=None):
if data_type is None:
self.data_type = ""
else:
self.data_type = data_type
def printToLog(x='', *args):
if args:
x = x.format(*args)
else:
x = str(x)
logFile.write(x)
logFile.write('\n')
print(x)
if __name__ == '__main__':
main()
def main(self):
self.printToLog('this is just an example, for some fake code')
f = fake_class('data-xml-435')
# please appreciate that the full code is over 500 lines
# long that has been edited down for the sake of readability
I need the main method to be able to call other methods in the class, but no matter what I do, I cannot manage to allow it to do so. I have made printToLog into a classmethod, I have tried different ways of instantiating the fake_class, calling and all to no avail. The program complains that it doesn't know what printToLog is, what self is or what fake_class is!
So how might I call a method with another method within Python?
if __name__ == '__main__':
main()
does not make any sense with class. You just don't need them.
With that removed, you have to call main explicitly using the object you created.
f = fake_class('data-xml-435')
f.main() # or f.printToLog(with arguments) whichever is exciting you!
Again, printToLog is function of class, so you need a self:
def printToLog(self, x='', *args):
if args:
x = x.format(*args)
else:
x = str(x)
logFile.write(x)
logFile.write('\n')
print(x)
I have this main class
def main(args):
if type == train_pipeline_type:
strategy = TrainPipelineStrategy()
else:
strategy = TestPipelineStrategy()
for table in fetch_table_information_by_region(region):
split_required = DataUtils.load_from_dict(table, "split_required")
if split_required:
strategy.split(spark=spark, table_name=table_name,
data_loc=filtered_data_location, partition_column=partition_column,
split_output_dir= split_output_dir)
logger.info("Data Split for table : {} completed".format(table_name))
My TrainPipelineStrategy, and TestPipelineStrategy looks like this -
class PipelineTypeStrategy(object):
def partition_data(self, x):
# Something
def prepare_split_data(self, y):
# Something
def write_split_data(self, z):
# Something
def split(self, p):
# Something
class TrainPipelineStrategy(PipelineTypeStrategy):
""""""
class TestPipelineStrategy(PipelineTypeStrategy):
def write_split_data(self, y):
# Something else
My test case -
I need to test how many times split is called by mocking split functionality in main method.
Here is what i have tried -
#patch('module.PipelineTypeStrategy.TrainPipelineStrategy')
def test_split_data_main_split_data_call_count(self, fake_train):
fake_train_functions = mock.Mock()
fake_train_functions.split.return_value = None
fake_train.return_value = fake_train_functions
test_args = ["", "--x=6"]
SplitData.main(args=test_args)
assert fake_train_functions.split.call_count == 10
When i try to run my test, it creates the mock but ultimately ends up calling the actual split function. What am i doing wrong ?
The main issue with this code is that the way you set up the patch would be if TrainPipelineStrategy were a nested class of PipelineTypeStrategy, but TrainPipelineStrategy is a subclass of PipelineTypeStrategy.
Since TrainPipelineStrategy inherits from PipelineTypeStrategy it has access to split directly, so you can patch split without any reference to PipelineTypeStrategy (unless you specifically want to patch the version of split defined in PipelineTypeStrategy).
However, if you just want to mock the split method of the PipelineTypeStrategy class, you should use the patch.object decorator to mock just split instead of mocking the whole class as it's a bit more clean. Here's an example:
class TestClass(unittest.TestCase):
#patch.object(TrainPipelineStrategy, 'split', return_value=None)
def test_split_data_main_split_data_call_count(self, mock_split):
test_args = ["", "--x=6"]
SplitData.main(args=test_args)
self.assertEqual(mock_split.call_count, 10)
Here's the class:
class MinerNotFullAction:
def __init__(self, entity, image_store):
self.entity = entity
self.image_store = image_store
def miner_to_ore(self, world, ore):
entity_pt = entities.get_position(self.entity)
if not ore:
return ([entity_pt], False)
ore_pt = entities.get_position(ore)
obj = point.Point(0, 0)
if obj.adjacent(entity_pt, ore_pt):
entities.set_resource_count(self.entity,
1 + entities.get_resource_count(self.entity))
remove_entity(world, ore)
return ([ore_pt], True)
else:
new_pt = next_position(world, entity_pt, ore_pt)
return (worldmodel.move_entity(world, entity, new_pt), False)
And here's the function that's in the same file, but it's outside of the class:
def miner_not_full_action(world, action, ticks):
entity = action.entity
entity_pt = entities.get_position(entity)
ore = find_nearest(world, entity_pt, entities.Ore)
(tiles, found) = MinerNotFullAction.miner_to_ore(world, entity, ore)
if found:
entity = try_transform_miner(world, entity, try_transform_miner_not_full)
schedule_action(world, entity,
create_miner_action(entity, action.image_store),
ticks + entities.get_rate(entity))
return tiles
If you look at the function, def miner_not_full_action, you'll see the line: (tiles, found) = miner_to_ore(world, entity, ore). Notice that inside this function, it is calling the method, miner_to_ore (from the class that I've provided above).
My question is, what is the correct way to rewrite this line of code so that the function can use this method from the class (even though the function itself is outside of the class)? Thanks!
You can only call methods of a class from outside if you either have an object of this class or can construct one. Except, if it is a static method or a class method.
In your example, you want to use something from
class MinerNotFullAction:
def __init__(self, entity, image_store):
self.entity = entity
self.image_store = image_store
def miner_to_ore(self, world, ore):
...
in
def miner_not_full_action(world, action, ticks):
entity = action.entity
entity_pt = entities.get_position(entity)
ore = find_nearest(world, entity_pt, entities.Ore)
(tiles, found) = MinerNotFullAction.miner_to_ore(world, entity, ore)
...
So, the question is: Do you have an appropriate ection object here?
If so (action sounds like an appropriate candidate), you can do
(tiles, found) = action.miner_to_ore(world, ore)
in order to perform your task.
See it from the other side: If you call this method, you must have something to be seen as self. This should be an instance of this class. If you don't have anything like that, you have to create one. Otherwise, self would make no sense in that method.
Easy example:
def miner_not_full_action(world, action, ticks):
# 1. call it via the class. That may or may not work, but you have to provide an action object as the first argument.
try1 = MinerNotFullAction.miner_to_ore(action, world, ore)
# 2. call it regularly (as already mentioned), equivalent to 1.
try2 = action.miner_to_ore(world, ore)
# If we don't have such an object? Then we create one:
ac = MinerNotFullAction()
# and use it to call:
try3 = ac.miner_to_ore(world, ore)
Original class program:
from Circle import circle
class circle:
def __init__(self,radius=1): #write def __init__(self,radius=1) to set a value
self.radius=radius
# constructer constructs the object and initializes it
def getArea(self):
return(3.142*self.radius*self.radius)
def getPerimeter(self):
return(2*3.142*self.myradius)
Using class:
def main():
c1=circle()
#If below happens
c1.radius=-1
#if above happens then negative value will be returned
c2=circle(5)
c3=circle(3)
print(c1.getArea())
print(c2.getArea())
print(c3.getArea())
main()
I was just trying to learn about classes in python. When I run the program it says that
builtins.AttributeError: 'circle' object has no attribute 'getArea'
I am not able to understand why it is happening.
What about something like this:
from math import pi
class Circle:
def __init__(self,radius=1):
self.radius=radius
def get_area(self):
return pi * self.radius**2
def get_circumvention(self):
return 2 * pi * self.radius
if __name__ == "__main__":
c1=Circle()
#If below happens
c1.radius=-1
#if above happens then negative value will be returned
c2=Circle(5)
c3=Circle(3)
print(c1.get_area())
print(c2.get_area())
print(c3.get_area())
print(c1.get_circumvention())
print(c2.get_circumvention())
print(c3.get_circumvention())
The error you are seeing is probably because you have that weird import statement on top that hides your circle class (you try to call Circle.circle.getArea() that does not exists)
Furthermore:
python coded styles suggest CapsWords for class names and
lowercase for methods and functions.
self.myradius is not defined in __init__ so getPerimeter will fail.
The brackets in the methods are not necessary.
math has pi
To the power is noted as ** (5**2 == 25)
Use the if __name__ == "__main__": construct if you only want to execute when directly run and not on import.
Perimeter -> circumvention
Use the import statement in another python file that you want to use the Circle class in: from whateveryounamedthisfile import Circle. Then you can use Circle like you would in this file.
Your import is pointless. Don't import 'circle' from 'Circle' if you, as the comments have stated. Also, you have not defined the 'myradius' attribute, therefore your 'getPerimeter()' function will not work unless you change that.