Accept a single string instead of normal parameters - python

Hello everyone I have a class that works with time, for example you enter two times and you can sum them (for now it doesn't matter that it goes beyond 23:59:59) or multiply them etc. The default input are zeros. There is also a function that returns current time. I can call time = Time() which returns 0:00:00, time = Time(12) returns 12:00:00.
The problem that I have is, I want to call time = Time('now') and it should store there current time using function now(), edits should be done in __init__() (if you don't like now() you can change it). But if i put time_now = '' as first parameter it doesn't work, same when i put it as a last, because when I write time = Time('now') it takes string 'now' and wants to put it to hours.
I know there are time modules which can do this, but this is for learning purposes.
My code:
import random, time
class Time:
def __init__(self, hours=0, minutes=0, seconds=0, time_now=''):
# if time_now == 'now':
# now()
time = abs(3600*hours + 60*minutes + seconds)
self.hour = time//3600
self.min = time//60%60
self.sec = time%60
def __repr__(self):
return '{}:{:02}:{:02}'.format(self.hour,self.min,self.sec)
def __add__(self, other):
if isinstance(other, Time):
return Time(self.hour+other.hour, self.min+other.min, self.sec+other.sec)
if isinstance(other, int):
return Time(self.hour, self.min, self.sec+other)
__radd__ = __add__
def __sub__(self, other):
return Time(seconds = self.__int__() - other.__int__())
def __mul__(self, other):
return Time(self.hour*other.hour, self.min*other.min, self.sec*other.sec)
def __int__(self):
return 3600*self.hour + 60*self.min + self.sec
def __eq__(self, other):
return self.__int__() == other.__int__()
def __lt__(self, other):
return self.__int__() < other.__int__()
#writing out hour/min/sec what we want
def __getitem__(self, key):
if key == 0:
return self.hour
if key == 1:
return self.min
if key == 2:
return self.sec
#time now
def now():
a=(time.localtime()[3:6])
return Time(a[0],a[1],a[2])

Python doesn't have method overloading, so your only option is to "play" with the arguments:
You can do something that IMHO is very bad (downgraded very bad to meeeeh... so, so after reading #ivan-pozdeev's comments in this answer)
class Time:
def __init__(self, hours=0, minutes=0, seconds=0, time_now=''):
if hours == 'now':
tmp_t = now()
self.hour = tmp_t.hour
self.min = tmp_t.min
self.sec = tmp_t.sec
else:
t = abs(3600*hours + 60*minutes + seconds)
self.hour = t//3600
self.min = t//60%60
self.sec = t%60
That... well, that works:
>>> a = Time('now')
>>> print vars(a)
{'sec': 20, 'hour': 15, 'min': 18}
>>>
>>> a = Time(hours=19, minutes=4, seconds=5)
>>> print vars(a)
{'sec': 5, 'hour': 19, 'min': 4}
But that leaves the code in a very weird state. Is very difficult to read. I certainly would try to come with a different approach altogether...
I also changed the time variable within the __init__ to t because that conflicted with the time name from import time

You can use a call with named parameters: Time(time_now='now'), but that looks too reiterative.
If I was using named parameters, I'd instead change it to a boolean and use something like Time(now=True), which looks a bit cleaner.
But I think a better alternative is to make your "now" objects be constructed from your now() function, which I'd move to a static method:
class Time(object):
#...
#classmethod
def now(cls):
a=(time.localtime()[3:6])
return cls(a[0],a[1],a[2])
So you'd construct your now objects like x = Time.now() instead of x = Time('now')

For flexible argument handling beyond what's available with static arguments, you may use *args and/or **kwargs:
def __init__(self, *args, **kwargs):
a_seq=('hours','minutes','seconds')
if len(args)>0 and args[0]=='now':
now_=now()
self.__dict__.update(a,getattr(now_,a) for a in a_seq)
else:
t=0
for i,a in enumerate(a_seq):
try: v=args[i]
except IndexError: v=kwargs.get(a,0)
else: if a in kwargs: raise TypeError("multiple values given for argument `%s'"%a)
t+=v
t*=60
for a in a_seq[-1:0:-1]:
setattr(self,a,t%60)
t//=60
setattr(self,a_seq[0],t)
(I renamed the fields to the same names as arguments to make it easier to use reflection. Reflection is used here to eliminate code duplication (without it, it'd be about 1.5 times longer).)
In this particular case, though, BorrajaX's solution is much simpler because the deviation from a normal static argument list here is only minor (in fact, the try-except-else in the 2nd half of my code do nothing but emulate it).

Almost never try to implement your own time module. It's time consuming and defective. Use time or datetime. All your needs are already implemented somehow.

Related

Detect the last inline method call of a class

Let's say we have a python class with methods intended to be called one or more times inline. My goal is to make methods behave differently when they are invoked last in an inline chain of calls.
Example:
class InlineClass:
def __init__(self):
self.called = False
def execute(self):
if self.called:
print('do something with awareness of prior call')
return self
else:
print('first call detected')
self.called = True
return self
def end(self):
print ('last call detected, do something with awareness this is the last call')
self.called = False
return self
x = InlineClass()
x.execute().execute().execute().end() # runs 3 execute calls inline and end.
The example above only knows it has reached the last inline call once the end method is invoked. What I would like to do, in essence, is to make that step redundant
QUESTION
Keeping in mind the intent for this class's methods to always be called one or more times inline, is there an elegant way to format the class so it is aware it has reached its last inline method call, and not necessitate the end call as in the example above.
Instead of chaining the functions, you can try creating a function that handles passing different parameters depending on how many times the function has been / will be called.
Here is some example code:
class Something:
def repeat(self, function, count):
for i in range(count):
if i == 0:
function("This is the first time")
elif i == count - 1:
function("This is the last time")
else:
function("This is somewhere in between")
def foo_function(self, text):
print(text)
foo = Something()
foo.repeat(foo.foo_function, 5)
foo.repeat(foo.foo_function, 2)
foo.repeat(foo.foo_function, 6)
foo.repeat(foo.foo_function, 8)
Output:
This is the first time
This is somewhere in between
This is somewhere in between
This is somewhere in between
This is the last time
This is the first time
This is the last time
This is the first time
This is somewhere in between
This is somewhere in between
This is somewhere in between
This is somewhere in between
This is the last time
This is the first time
This is somewhere in between
This is somewhere in between
This is somewhere in between
This is somewhere in between
This is somewhere in between
This is somewhere in between
This is the last time
You need to return modified copies instead of self, here is the example with behaviour you described:
class InlineClass:
def __init__(self, counter=0):
self.counter = counter
def execute(self):
return InlineClass(self.counter+1)
def __str__(self):
return f'InlineClass<counter={self.counter}>'
x = InlineClass()
print(x)
# => InlineClass<counter=0>
y = x.execute().execute().execute()
print(y)
# => InlineClass<counter=3>
print(x.execute().execute().execute())
# => InlineClass<counter=3>
print(y.execute().execute().execute())
# => InlineClass<counter=6>

Python possible to short circuit function call

I am building a function to construct objects with set attributes (similar to a namedtuple); however, the output length must be variable.
I would like to build a function that allows the user to append additional attributes through a function call. Importantly, I would like to find a way to 'short-circuit' parameters and am unsure if Python is powerful enough to do this.
To explain take this trivial example:
def foo():
print("foo")
return False
def bar():
print("bar")
return True
if foo() and bar():
pass
Foo's function call returns False, and Bar short-circuits. The output console will only print foo, and bar is never executed.
Is there such a way to mimic this behavior with inspection or reflection in respect to function calls. Here is an example with my implementation is shown below:
from inspect import stack
cache = {}
def fooFormat(**kwargs):
caller = stack()[1][3]
if caller not in cache:
class fooOut(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def optional(self, opt, **kwargs):
if (opt):
self.__dict__.update(kwargs)
return self
def __str__(self):
return caller + str(self.__dict__)
cache[caller] = iadsOut
return cache[caller](**kwargs)
def stdev(nums, avg = None):
print("\tStdev call")
if avg is None:
avg = sum(nums) / len(nums)
residuals = sum((i - avg)**2 for i in nums)
return residuals**.5
def stats(nums, verbose=False):
if verbose:
print("Stats call with verbose")
else:
print("Stats call without verbose")
total = sum(nums)
N = len(nums)
avg = total / N
return fooFormat(
avg = avg,
lowerB = min(nums),
upperB = max(nums)).optional(verbose,
stdev = stdev(nums, avg))
In the function 'stats', the return fooFormat should of course yield avg, lowerB, and upperB; additionally, it should yield std if verbose is set to True. Moreover, the function 'stdev' should NOT be called if verbose is set to False.
stats([1,2,3,4], False)
stats([1,2,3,4], True)
Of course, a way around this is:
if verbose:
return fooFormat(
avg = avg,
lowerB = min(nums),
upperB = max(nums),
stdev = stdev(nums, avg))
else:
return fooFormat(
avg = avg,
lowerB = min(nums),
upperB = max(nums))
However, I am hoping there to implement this behavior without a branch.
This doesn't quite answer the shortcutting point, but this is a more efficient way of writing it:
out_dic = { # these items will always be calculated
'avg': avg,
'lowerB':max(nums),
'upperB':min(nums)
}
if verbose: # this is calculated only if verbose
out_dic['stdev'] = stdev(nums,avg)
return fooFormat(**out_dic)
In other words you can expand a dictionary to the kwargs, and add to the dictionary dynamically.

Is there something like the threading macro from Clojure in Python?

In Clojure I can do something like this:
(-> path
clojure.java.io/resource
slurp
read-string)
instead of doing this:
(read-string (slurp (clojure.java.io/resource path)))
This is called threading in Clojure terminology and helps getting rid of a lot of parentheses.
In Python if I try to use functional constructs like map, any, or filter I have to nest them to each other. Is there a construct in Python with which I can do something similar to threading (or piping) in Clojure?
I'm not looking for a fully featured version since there are no macros in Python, I just want to do away with a lot of parentheses when I'm doing functional programming in Python.
Edit: I ended up using toolz which supports pipeing.
Here is a simple implementation of #deceze's idea (although, as #Carcigenicate points out, it is at best a partial solution):
import functools
def apply(x,f): return f(x)
def thread(*args):
return functools.reduce(apply,args)
For example:
def f(x): return 2*x+1
def g(x): return x**2
thread(5,f,g) #evaluates to 121
I wanted to take this to the extreme and do it all dynamically.
Basically, the below Chain class lets you chain functions together similar to Clojure's -> and ->> macros. It supports both threading into the first and last arguments.
Functions are resolved in this order:
Object method
Local defined variable
Built-in variable
The code:
class Chain(object):
def __init__(self, value, index=0):
self.value = value
self.index = index
def __getattr__(self, item):
append_arg = True
try:
prop = getattr(self.value, item)
append_arg = False
except AttributeError:
try:
prop = locals()[item]
except KeyError:
prop = getattr(__builtins__, item)
if callable(prop):
def fn(*args, **kwargs):
orig = list(args)
if append_arg:
if self.index == -1:
orig.append(self.value)
else:
orig.insert(self.index, self.value)
return Chain(prop(*orig, **kwargs), index=self.index)
return fn
else:
return Chain(prop, index=self.index)
Thread each result as first arg
file = Chain(__file__).open('r').readlines().value
Thread each result as last arg
result = Chain(range(0, 100), index=-1).map(lambda x: x * x).reduce(lambda x, y: x + y).value

Decrementing Function Arguments (PYTHON)

I'm calling functions similar to those that follow, inside a loop:
def bigAnim(tick,firstRun):
smallAnim(x,y,duration)
#more anims and logic...
def smallAnim(x, y,duration):
duration -= 1
if duration != 0:
Anim.blit(screen,(x ,y))
Anim.play()
else:
Anim.stop()
loopedOnce = True
return loopedOnce
Now say I were to call the smallAnim inside the big anim as follows:
def bigAnim(tick,firstRun):
smallAnim(0,50,5)
smallAnim is now being called indefinitely, as duration will never go lower than 4 (being reset to 5 every time it's called in the loop). What would be the best way to solve this problem?
You need to do the counting in bigAnim and only call smallAnim() when the value is greater than zero.
Or you can return the current duration:
def bigAnim(tick,firstRun):
duration = smallAnim(x,y,duration)
#more anims and logic...
def smallAnim(x, y, duration):
duration -= 1
if duration > 0:
Anim.blit(screen,(x ,y))
Anim.play()
return duration
Your underlying problem is Python does pass the references to the variables, but integers are immutable.
This is a little easier to understand with strings:
The function
def foo(s):
s = " world"
will only modify s local to the function if you call foo("hello"). The typical pattern you'll see instead is:
def foo(s):
return s + " world"
And then ... print foo("hello")

Checking if function was not called for x amount of time

I didn't find this kind of question anywhere so I'm going to ask it here.
How can I check if some specific function written by me wasn't called for some x amount of time?
You could embed the last called time in the function definition:
def myfun():
myfun.last_called = datetime.now()
# … do things
From this point it should be easy to tell when the function was called. Each time it's called it will update its last_called timestamp.
A more general approach would be to define a function decorator to attach the property:
def remembercalltimes(f, *args, **kwargs):
"""A decorator to help a function remember when it was last called."""
def inner(*args, **kwargs):
inner.last_called = datetime.now()
return f(*args, **kwargs)
return inner
#remembercalltimes
def myfun():
# … do things
>>> myfun()
>>> myfun.last_called
>>> datetime.datetime(2014, 3, 19, 11, 47, 5, 784833)
import time
last_time_f_called = time.time()
def f():
global last_time_f_called
now = time.time()
time_since = now - last_time_f_called
last_time_f_called = now
# do whatever you wanted to do about value of time_since
Something like that?
You could probably wrap that in a decorator that updated times in a dict, where key was the function name, if it was the sort of thing you wanted to do a lot...
This seems like a reasonable time to plop that info in the function's __dict__, maybe with a decorator.
def lastcalled(func):
def inner():
from datetime import datetime
then = func.__dict__.get('lastcalled')
diff = int((datetime.now() - then ).total_seconds()) if then else None
print('Last called: {}'.format('{} sec ago'.format(diff) if diff else 'Never'))
func()
func.lastcalled = datetime.now()
return inner
demo:
#lastcalled
def f():
print('printing in f()')
f()
Last called: Never
printing in f()
#wait 5 seconds
f()
Last called: 5 sec ago
printing in f()

Categories