New to python, so I have this setup where I file gets created, and I have to add an extension number. The first file will have an extension number of 1 since being the first. A second file gets created and the extension number will increment, so it will be 2. So each files gets created, the extension number will increment.
Now, if it's a different day then that extension number will reset to 1, and it will increment if new files are created. So each day, the extension number needs to be reset to 1
def get_counter(date):
counter = 1
now = datetime.datetime.utcnow().strftime('%Y-%m-%d')
if date != now:
now = date
counter = 1
return counter
counter += 1
return counter
I have set up this function but it will not work because the now and counter variable will get overwritten. So will need these variables somewhere else. Just wondering if there is a work around this process or is there a python library that can handle this type of situation. Your suggestions will be appreciated!
You could assign the counter outside of that function and send it as a parameter, that way you don't overwrite it every single time you call your function, like so:
counter = 1
for file_to_be_writen in file_collection:
counter = get_counter(date, counter)
and leave your function like this:
def get_counter(date, counter):
now = datetime.datetime.utcnow().strftime('%Y-%m-%d')
if date == now:
counter += 1
return counter
return counter
When you need to preserve state across function calls that is a hint that you need a custom object. You could use global variables as well but encapsulating the state inside an object is usually better.
Here I implement a class Counter that takes care of everything. It has a __next__ method that returns the next number so the calling code only needs to call next(counter). It also has an __iter__ method so it can be used in for loops.
You need to provide a function to get the current (date_getter) time when creating an instance. Besides making the code more testable this allows you to decide if you want to use utc time, local time, the first day of the week so the counter resets each week, etc.
import datetime
class TimeArrowReversedError(Exception):
pass
class Counter:
def __init__(self, date_getter):
self._date_getter = date_getter
self._current_date = date_getter()
self._current_value = 0
def _check_date(self):
current_date = self._date_getter()
if self._current_date > current_date:
message = 'Time arrow got reversed. Abandon all hope.'
raise TimeArrowReversedError(message)
if self._current_date < current_date:
self._current_date = current_date
self._current_value = 0
def __next__(self):
self._check_date()
self._current_value += 1
return self._current_value
def __iter__(self):
return self
This is the code I used to test it. Note that I am using as date_getter a function that actually returns whatever date I want. I do not want to wait until 23:59 to run the test. Instead I tell the function which date to return (including going backwards in time) and see how the counter behaves.
current_date = datetime.date(year=2018, month=5, day=9)
get_current_date = lambda: current_date
counter = Counter(get_current_date)
n = next(counter)
assert n == 1
n = next(counter)
assert n == 2
for expected, result in zip([3, 4], counter):
assert expected == result
current_date = current_date + datetime.timedelta(days=1)
n = next(counter)
assert n == 1
n = next(counter)
assert n == 2
current_date = current_date - datetime.timedelta(days=2)
try:
n = next(counter)
except TimeArrowReversedError:
pass
else:
raise AssertionError('"TimeArrowReversedError" expected.')
Here is a more realistic way in which yo could use this class:
def create_counter():
return Counter(datetime.datetime.utcnow().date)
counter = create_counter()
Print the first couple of numbers:
print(next(counter))
print(next(counter))
Output:
1
2
Using a loop to add numbers to names in a list:
names = ['foo', 'bar']
for name, n in zip(names, counter):
print('{}_{}'.format(name, n))
Output:
foo_3
bar_4
Now I realize that Counter is a really bad choice because there is already a completely unrelated Counter class in the standard library. But I cannot think of a better name right now so I will leave it as is.
Related
def solver():
empty_cell = empty_square()
counter = 0
if not empty_cell:
return True
i,j = empty_cell[0],empty_cell[1]
for num in range(1,10):
counter += 1
if constraint_check(num,i,j):
sudoku[i][j] = num
if solver():
return True
else:
sudoku[i][j] = 0
return False
Given the code above, how would I implement a counter to count how many iterations the recursive part of the function makes? As can be seen in the code I have attempted something above but I was not able to retrieve this variable to print it out and record the number.
set counter as function parameter -> solver(counter=1)
then when calling it again within your function add +1 -> solver(counter+1)
So I just started working in a new codebase and I'm trying to help refactor some stuff. There's things like huge methods that should be splitted into chunks and so on. There's this method A that does the exact same thing as method B, with a small difference.
Let's say method A is:
def func_a(data):
# Do some stuff...
obj = get_obj_from(data)
value = 0
# Somewhere inside a loop
for item in items:
value += item.value_a
obj.attribute_a = value
# Do some other stuff...
And method B is:
def func_b(data):
# Do same stuff as func_a()...
obj = get_obj_from(data)
value = 0
count = 0
# Somewhere inside a loop that does the same as in func_a()
for item in items:
value += item.value_b
count += 1
obj.attribute_b = value
avg = value / count
# Do some other stuff just as in func_a()...
Please notice how when assigning to the obj, a different attribute is used for each method. This gets me to the point where I don't know if the right thing is to keep both methods and just extract the things that are similar. I've been trying so hard to somehow just make it into method that can do both but can't quite get it.
You can combine both methods, but you will need to pass a variable(like flag) to identify flow - to go with a or b. Like below
def func_ab(data, is_a=True):
obj = get_obj_from(data)
value = 0
count = 0
for item in items:
if is_a:
value += item.value_a
else:
value += item.value_b
count += 1
if is_a:
obj.attribute_a = value
else:
obj.attribute_b = value
avg = value / count
is_a has default value of True so while calling this function for a you can call as func_ab(data) and while calling for b func_ab(data, False)
Hope this helps!
You can further refactor:
def func_ab(data, is_a=True):
obj = get_obj_from(data)
if is_a:
obj.attribute_a = sum([item.value_a for item in items])
else:
obj.attribute_b = sum([item.value_b for item in items])
avg = obj.attribute_b / len(items)
You can make use of some of the builtins like getattr and setattr.
def func(data, att_key='a'):
obj = get_obj_from(data)
att_name = f'attribute_{att_key}'
value_name = f'value_{att_key}'
# sets the obj.{att_name} to the sum of the item.{value_name}
setattr(obj, att_name, sum([getattr(item, value_name) for item in items]) )
if att_key == 'b':
avg = obj.attribute_b / len(items)
This is flexible to handle additional cases if you have more than just 'a' and 'b' to worry about.
So the title is pretty self explanatory, but i'll go into more detail. I am creating a text dependent game and I will have millions of areas. And each time you enter a new area, you will be greeted with a one time only different reaction than if you came into the same place again later, and I need to find a way to to this:
if len(line) == 1:
do exclusive thing
else:
do normal thing
Sure, I could use a counter system like "a = 0" but then I would need to create a separate counter for every single area I create, and I don't want that.
You could just store a single dict to keep track of room visits, and probably even better to use a defaultdict
from collections import defaultdict
#Using a defaultdict means any key will default to 0
room_visits = defaultdict(int)
#Lets pretend you had previously visited the hallway, kitchen, and bedroom once each
room_visits['hallway'] += 1
room_visits['kitchen'] += 1
room_visits['bedroom'] += 1
#Now you find yourself in the kitchen again
current_room = 'kitchen'
#current_room = 'basement' #<-- uncomment this to try going to the basement next
#This could be the new logic:
if room_visits[current_room] == 0: #first time visiting the current room
print('It is my first time in the',current_room)
else:
print('I have been in the',current_room,room_visits[current_room],'time(s) before')
room_visits[current_room] += 1 #<-- then increment visits to this room
You need static var : What is the Python equivalent of static variables inside a function?
def static_var(varname, value):
def decorate(func):
setattr(func, varname, value)
return func
return decorate
#static_var("counter", 0)
def is_first_time():
is_first_time.counter += 1
return is_first_time.counter == 1
print(is_first_time())
print(is_first_time())
print(is_first_time())
We have to use a previously made function (the mega_calculator) to calculate the average amount of property damage for 10 buildings. however, we need to find out which building is going to be the most destroyed, but we keep getting error messages about comparing functions to ints. for some reason, the y variable(used to store mega_calculator values) is being labeled as a function, and the if statements aren't being triggered.
We are trying to use a for loop but it doesn't change anything. We also tried asserting inside mega_calculator that the return value must be an integer type, but that didn't do anything. we tried saving the average value as a variable and asserting that as an integer type but that didn't do anything.
What should I do for that?
Any help is loved and appreciated greatly. We must have the weird function setup, so unfortunately I can't just make a nice simple while loop.
def mega_calculator(fn, repeat=1000):
def helper(*args):
total = 0
for _ in range(repeat):
total += fn(*args)
return total / repeat
return helper
def worst_hurricane(odds): """odds is a predefined function that tells us a random amount of property damage"""
index_variable = 1
big_boom = 0
place = 0
while index_variable <= 10:
y = mega_calculator(odds,50) """checking odds of damage for skyscrapers only, and finding the average after 50 times is what the function cal to mega_calculator does"""
print("building", a, "will have", y, "dollars of damage")
if y > big_boom:
big_boom = y
place = index_variable
elif y == big_boom:
place = max(place, index_variable)
index_variable +=
return place
`
mega_calculator is returning a function named helper, that you can call. Try code like this:
calculator = mega_calculator(odds)
y = calculator(50)
You also probably want to unindent index_variable += 4 positions to the left, and change it to index_variable += 1.
Here is what you are trying to do:
I am using some dummy function called, just to make you understand:
>>> def mega_calculator(some_function):
... def helper(*args):
... return some_function(*args)
... return helper
...
>>> def odds(*args):
... print args
...
>>> x = mega_calculator(odds)
>>> x
<function helper at 0x10c8f18c0>
>>>
>>> x = mega_calculator(odds)(['Here', 'are some' , 'argument'])
(['Here', 'are some', 'argument'],)
>>>
I want to count 'fizz' in the list and I wrote below code and it doesn't worked. Tell me why and provide a solution. I was doing this tutorial and I have to write code as their instruction but I am unable to do what they said or maybe I misunderstood them.
count = 0
def fizz_count(x):
for string in x:
if string == 'fizz':
count = count + 1
else:
count = count
return count
If you want to check if your answer is correct then you have to check it by interpreting it here. Note that I am not calling my own function. Instead, their is an built in feature in Codecademy tutorial it checks function by calling function with some argument.
You need to have the count variable inside for loop, and you dont require an else condition
def fizz_count(x):
count=0
for string in x:
if string == 'fizz':
count = count + 1
return count
You can also write your function as
def fizz_count(x):
return x.count('fizz')
Have a look at this below code. I made some correction in it. There were some syntactical error and some indentation errors which I fixed it. Have a look at it:
def fizz_count(x):
count = 0
for string in x:
if string == 'fizz':
count = count + 1
else:
count = count
return count
str1 = fizz_count(['fizzers','fizzerlss','fizz','fizz'])
print str1
Edit: Same with more explanation due to down votes
Considering your approach with a global variable count (global, because it is not within the function), you would need to do two adaptions:
You need to make count available locally with the keyword global
Since you use a global variable, you do not need to return it because it is available anyway
Code:
count = 0
def fizz_count(x):
global count # make count available for writing in the local scope
for string in x:
if string == 'fizz':
count = count + 1
else:
count = count
Now actually using a global variable especially for such kind of tasks is not recommended, because it takes more time to load, you have to take care of the current state and stuff like that, so you rather'd introduce a local variable and pass it via the return statement as you did.
Put count = 0 into function
Code
# we put count = 0 into the function
def fizz_count(x):
count = 0 # right here
for string in x:
if string == 'fizz':
count = count + 1
else:
count = count
return count
Now a new count will be initialized to zero within the function.
Now there are two more things here:
the else statement
and the increment
Since the else statement is outside the loop it will be only executed if the if condition was never True during the loop. That has some use cases. But you'd put it in the loop usually. However, in your case it basically does not change anything, thats why it can be removed completely.
Well and the second point is that the increment can be written as count += 1 which is considered more readable, because it is less clumsy and the second count is merged into the +=
Therefore finally the function could be written like so
def fizz_count(x):
count = 0
for string in x:
if string == 'fizz':
count += 1
return count
Check also the reasonable solutions of the other answers