here's a newb Python question that I'm sure is a no-brainer for the pros. I have an object OddStream that is called from the function print_from_stream to create a list of odd numbers starting from 1. It works find the first time but when calling it a second time the new list starts from the last number of the first list + 2.
What should I write to reset OddStream? BTW, this is only a portion of the code, but it's the part that matters. Thanks if you can help.
class OddStream(object):
def __init__(self):
self.current = 1
def get_next(self):
to_return = self.current
self.current += 2
return to_return
def print_from_stream(n):
for _ in range(n):
print(stream.get_next())
I guess the stream instance of the OddStream class is being instantiated like this:
class OddStream(object):
# ...
stream = OddStream() # Breakpoint 1
def print_from_stream(n):
for _ in range(n):
print(stream.get_next()) # Breakpoint 2
At breakpoint 1 stream has been instantiated and stream.current = 1
At breakpoint 2 stream.get_next() has been called and it has increased stream.current
So the behaviour you described should be expected.
To avoid such behaviour, add a reset() method to OddStream and call it from print_from_stream():
class OddStream(object):
# ...
def reset(self):
self.current = 1
stream = OddStream()
def print_from_stream(n):
stream.reset()
for _ in range(n):
print(stream.get_next())
print("First run:")
print_from_stream(10)
print("Second run:")
print_from_stream(10)
Related
I'm developing an application that reads a message input from telegram with a set of variables, and then starts a game with the user. So I created a class that represents an instance of the game, making one game per chat possible:
class Battle:
def __init__(self, mainchat):
self.mainchat = mainchat
print('Instance of battle started on chat %s' % self.mainchat)
pcount = 0
team1 = []
team2 = []
p1 = ()
p2 = ()
p1score = 0
p2score = 0
battlechoicep1 = -1
battlechoicep2 = -1
so, as soon as I get a message, I start an instance of a battle based on user inputes, e.g.
battle = Battle(chat_id)
battle.p1 = 'Paul'
battle.battlechoicep1 = 4
...
this way has been working fine right now, but every time I want to reset the battle, I go through a function that does this:
battle.pcount = 0
battle.team1 = []
battle.team2 = []
battle.p1 = ()
battle.p2 = ()
battle.p1score = 0
battle.p2score = 0
battle.battlechoicep1 = -1
battle.battlechoicep2 = -1
save() # outside function that saves the scores into a pickle file
return
So, I would like to make it so this is a function inside my class, so everytime I call battle.reset it would call something like this
def reset():
battle.pcount = 0
battle.team1 = []
battle.team2 = []
battle.p1 = ()
battle.p2 = ()
battle.p1score = 0
battle.p2score = 0
battle.battlechoicep1 = -1
battle.battlechoicep2 = -1
save() # outside function that saves the scores into a pickle file
return
I don't know how is the right approach to this problem, I don't even know if what I've been doing up to now is 'correct' (it is working at least).
Creating the function inside the class (like def reset(self):) seems to have no effect.
You're on the right track with def reset(self). You just need to change the instances of battle to self in the method itself. NOTE: This needs to be a method of the Battle class.
def reset(self):
self.pcount = 0
... # etc
save() # outside function that saves the scores into a pickle file
When you pass in self as the first parameter of a class method, it allows the method to work on the instance of the class that you've called it on. If you just do def reset(self) without changing the battle to self, it will try to modify a variable in the current scope called battle, which in this case probably doesn't exist.
The other thing you could do if you just want reset to create a completely new object without preserving any of the attributes, you can just do:
def reset(self):
return Battle()
You're almost there!
class Battle:
def __init__(self, mainchat):
self.mainchat = mainchat
print('Instance of battle started on chat %s' % self.mainchat)
self.reset()
def reset(self):
self.team1, self.team2 = [], []
self.p1 = self.p2 = () #New tuples will be assigned and overwritten
self.pcount = self.p1score = self.p2score = 0
self.battlechoicep1 = self.battlechoicep2 = -1
save() # outside function that saves the scores into a pickle file
So when you need to reset, just call battle.reset()! Maybe the save function can also be a class method as well, just follow the same format.
I'm trying to understand when you would want to have an instance of a class, and what exactly the difference is between these two variations of code:
Class A takes a time and and assigns it to a new variable, and then returns that new variable.
class A:
def B(time):
seconds = time
return seconds
seconds = A.B(int)
Class C takes a time in as well, but also creates an instance of function D (using self) and then returns self.seconds.
class C:
def D(self, time):
self.seconds = time
return self.seconds
seconds = C().D(int)
They end up returning the same values. I'm have difficulty understanding how these two pieces of code are different. Is one superior in certain situations vs. the other?
Thank you!
EDIT: Added calls to both functions.
Perhaps the following (very simplified) example helps to see where it can be useful to have an instance of a class:
class A:
minutes = 2
def time(seconds):
return 60*A.minutes + seconds
class B:
minutes = 2
def time(self, seconds):
return 60*self.minutes + seconds
print("Class:")
print(A.time(30))
a1 = A
a2 = A
a1.minutes = 3
a2.minutes = 4
print(a1.time(30)) # 60*4 + 30
print(a2.time(30)) # 60*4 + 30
print("Instance:")
print(B().time(30))
b1 = B()
b2 = B()
b1.minutes = 3
b2.minutes = 4
print(b1.time(30)) # 60*3 + 30
print(b2.time(30)) # 60*4 + 30
This results in:
Class:
150
270
270
Instance:
150
210
270
At the core, what you are asking for is understanding the difference between a Static Method and a normal Method, and what the advantages of OOP are.
A Static method can be called without instantiating the class, such as in your first example. This allows you to group related functions under a single header (the class), but it is not, technically, OOP.
However, a Static method has no instance data to act upon, as there is no instance.
A class instance allows you to keep track of Object specific data, and act upon them within your methods.
For example:
import time
class Stopwatch:
def __init__(self, name, start):
self.name = name
self.time = start
self.active = False
def start(self):
self.active = True
def stop(self):
self.active = False
def reset(self, time):
self.time = time
def isComplete(self):
return (self.time == 0)
def tick(self):
if self.active:
self.time -= 1
print(self.name+": ",self.time)
if self.time == 0:
print("Timer of " + self.name + " has reached zero!")
self.stop()
watchA = Stopwatch("A", 10)
watchB = Stopwatch("B", 5)
watchA.start()
watchB.start()
while (not watchA.isComplete()) or (not watchB.isComplete()):
time.sleep(1)
watchA.tick()
watchB.tick()
Running this outputs:
A: 9
B: 4
A: 8
B: 3
A: 7
B: 2
A: 6
B: 1
A: 5
B: 0
Timer of B has reached zero!
A: 4
A: 3
A: 2
A: 1
A: 0
Timer of A has reached zero!
Notice how the time of each watch is tracked separately, despite using the same code. This would not be possible using Static methods, as the data is attached not to the Class, but to the Instanced objects themselves.
Hi i have a python wrapper function which counts the number of times a function is called and based on each count i am performing some actions which writes the content to a html file. Now is there a way to set the counter back to 1 after one iteration, so that when i start for second iteration I want the count of htmloverview() to start from beginning and not count from previous values.
Decorator:
def counter(func):
#wraps(func)
def tmp(*args, **kwargs):
tmp.count += 1
return func(*args, **kwargs)
tmp.count = 0
return tmp
#counter
def htmloverview(fileouthtml,resultfile,file,identical,namesBothSub):
r= htmloverview.count
if(len(diff)==0):
if(r==1):
s = '\n'.join([message,message1,'<td>','0','</td>','</tr>'])
else:
s = '\n'.join(['<tr>','<td>',message1,'<td>','0','</td>','</tr>'])
fileouthtml.write(s)
fileouthtml.write('\n')
I can run the simulator 'n' times and each time when i run, i want the counter of htmloverview to start from beginning and not count from previous iteration, is there a way to do it.
A class seems to be a better fit here than a decorator.
class Simulation(object):
def __init__(self, func):
self.count = 0
self._func = func
def reset_count(self):
self.count = 0
def run(self, *args, **kwargs):
self.count += 1
return self._func(*args, **kwargs)
sim = Simulation(htmloverview)
for i in range(100): #first iteration
sim.run(fileouthtml,resultfile,file,identical,namesBothSub)
print sim.count #ran 100 times
sim.reset()
you could do error handling and keep error count and have multiple instances of simulation each with it's own value of count
(Would have put this in a comment if I could)
I'm a bit unsure what you are trying to achieve. Do you want your function to have one behavior the first time you call it and another for all other calls, until you reset the state? Then you could either pass the state variable as a boolean parameter:
def htmloverview(fileouthtml,resultfile,file,identical,namesBothSub, first_call) # True/False
or you could keep the state in a global variable:
htmloverview_count=0
def htmloverview(fileouthtml,resultfile,file,identical,namesBothSub):
global htmloverview_count
if htmloverview_count>0:
<do something>
htmloverview_count+=1
And reset the state from the calling context:
htmloverview_count=0
If you have lots of functions with similar behavior it might make sense to use a decorator. Please elaborate your question: would any of the above solve your problem?
I have this class called DecayingSet which is a deque with expiration
class DecayingSet:
def __init__(self, timeout): # timeout in seconds
from collections import deque
self.timeout = timeout
self.d = deque()
self.present = set()
def add(self, thing):
# Return True if `thing` not already in set,
# else return False.
result = thing not in self.present
if result:
self.present.add(thing)
self.d.append((time(), thing))
self.clean()
return result
def clean(self):
# forget stuff added >= `timeout` seconds ago
now = time()
d = self.d
while d and now - d[0][0] >= self.timeout:
_, thing = d.popleft()
self.present.remove(thing)
I'm trying to use it inside a running script, that connects to a streaming api.
The streaming api is returning urls that I am trying to put inside the deque to limit them from entering the next step of the program.
class CustomStreamListener(tweepy.StreamListener):
def on_status(self, status, include_entities=True):
longUrl = status.entities['urls'][0]['expanded_url']
limit = DecayingSet(86400)
l = limit.add(longUrl)
print l
if l == False:
pass
else:
r = requests.get("http://api.some.url/show?url=%s"% longUrl)
When i use this class in an interpreter, everything is good.
But when the script is running, and I repeatedly send in the same url, l returns True every time indicating that the url is not inside the set, when is supposed to be. What gives?
Copying my comment ;-) I think the indentation is screwed up, but it looks like you're creating a brand new limit object every time on_status() is called. Then of course it would always return True: you'd always be starting with an empty limit.
Regardless, change this:
l = limit.add(longUrl)
print l
if l == False:
pass
else:
r = requests.get("http://api.some.url/show?url=%s"% longUrl)
to this:
if limit.add(longUrl):
r = requests.get("http://api.some.url/show?url=%s"% longUrl)
Much easier to follow. It's usually the case that when you're comparing something to a literal True or False, the code can be made more readable.
Edit
i just saw in the interpreter the var assignment is the culprit.
How would I use the same obj?
You could, for example, create the limit object at the module level. Cut and paste ;-)
I am trying to simply get the value out of my class using a simple function with a return value, I'm sure its a trivial error, but im pretty new to python
I have a simply class set up like this:
class score():
#initialize the score info
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
# Score Info
def setScore(num):
self.score = num
# Enemy Info
def getEnemies():
return self.num_enemies
# Lives Info
def getLives():
return self.getLives
etc.....
Than I create an instance of the class as such:
scoreObj = score()
for enemies in range(0, scoreObj.getEnemies):
enemy_sprite.add(enemy())
I get the error saying that an integer is expected, but it got an instancemethod
What is the correct way to get this information?
Thanks!
scoreObj.getEnemies is a reference to the method. If you want to call it you need parentheses: scoreObj.getEnemies().
You should think about why you are using a method for this instead of just reading self.num_enemies directly. There is no need for trivial getter/setter methods like this in Python.
The first parameter for a member function in python is a reference back to the Object.
Traditionally you call it "self", but no matter what you call the first parameter, it refers back to the "self" object:
Anytime I get weird errors about the type of a parameter in python, I check to see if I forgot the self param. Been bit by this bug a few times.
class score():
#initialize the score info
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
# Score Info
def setScore(self, num):
self.score = num
# Enemy Info
def getEnemies(self):
return self.num_enemies
# Lives Info
def getLives(foo): #foo is still the same object as self!!
return foo.num_lives
#Works but don't do this because it is confusing
This code works:
class score():
def __init__(self):
self.score = 0
self.num_enemies = 5
self.num_lives = 3
def setScore(self, num):
self.score = num
def getEnemies(self):
return self.num_enemies
def getLives(self):
return self.getLives
scoreObj = score()
for enemy_num in range(0, scoreObj.getEnemies()):
print enemy_num
# I don't know what enemy_sprite is, but
# I commented it out and just print the enemy_num result.
# enemy_sprite.add(enemy())
Lesson Learned:
Class functions must always take one parameter, self.
That's because when you call a function within the class, you always call it with the class name as the calling object, such as:
scoreObj = score()
scoreObj.getEnemies()
Where x is the class object, which will be passed to getEnemies() as the root object, meaning the first parameter sent to the class.
Secondly, when calling functions within a class (or at all), always end with () since that's the definition of calling something in Python.
Then, ask yourself, "Why am I not fetching 'scoreObj.num_lives' just like so instead? Am I saving processing power?" Do as you choose, but it would go faster if you get the values directly from the class object, unless you want to calculate stuff at the same time. Then your logic makes perfect sense!
You made a simple mistake:
scoreObj.getEnemies()
getEnemies is a function, so call it like any other function scoreObj.getEnemies()