Time is not defined - Class python - python

I've been trying to make this class called Time with has the attributes of hour,minutes and seconds, that also has accessor functions and mutator functions such as set_hour, increment_hour and so on.
This is my code, I cannot get it to work I get the error Time is not defined or t is not defined when i switch the last lines around. Python 3.2.5 by the way.
class Time:
"""The Time class defines the time with
attributes: hour, minute, second
"""
#Attributes
hour = 12
minutes = 00
seconds = 00
#Functions
def get_hour(self):
return self.hour
def get_minute(self):
return self.minute
def get_second(self):
return self.second
def print_time(self):
print("Hello, the current time is", self.hour,":",self.minute,":",self.second)
def set_hour(self, new_hour):
self.hour = new_hour
t.set_hour("1")
print(t.get_hour())
print(t.print_time())
t = Time()

It seems you are invoking the method set_hour("1") on a variable t before that variable has been initialized by t = Time().
EDIT: and correct the indentation as said in the comments. I'm not a Python programmer so I didn't catch that.

Related

Creating a class instance that will lose 1hp every minute?

I want to create several "Players" instances that they will automatically lose hp after some time (e.g. 60 seconds).
Say I have a class:
class Player:
def __init__(self, hp=1000):
self.hp = hp
def lose_hp(self): #not sure if there's a better way to do this than to call this function every 60 seconds
pass
Is there a way to do that without having to call the lose_hp function for each player? (if I have 10000 players it might be difficult).
Save the base HP at object creation and the object creation time, and compute the actual HP based on the current time on the fly:
import time
class Player:
HP_LOSS_INTERVAL = 60
HP_LOSS_PER_INTERVAL = 10
def __init__(self, hp=1000):
self.base_hp = hp
self.birth_time = time.time()
def hp(self):
hp_loss = (time.time() - self.birth_time) // HP_LOSS_INTERVAL * HP_LOSS_PER_INTERVAL
return max(0, self.base_hp - hp_loss)
Here I did it with time.time(), probably in a game you want to use a timer based on your game loop ticks.

Running a Python web scraper every hour [duplicate]

I'm looking for a library in Python which will provide at and cron like functionality.
I'd quite like have a pure Python solution, rather than relying on tools installed on the box; this way I run on machines with no cron.
For those unfamiliar with cron: you can schedule tasks based upon an expression like:
0 2 * * 7 /usr/bin/run-backup # run the backups at 0200 on Every Sunday
0 9-17/2 * * 1-5 /usr/bin/purge-temps # run the purge temps command, every 2 hours between 9am and 5pm on Mondays to Fridays.
The cron time expression syntax is less important, but I would like to have something with this sort of flexibility.
If there isn't something that does this for me out-the-box, any suggestions for the building blocks to make something like this would be gratefully received.
Edit
I'm not interested in launching processes, just "jobs" also written in Python - python functions. By necessity I think this would be a different thread, but not in a different process.
To this end, I'm looking for the expressivity of the cron time expression, but in Python.
Cron has been around for years, but I'm trying to be as portable as possible. I cannot rely on its presence.
If you're looking for something lightweight checkout schedule:
import schedule
import time
def job():
print("I'm working...")
schedule.every(10).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("10:30").do(job)
while 1:
schedule.run_pending()
time.sleep(1)
Disclosure: I'm the author of that library.
You could just use normal Python argument passing syntax to specify your crontab. For example, suppose we define an Event class as below:
from datetime import datetime, timedelta
import time
# Some utility classes / functions first
class AllMatch(set):
"""Universal set - match everything"""
def __contains__(self, item): return True
allMatch = AllMatch()
def conv_to_set(obj): # Allow single integer to be provided
if isinstance(obj, (int,long)):
return set([obj]) # Single item
if not isinstance(obj, set):
obj = set(obj)
return obj
# The actual Event class
class Event(object):
def __init__(self, action, min=allMatch, hour=allMatch,
day=allMatch, month=allMatch, dow=allMatch,
args=(), kwargs={}):
self.mins = conv_to_set(min)
self.hours= conv_to_set(hour)
self.days = conv_to_set(day)
self.months = conv_to_set(month)
self.dow = conv_to_set(dow)
self.action = action
self.args = args
self.kwargs = kwargs
def matchtime(self, t):
"""Return True if this event should trigger at the specified datetime"""
return ((t.minute in self.mins) and
(t.hour in self.hours) and
(t.day in self.days) and
(t.month in self.months) and
(t.weekday() in self.dow))
def check(self, t):
if self.matchtime(t):
self.action(*self.args, **self.kwargs)
(Note: Not thoroughly tested)
Then your CronTab can be specified in normal python syntax as:
c = CronTab(
Event(perform_backup, 0, 2, dow=6 ),
Event(purge_temps, 0, range(9,18,2), dow=range(0,5))
)
This way you get the full power of Python's argument mechanics (mixing positional and keyword args, and can use symbolic names for names of weeks and months)
The CronTab class would be defined as simply sleeping in minute increments, and calling check() on each event. (There are probably some subtleties with daylight savings time / timezones to be wary of though). Here's a quick implementation:
class CronTab(object):
def __init__(self, *events):
self.events = events
def run(self):
t=datetime(*datetime.now().timetuple()[:5])
while 1:
for e in self.events:
e.check(t)
t += timedelta(minutes=1)
while datetime.now() < t:
time.sleep((t - datetime.now()).seconds)
A few things to note: Python's weekdays / months are zero indexed (unlike cron), and that range excludes the last element, hence syntax like "1-5" becomes range(0,5) - ie [0,1,2,3,4]. If you prefer cron syntax, parsing it shouldn't be too difficult however.
More or less same as above but concurrent using gevent :)
"""Gevent based crontab implementation"""
from datetime import datetime, timedelta
import gevent
# Some utility classes / functions first
def conv_to_set(obj):
"""Converts to set allowing single integer to be provided"""
if isinstance(obj, (int, long)):
return set([obj]) # Single item
if not isinstance(obj, set):
obj = set(obj)
return obj
class AllMatch(set):
"""Universal set - match everything"""
def __contains__(self, item):
return True
allMatch = AllMatch()
class Event(object):
"""The Actual Event Class"""
def __init__(self, action, minute=allMatch, hour=allMatch,
day=allMatch, month=allMatch, daysofweek=allMatch,
args=(), kwargs={}):
self.mins = conv_to_set(minute)
self.hours = conv_to_set(hour)
self.days = conv_to_set(day)
self.months = conv_to_set(month)
self.daysofweek = conv_to_set(daysofweek)
self.action = action
self.args = args
self.kwargs = kwargs
def matchtime(self, t1):
"""Return True if this event should trigger at the specified datetime"""
return ((t1.minute in self.mins) and
(t1.hour in self.hours) and
(t1.day in self.days) and
(t1.month in self.months) and
(t1.weekday() in self.daysofweek))
def check(self, t):
"""Check and run action if needed"""
if self.matchtime(t):
self.action(*self.args, **self.kwargs)
class CronTab(object):
"""The crontab implementation"""
def __init__(self, *events):
self.events = events
def _check(self):
"""Check all events in separate greenlets"""
t1 = datetime(*datetime.now().timetuple()[:5])
for event in self.events:
gevent.spawn(event.check, t1)
t1 += timedelta(minutes=1)
s1 = (t1 - datetime.now()).seconds + 1
print "Checking again in %s seconds" % s1
job = gevent.spawn_later(s1, self._check)
def run(self):
"""Run the cron forever"""
self._check()
while True:
gevent.sleep(60)
import os
def test_task():
"""Just an example that sends a bell and asd to all terminals"""
os.system('echo asd | wall')
cron = CronTab(
Event(test_task, 22, 1 ),
Event(test_task, 0, range(9,18,2), daysofweek=range(0,5)),
)
cron.run()
None of the listed solutions even attempt to parse a complex cron schedule string. So, here is my version, using croniter. Basic gist:
schedule = "*/5 * * * *" # Run every five minutes
nextRunTime = getNextCronRunTime(schedule)
while True:
roundedDownTime = roundDownTime()
if (roundedDownTime == nextRunTime):
####################################
### Do your periodic thing here. ###
####################################
nextRunTime = getNextCronRunTime(schedule)
elif (roundedDownTime > nextRunTime):
# We missed an execution. Error. Re initialize.
nextRunTime = getNextCronRunTime(schedule)
sleepTillTopOfNextMinute()
Helper routines:
from croniter import croniter
from datetime import datetime, timedelta
# Round time down to the top of the previous minute
def roundDownTime(dt=None, dateDelta=timedelta(minutes=1)):
roundTo = dateDelta.total_seconds()
if dt == None : dt = datetime.now()
seconds = (dt - dt.min).seconds
rounding = (seconds+roundTo/2) // roundTo * roundTo
return dt + timedelta(0,rounding-seconds,-dt.microsecond)
# Get next run time from now, based on schedule specified by cron string
def getNextCronRunTime(schedule):
return croniter(schedule, datetime.now()).get_next(datetime)
# Sleep till the top of the next minute
def sleepTillTopOfNextMinute():
t = datetime.utcnow()
sleeptime = 60 - (t.second + t.microsecond/1000000.0)
time.sleep(sleeptime)
I know there are a lot of answers, but another solution could be to go with decorators. This is an example to repeat a function everyday at a specific time. The cool think about using this way is that you only need to add the Syntactic Sugar to the function you want to schedule:
#repeatEveryDay(hour=6, minutes=30)
def sayHello(name):
print(f"Hello {name}")
sayHello("Bob") # Now this function will be invoked every day at 6.30 a.m
And the decorator will look like:
def repeatEveryDay(hour, minutes=0, seconds=0):
"""
Decorator that will run the decorated function everyday at that hour, minutes and seconds.
:param hour: 0-24
:param minutes: 0-60 (Optional)
:param seconds: 0-60 (Optional)
"""
def decoratorRepeat(func):
#functools.wraps(func)
def wrapperRepeat(*args, **kwargs):
def getLocalTime():
return datetime.datetime.fromtimestamp(time.mktime(time.localtime()))
# Get the datetime of the first function call
td = datetime.timedelta(seconds=15)
if wrapperRepeat.nextSent == None:
now = getLocalTime()
wrapperRepeat.nextSent = datetime.datetime(now.year, now.month, now.day, hour, minutes, seconds)
if wrapperRepeat.nextSent < now:
wrapperRepeat.nextSent += td
# Waiting till next day
while getLocalTime() < wrapperRepeat.nextSent:
time.sleep(1)
# Call the function
func(*args, **kwargs)
# Get the datetime of the next function call
wrapperRepeat.nextSent += td
wrapperRepeat(*args, **kwargs)
wrapperRepeat.nextSent = None
return wrapperRepeat
return decoratorRepeat
I like how the pycron package solves this problem.
import pycron
import time
while True:
if pycron.is_now('0 2 * * 0'): # True Every Sunday at 02:00
print('running backup')
time.sleep(60) # The process should take at least 60 sec
# to avoid running twice in one minute
else:
time.sleep(15) # Check again in 15 seconds
There isn't a "pure python" way to do this because some other process would have to launch python in order to run your solution. Every platform will have one or twenty different ways to launch processes and monitor their progress. On unix platforms, cron is the old standard. On Mac OS X there is also launchd, which combines cron-like launching with watchdog functionality that can keep your process alive if that's what you want. Once python is running, then you can use the sched module to schedule tasks.
Another trivial solution would be:
from aqcron import At
from time import sleep
from datetime import datetime
# Event scheduling
event_1 = At( second=5 )
event_2 = At( second=[0,20,40] )
while True:
now = datetime.now()
# Event check
if now in event_1: print "event_1"
if now in event_2: print "event_2"
sleep(1)
And the class aqcron.At is:
# aqcron.py
class At(object):
def __init__(self, year=None, month=None,
day=None, weekday=None,
hour=None, minute=None,
second=None):
loc = locals()
loc.pop("self")
self.at = dict((k, v) for k, v in loc.iteritems() if v != None)
def __contains__(self, now):
for k in self.at.keys():
try:
if not getattr(now, k) in self.at[k]: return False
except TypeError:
if self.at[k] != getattr(now, k): return False
return True
I don't know if something like that already exists. It would be easy to write your own with time, datetime and/or calendar modules, see http://docs.python.org/library/time.html
The only concern for a python solution is that your job needs to be always running and possibly be automatically "resurrected" after a reboot, something for which you do need to rely on system dependent solutions.

Change Python Class Variable Value

I am extremely new to Python (coming from JavaScript) and I am battling with understanding how to change a value of a class variable. All I am trying to do is to change the age value, and then display the new msg. But when I add Tester.age = 20 it doesn't change my msg output. My msg output still uses age = 10.
How do I change a class variable externally?
class ClassTester:
age = 10
seconds = age * 365 * 24 * 60 * 60
msg = "You have lived for " + str(seconds) + " seconds."
Tester = ClassTester()
Tester.age = 20
print(Tester.msg)
I recommend using properties, so your interface would not change.
class ClassTester:
def __init__(self):
self._age = 10
self._msg = "You have lived for {} seconds."
self._secs = self._seconds(self._age)
#staticmethod
def _seconds(age):
return age * 365 * 24 * 60 * 60
#property
def age(self):
return self._age
#age.setter
def age(self, v):
self._age = v
self._secs = self._seconds(v)
#property
def msg(self):
return self._msg.format(self._secs)
Tester = ClassTester()
print(Tester.msg) # You have lived for 315360000 seconds.
Tester.age = 20
print(Tester.msg) # You have lived for 630720000 seconds.
EDIT:
I added a static method to recalculate the seconds value and call that from the __init__ and the age setter to reduce recalculations as per the OP's concern about those in the comment to another answer
age is the static class variable
You can directly access the age variable using Class name
>>ClassTester.age=20
>>ClassTester.age
>>20
Static class variables in Python
The solution is to set the variables in an object-level (not class-level). You do this by creating the variables inside the init area like below. You can then change the values externally.
Then you need to calculate whatever you want in a different function, using that variable. Then just call that function where you need it.
VERY IMPORTANT (the mistake I made): The init is written with TWO underscores _ x 2 on each side
class ClassTester:
def __init__(self):
self.age = 10
def msg(self):
self.seconds = self.age * 365 * 24 * 60 * 60
self.txt = "You have lived for " + str(self.seconds) + " seconds."
return self.txt
Tester = ClassTester()
Tester.age = 20
print(Tester.msg())
Tester.age = 30
print(Tester.msg())
You are doing it wrong,
you define msg var as an attribute to the class, and it has been evaluated once, (when you instance the class) and no more change,
so when you call:
print(Tester.msg)
you are getting the first value,
what actully is nearest to your work is just make msg into method, simply:
class ClassTester:
age = 10
seconds = self.age * 365 * 24 * 60 * 60
msg = "You have lived for " + str(seconds) + " seconds."
def get_msg(self):
seconds = self.age * 365 * 24 * 60 * 60
self.msg = "You have lived for " + str(seconds) + " seconds."
Tester = ClassTester()
Tester.age = 20
Tester.get_msg()
print(Tester.msg)
First, as was pointed out in comments, you should declare variables in __init__ constructor. As to your example, I'd suggest to make some more advanced steps, so consider following: you actually have only one important variable, which is self.age. Everything else is derived from it, and so you can lose consistency: for example, when changing self.age another variables will not be changed. Also, you can later on in your project change self.seconds variable, thus completely messing up your class instance. To solve that, have a look at property decorator:
class ClassTester:
def __init__(self, age=10):
self.age = age
#property
def seconds(self):
return self.age * 365 * 24 * 60 * 60
#property
def msg(self):
return "You have lived for {} seconds.".format(self.seconds)
There, #property is a handy decorator, which allows you to do address seconds and msg as attributes, but which will be always synced and consistent: first, you cannot set seconds attribute, thus it is protected. Second, changing age will affect all subsequent calls to msg and seconds.
Example usage:
>>> tester = ClassTester()
>>> tester.seconds
315360000
>>> tester.msg
'You have lived for 315360000 seconds.'
>>> tester.age = 23
>>> tester.seconds
725328000
>>> tester.msg
There is a lot more about #property, feel free to explore! For example, see this answer for some in-depth #property analysis.
Old question, but still deserves a new answer.
It seems that what the OP wanted was to somehow change the value of a class variable in a way that the change could be felt by all objects of the class.
You can´t do it directly changing the value of the class variable, but if the value of the class variable is a mutable object then you can change the content of that object instead and the change will be seem by all instances of the class.
class A:
my_magic = dict()
a = A()
b = A()
c = A()
a.my_magic['x'] = "something"
b.my_magic['y'] = "other thing"
print(c.my_magic)
results
{'x': 'something', 'y': 'other thing'}

calling a method inside a class-Python

class Time:
def __init__(self,x,y,z):
self.hour=x
self.minute=y
self.second=z
def __str__(self):
return "({:02d}:{:02d}:{:02d})".format(self.hour, self.minute, self.second)
def time_to_int(time):
minutes=time.hour*60+time.minute
seconds=minutes*60+time.second
return seconds
def int_to_time(seconds):
time=Time()
minutes,time.second=divmod(seconds,60)
time.hour,time.minute=divmod(minutes,60)
return time
def add_time(t1,t2):
seconds=time_to_int(t1)+time_to_int(t2)
return int_to_time(seconds)
start=Time(9,45,00)
running=Time(1,35,00)
done=add_time(start,running)
print(done)
I am new to python and i've been doing some practice lately.I came across a question and i've written the code for the same.But I am repeatedly getting an error: "add_time is not defined". I tried defining a main() method but then it doesn't print anything.Please help.
You haven't created an object to the above class.
Any function/method inside a class can only be accessed by an object of that class .For more information on the fundamentals of Object Oriented Programming, please check this page.
Meanwhile for this to work, define your class in the following way :
class Time:
def __init__(self,x=None,y=None,z=None):
self.hour=x
self.minute=y
self.second=z
def __str__(self):
return "({:02d}:{:02d}:{:02d})".format(self.hour, self.minute, self.second)
def time_to_int(time):
minutes=time.hour*60+time.minute
seconds=minutes*60+time.second
return seconds
def int_to_time(seconds):
time=Time()
minutes,time.second=divmod(seconds,60)
time.hour,time.minute=divmod(minutes,60)
return time
def add_time(t1,t2):
seconds=time_to_int(t1)+time_to_int(t2)
return int_to_time(seconds)
and outside the class block, write the following lines :
TimeObject = Time()
start=Time(9,45,00)
running=Time(1,35,00)
TimeObject.add_time(start,running)
print "done"
I however suggest you to write the add_time function outside the class because you are passing the objects to the class as the parameters to the function within the same class and it is considered as a bad design in object oriented programming.
Hope it helps. Cheers!
This works fine for me as long as you specified 3 args in your constructor
def int_to_time(seconds):
time=Time(0,0,0) # just set your 3 positionals args here
minutes,time.second=divmod(seconds,60)
time.hour,time.minute=divmod(minutes,60)
return time
Another way to avoid it could be:
class Time:
def __init__(self,x=0,y=0,z=0):
self.hour=x
self.minute=y
self.second=z
If you want to add your functions to your class (such as time_to_int, int_to_time or even add_time) then you will need to indent with one more level of 4 spaces and add self to your method parameters
Hii Mathers25,
I solve your problem try this below code to get the best output,
class TimeClass:
def __init__(self,x,y,z):
self.hour = x
self.minute = y
self.second = z
def __str__(self):
return "({:02d}:{:02d}:{:02d})".format(self.hour, self.minute, self.second)
def time_to_int(self,time):
minutes = (time.hour * 60) + time.minute
seconds = (minutes * 60) + time.second
return seconds
def int_to_time(self,seconds):
time = TimeClass(0,0,0)
minutes,time.second=divmod(seconds,60)
time.hour,time.minute=divmod(minutes,60)
return time
def add_time(self,t1,t2):
seconds = self.time_to_int(t1) + self.time_to_int(t2)
# Call method int_to_time() using self keyword.
return self.int_to_time(seconds)
# First time object create that time set value is 0 of hour,minute and second
TimeObject = TimeClass(0,0,0)
# After create second object
start=TimeClass(9,45,00)
# After create thired Object
running=TimeClass(1,35,00)
# Store the value which return by add_time()
done = TimeObject.add_time(start,running)
# Display the value of done variable
print(done)
class Employee:
def __init__(self):
self.wage = 0
self.hours_worked = 0
def calculate_pay(self):
return self.wage * self.hours_worked
alice = Employee()
alice.wage = 9.25
alice.hours_worked = 35
print('Alice:\n Net pay: {:.2f}'.format(alice.calculate_pay()))
barbara = Employee()
barbara.wage = 11.50
barbara.hours_worked = 20
print('Barbara:\n Net pay: {:.2f}'.format(barbara.calculate_pay()))
Works for me:
class C:
def f(a, b):
return a + b
x = f(1,2)
print(C.x)
but you should not do such things. Code in class-level is executing when class is "creating", usually you want static methods or class methods (decorated with #staticmethod or #classmethod) and execute code in some function/instantiated class. Also you can execute it on top (module) level if this is the simple script. Your snippet is "bad practice": class level (i'm talking about indentation) is for declarations, not for execution of something. On class-level is normal to execute code which is analogue of C macros: for example, to call decorator, to transform some method/attribute/etc - static things which are "pure" functions!

Transfer variable between Python module

For example, I have a file called "gui.py", which uses a module, which is called "pytime.py".
They are in the same directory.
The module (time.py) code has two functions: settime() and readtime()
gui.py code looks like:
import pytime
pytime.settime(16,40) #set hour to 16:40
Now, I want that the other function in the pytime module (readtime()) could access the hour.
I tried "global" but it didn't helped, and also googled a lot.
Thanks!
if you want shared state between the functions, the best way to do this would probably be a class:
# pytime.py
class PyTime(object):
def __init__(self, hour=0, minute=0):
self._hour = hour
self._minute = minute
def set_time(self, hour=None, minute=None):
if hour is not None:
self._hour = hour
if minute is not None:
self._minute = minute
def read_time(self):
return self._hour, self._minute
def __str__(self):
return "{0._hour:02d}:{0._minute:02d}".format(self)
#property
def hour(self):
return self._hour
#property
def minute(self):
return self._minute
In use:
>>> timer = PyTime()
>>> timer.set_time(16, 40)
>>> timer.read_time()
(16, 40)
>>> timer.hour
16
>>> str(timer)
'16.40'
>>> timer.set_time(minute=30)
>>> str(timer)
'16:30'
>>> timer.hour = 15
Traceback (most recent call last):
File "<pyshell#25>", line 1, in <module>
timer.hour = 15
AttributeError: can't set attribute
Note this last result - as I define a property getter for hour but no setter, hour is immutable (although a determined user can access _hour directly).
You could pass in the variable into the function as such:
pytime.py:
def settime(hour, minute):
return str(hour)+':'+str(minute)
def readtime(hour):
print 'This is the hour: {0}'.format(hour)
gui.py:
import pytime
hour = pytime.settime(16, 40)
pytime.readtime(hour)
This runs as:
bash-3.2$ python gui.py
This is the hour: 16:40
bash-3.2$

Categories

Resources