Tick method in a PoliceOfficer class - python

My question deals with creating a tick procedure the original tick procedure where it makes a class called PoliceOfficer arrest everyone who is naked around him.
def tick(self):
# next time step for all objects that tick
for t in self.__things:
obj = self.get_thing(t)
if has_method(obj, "tick"):
obj.tick()
This the original tick method.
This is my PoliceOfficer class and the method known as arrest. The arrest method arrests someone based upon them not having any clothes on when in the area of the PoliceOfficer, and when there isn't anyone to arrest he just says something else.
class PoliceOfficer (Person):
def __init__(self, name, jail):
Person.__init__(self, name)
self.set_restlessness(0.5)
self.__jail = jail
def arrest (self, Person):
if self.location.name is Person.location.name:
self.say (Person.name + "You're under arrest!")
self.say ("You have the right to shut up and lay on the ground with your hands behind your back")
Person.name(Place("jail")
else:
return self.say (Person.name + "Ain't got nothing to do damnit")
def tick (self):
if isinstance(t, Student):
if Student.is_dressed = False:
arrest.student
else:
(Person)tick(): self.say("Shoot no one to arrest off to the 7 eleven")
Would this be partially correct on making my own tick method for PoliceOfficer?
If not what else would I need to do or change to make it like the tick method described, except for making the PoliceOfficer arrest any student that isn't dressed?

Uhm,... you want to test is an object is of a certain class? Python has a built-in function for that: isinstance(). Quick example:
>>> isinstance(1, int)
True
>>> isinstance("Hello World!", int)
False
>>> isinstance("Hello World!", str)
True
Check the documentation for more information.
http://docs.python.org/library/functions.html#isinstance
As per delnan's "suggestion", a little piece of advice: instead of checking for the class behind the Person you receive, it's cleaner to have Person implement a canBeArrested() method that subclasses can override, for which Student can return false.
class Person(object):
(...)
def canBeArrested(self):
return True
class Diplomat(Person):
(...)
def canBeArrested(self):
# Overrides Person's default behaviour
return False

There are two ways:
obj.__class__.__name__ == "Student"
or
isinstance(obj, Student)
I recommend the second way, but sometimes you really need the name of the class, for which obj.__class__.__name__ is the way to go.

Related

Python: What's best practice for variable initialization value that won't render True or False when used in boolean logic?

I often times find myself initializing an attribute in a class to False, But what I really want is for this to represent True or False ONLY after it is actually assigned to reduce bugs in the future. For instance, the attribute isDog I want to assign later in the methods to either True or False, but I hate having to assign the default to "False" since it leaves room for bugs in the future and seems to assume a priori it's not a dog. Is there a best practice or standard for what I could assign this to that won't render in boolean logic (instead, printing an error if used in Boolean logic) so that I don't need to preassign as False?
A good option is to define your variable as None and check if it is defined before using it.
Here an example:
class Animal:
def __init__(self):
self.is_dog: Optional[bool] = None
...
def become_a_dog(self) -> None:
self.is_dog = True
def become_a_cat(self) -> None:
self.is_dog = False
def can_bark(self) -> bool:
if self.is_dog is None:
raise Exception("Animal instance is not yet specified as dog or cat.")
return self.is_dog
I won't say that this is best practice or standard, however you could use the None keyword to achieve this functionality.
Take a look at the code example below
class Pet:
def __init__(self):
self.isDog = None
self.isCat = None
myCat = Pet()
myCat.isCat = True
if myCat.isDog:
print('I have a dog!')
if myCat.isCat:
print('I have a cat!')
if myCat.isDog == None:
print("I haven't decided whether it's a dog yet")
This code will output "I have a cat!", and "I haven't decided whether it's a dog yet"
Here's a workaround using #property
class Foo:
def __init__(self):
self._is_foo = None
#property
def is_foo(self):
assert isinstance(self._is_foo, bool), "ERROR!!!"
return self._is_foo
def set_foo(self, val):
self._is_foo = val
x = Foo()
x.is_foo
# AssertionError: ERROR!!!
x.set_foo(True)
x.is_foo
# True

Having an issue with inheritance in python

I'm having trouble with inheritance between classes. The class I'm struggling with is the vulture class which is a subclass of the bird class which is a subclass of the critter class. The bird and critter class, and the main that they're being run through, all work fine. But when I try to use the vulture class, I get an error:
AttributeError: 'Vulture' object has no attribute '_Bird__direction'
I'm not sure what I did wrong, and I'm hoping someone could help me find my mistake.
Vulture class:
from bird import *
class Vulture (Bird):
def __init__(self):
self.__hungry=True
self.__in_a_row=-1
self.__direction=DIRECTION_NORTH
def eat(self):
if self.__hungry:
self.__hungry=False
return True
else:
return False
def fight(self, opponent):
self.__hungry=True
return super(Bird, self).fight(self,opponent)
def get_color(self):
black
Bird class:
from Critter import *
class Bird (Critter):
def __init__(self):
self.__in_a_row=-1 #doesn't go north 3 times on first move if set to 0
self.__direction=DIRECTION_NORTH
def fight(self, opponent):
if opponent.__str__=="%": #roars at ants
return ATTACK_ROAR
else:
return ATTACK_POUNCE
def get_color(self):
return "blue"
def __str__(self): #uses the most recent direction to determine which character should be used
if (self.__direction==DIRECTION_NORTH or self.__direction==DIRECTION_CENTER):
return "^"
elif self.__direction==DIRECTION_EAST:
return ">"
elif self.__direction==DIRECTION_SOUTH:
return "V"
else:
return "<"
def get_move(self):
if self.__in_a_row<2:
self.__in_a_row+=1
return self.__direction
else: #Turning in the proper direction after it hits the end of the line
if self.__direction==DIRECTION_NORTH:
self.__direction=DIRECTION_EAST
self.__in_a_row=0
return self.__direction
elif self.__direction==DIRECTION_EAST:
self.__direction=DIRECTION_SOUTH
self.__in_a_row=0
return self.__direction
elif self.__direction==DIRECTION_SOUTH:
self.__direction=DIRECTION_WEST
self.__in_a_row=0
return self.__direction
elif self.__direction==DIRECTION_WEST:
self.__direction=DIRECTION_NORTH
self.__in_a_row=0
return self.__direction
def eat(self):
return False
I don't think that the critter class itself will be relevant in this, and it's pretty big, so I'll leave that off the post unless someone thinks it might help to have.
See this section on Private Variables in the Python documentation.
Python treats instance variables that start with double-underscores specially, mangling the name to keep them private to the class (even private from the parent class). When you call a Bird method on your Vulture class, the Bird method references to self.__direction are actually referencing the self._Bird__direction variable which is distinct from the self._Vulture__direction variable that you initialize in your Vulture __init__ constructor.
In particular:
v = Vulture() # initializes self._Vulture__direction only
print(v) # throws an exception -- v._Bird__direction isn't initialized
Edit: As #ShadowRanger points out, the convention in Python is to prefix with a single underscore those instance variables or methods that are intended to be private to the implementation but freely shared between superclasses and subclasses (i.e., similar to protected in Java or C++). There's no special treatment of such variables by the language, it's just a signal to users of the class that they shouldn't "mess" with those instance variables or methods.
This is probably what you intended for __direction, __in_a_row, and maybe even __hungry (though that last one doesn't appear in the Bird class). If you change all these double underscore prefixes to single underscores, that should clear up your problem.

Modify Class Object Argument Based On When Calling A Method

This is a heavily simplified version of what I am working on, I just don't want to put 5,000 lines in here. So I know this works and all, but I want to be able to have the method"eat" be able to be applied non-specifically to any object that this class parents (such as "John Smith", and adding lets say "Mike Doe".) I would like it to automatically select the person who undergoes ".eat()" to eat food rather than making the method specifically state: johnSmith.hunger = False. What I am doing is creating methods of actions people can use within the game that affect other objects (class children and variables), but I don't want to set a method for each action for each character unit. That would be insane. Given below is my set of code.
class human():
def __init__(self, name, hunger):
self.name = name
self.hunger = hunger
def eat(self):
johnSmith.hunger = False
print("Human Ate Food")
johnSmith = human("John Smith", True)
print("Human Is Hungry:", johnSmith.hunger)
johnSmith.eat()
print("Human Is Hungry:", johnSmith.hunger)
If I am unclear (which I know I am Not doing a great job explaining), feel free to ask.
Just use self:
def eat(self):
self.hunger = False
print("%s Ate Food" % self.name)

Python unittesting for a class method

A beginner level question.. trying to understand how I can best use the built-in unittest. In the trivial example below, the method consume_food picks a food item and then I am calling food.cut() method.
In future, this method may return instance of Drink object. The #commented code indicates one possible future implementation. In this case, self.milk will not have the cut method defined.
I want to add a unit test for consume_food and pick_food methods. I would like to do this for the original implementation first and then change it after adding self.milk functionality.
EDIT: The intention is to write a unit test for an existing api, so that I can capture any such changes ( i.e. absence of Drink.cut method) forcing me to update the methods and unit tests.
Can someone please help showing me how to write a unit test for this example?
class Fruit:
def cut(self):
print("cut the fruit")
class Drink:
def pour(self):
print("pour the drink")
class A:
def __init__(self):
self.apple = Fruit()
self.banana=Fruit()
#self.milk = Drink()
#self.liquid_diet = True
def consume_food(self):
food = pick_food()
food.cut()
print("consuming the food")
def pick_food(self):
return self.apple
#if self.liquid_diet: return self.milk
#return self.apple
The thing is, your cut() and consume_food() methods don't really do much right now that allow you to make meaningful assertions after you execute them in a test.
So I'd suggest to expand your initial code a little bit to have those methods act upon the respective objects so that you can make meaningful assertions on their state after invoking those methods.
Right now, all they really do is write to STDOUT, which is sort of a global state - which should generally be avoided and is always difficult to test. (I'm not saying that printing output is a bad thing - but if that's the only thing your code does, it's going to be very tricky to test).
So I introduced a common superclass Food which has a consume() method, and sets a corresponding attribute. Similarly, the cut() method on Fruit now sets an attribute that you can test for.
import unittest
class Food(object):
def __init__(self):
self.consumed = False
def consume(self):
self.consumed = True
class Fruit(Food):
def __init__(self):
super(Fruit, self).__init__()
self.been_cut = False
def cut(self):
print("cut the fruit")
self.been_cut = True
class Consumer(object):
def __init__(self):
self.apple = Fruit()
self.banana = Fruit()
def consume_food(self):
food = self.pick_food()
food.cut()
print("consuming the food")
food.consume()
def pick_food(self):
return self.apple
These tests now can make assertions on the object's states after the relevant methods have been invoked. Note that they follow the AAA pattern - Arrange Act Assert:
First, you arrange the objects under test the way you need them (instantiate a consumer).
Then you act on the objects under test (invoking the method in question)
Finally, you make assertions on the resulting state you expect the objects to be in
class TestConsumer(unittest.TestCase):
def test_consume_food_consumes_the_apple(self):
c = Consumer()
c.consume_food()
self.assertTrue(c.apple.consumed,
"Expected apple to be consumed")
def test_consume_food_cuts_the_food(self):
c = Consumer()
c.consume_food()
self.assertTrue(c.apple.been_cut,
"Expected apple to be cut")
def test_pick_food_always_selects_the_apple(self):
c = Consumer()
food = c.pick_food()
self.assertEquals(c.apple, food,
"Expected apple to have been picked")
if __name__ == '__main__':
unittest.main()

Python checking __init__ parameter

I've been trying to figuring this out for the last few hours, and I'm about to give up.
How do you make sure that in python only a matching specific criteria will create the object?
For example, let's say I want to create an object Hand, and initialize a Hand only when I have enough Fingers in the initializer? (Please just take this as an analogy)
Say,
class Hand:
def __init__(self, fingers):
# make sure len(fingers)==5, and
#only thumb, index, middle, ring, pinky are allowed in fingers
pass
Thanks.
These are the closest questions I found, but one is in C++, the other does not answer my question.
checking of constructor parameter
How to overload __init__ method based on argument type?
You have to define __new__ for that:
class Foo(object):
def __new__(cls, arg):
if arg > 10: #error!
return None
return super(Foo, cls).__new__(cls)
print Foo(1) # <__main__.Foo object at 0x10c903410>
print Foo(100) # None
That said, using __init__ and raising an exception on invalid args is generally much better:
class Foo(object):
def __init__(self, arg):
if arg > 10: #error!
raise ValueError("invalid argument!")
# do stuff
Try asserting:
class Hand(object):
def __init__(self,fingers):
assert len(fingers) == 5
for fing in ("thumb","index","middle","ring","pinky"):
assert fingers.has_key(fing)

Categories