If I have a variable:
var = 5
I want to detect and jump to a function when the value of the variable changes, so if var is not equal to the value it was before, I want to jump to a function.
What is the easiest way to do this?
Another example:
from datetime import datetime
import time
def dereferentie():
currentMinute = datetime.now().minute
checkMinute(currentMinute)
def checkMinute(currentMinute):
#if currentMinute has changed do:
printSomething()
def printSomething():
print "Minute is updated"
def main():
while (1):
dereferentie()
if __name__ == '__main__':
main()
Building on #HelloWorld's answer and #drIed's comment: A nice way would be, to wrap this into a class.
For example:
class Watcher:
""" A simple class, set to watch its variable. """
def __init__(self, value):
self.variable = value
def set_value(self, new_value):
if self.variable != new_value:
self.pre_change()
self.variable = new_value
self.post_change()
def pre_change(self):
pass # do stuff before variable is about to be changed
def post_change(self):
pass # do stuff right after variable has changed
I would go with a setter function which triggers your needed function.
def setValue(val):
global globalVal
valueChanged= g_val != val
if valueChanged:
preFunction()
globalVal = val
if valueChanged:
postFunction()
A great way is to use the #property and #.setter decorators.
class MyClass:
#property
def property_name(self):
return self.some_value
#property_name.setter
def property_name(self, new_value):
self.some_value = new_value
obj = MyClass()
obj.property_name = "New Value"
stored_value = obj.property_name
By the way this is one of my favorite features in Python.
Original Poster
Here's how I would implement your example.
from datetime import datetime
class TimeManager:
# The actual variable holding data
# You don't need to declare it, but I like to
_current_minute = None
#property
def current_minute(self):
"""Retrieve the local variable value."""
return self._current_minute
#current_minute.setter
#current_minute.setter
def current_minute(self, value):
"""Same method name, but set the local variable."""
self._current_minute = value
print("Minute has updated to {}".format(self._current_minute))
#current_minute.deleter
def current_minute(self):
"""You can also delete variables."""
del self._current_minute
def main():
# Create the class
time_manager = TimeManager()
for i in range(100):
current_minute = datetime.now().second
# set the .currrent_minute using a #property
time_manager.current_minute = current_minute
if __name__ == '__main__':
main()
Related
The first step of my program is to get the data.
After that I am finding myself passing this data to all the different classes (with also a config dictionary variable) over and over again.
So I am wondering if there is a better way to just store the data somewhere and make it available to all classes and functions, without passing them as a parameter.
Thank you
Edit: here is a code example
go.py
config = {
'mode' : 'single',
'data' : { },
'strategy' : { },
'view' : { }
}
stratego.start(config)
stratego.py
def start(config):
data = dt.Data(config['data'])
if (config['data']['type'] == 'yahoo'):
df = data.get_yahoo_data()
elif (config['data']['type'] == 'csv'):
df = data.get_csv_data()
else:
return False
trades = str.Strategy(df, config['strategy'])
tradeBook = trades.run()
but then I am realising that the problem is my main function (start). If I run the main code not in a function I have all my instances available in the global. Is that right? Is it correct to do this way or it is better to wrap the program in a main function?
If really you don't want to pass it as an argument you could define it as a variable in a python file and import this variable where you define your fonction. You should be able to use this variable in the function without passing it in argument.
EDIT: Refactored code according to code update by OP
Ok since you use a strategy pattern you can actually do that using a strategy like design pattern
stratego.py
def start(*strategies):
for strategy in strategies:
strategy.run()
go.py
from functools import lru_cache, wraps
from abc import ABC, abstractmethod
import stratego
#lru_cache()
def get_data(filepath):
# Load data from filepath
data = ...
return data
#lru_cache()
def get_data_with_config(**data_config):
# Load data based on data_config
data = get_data(data_config['filepath'])
if (data_config['type'] == 'yahoo'):
df = data.get_yahoo_data()
elif (data_config['type'] == 'csv'):
df = data.get_csv_data()
...
return df
class Strategy(ABC):
def __init__(self, config):
self.config = config
#abstractmethod
def run(self):
pass
class YahooStrategy(Strategy):
def __init__(self, config):
config = config.copy()
config['data']['type'] = 'yahoo'
super().__init__(config)
def run(self):
df = get_data_with_config(**self.config['data'])
# Do sth with data
class CsvStrategy(Strategy):
def __init__(self, config):
config = config.copy()
config['data']['type'] = 'csv'
super().__init__(config)
def run(self):
df = get_data_with_config(**self.config['data'])
# Do sth with data
class FunctionStrategy(Strategy):
def __init__(self, config, func):
super().__init__(config)
self.func = func
def run(self):
return self.func(self.config)
def strategy_decorator(func):
#wraps(func)
def wrapper(config):
return FunctionStrategy(config, func)
return wrapper
#strategy_decorator
def some_strategy_function(config):
df = get_data_with_config(**config['data'])
# Do smth with data
# With one strategy
strategy = YahooStrategy({'data': {'filepath': 'data.csv', ...}})
stratego.run(strategy)
# Multiple strategies
strategies = [
YahooStrategy({'data': {'filepath': 'data.csv', ...}}),
CsvStrategy({'data': {'filepath': 'data2.csv', ...}}),
some_strategy_function({'data': {'filepath': 'data4.csv', ...}})
]
stratego.run(*strategies)
If you're thinking pass by reference vs pass by value then I would suspect you are newer to Python. To my understanding, all variables are passed by reference. That is, you aren't copying the actual data every time you call a function with parameters.
If you're thinking more along the lines of global variables, you can do something like this:
globvar = 0
def set_globvar_to_one():
global globvar # Needed to modify global copy of globvar
globvar = 1
def print_globvar():
print(globvar) # No need for global declaration to read value of globvar
I am trying to call the sum_method function from my evaluation class to my main one, however I run into many errors. I want to use the new_data as the data parameter of my sum_method function.
evaluation class:
class evaluation():
def __init__(self, data):
self.data = data
def sum_method(self):
montant_init = self.data.loc[self.data['Initiateur'] == 'Glovoapp', 'Montant (centimes)'].sum()
print(montant_init)
main class:
class main(evaluation):
new_data.to_csv("transactions.csv", index=False)
self.data = new_data
def call_sum(self, new_data):
init_eval = evaluation.sum_method(self=new_data)
print(init_eval)
init_evalobj = main()
init_evalobj.call_sum()
if you use the method in your inherence class just use self
so:
init_eval = self.sum_method()
the self argument is passed in python automaticly as first parameter
update
you also should return a value:
def sum_method(self):
montant_init = self.data.loc[self.data['Initiateur'] == 'Glovoapp', 'Montant (centimes)'].sum()
print(montant_init)
return montant_init
I'd suggest making some changes to the both classes, to encapsulate the .data member variable in the base class. My preference would also be to separate out the calculation from the display, so leave all the print statements in the call_sum() function.
class evaluation:
def __init__(self, data):
self.data = data
def sum_method(self):
montant_init = self.data.loc[self.data['Initiateur'] == 'Glovoapp', 'Montant (centimes)'].sum()
return montant_init
class main(evaluation):
def __init__(self):
# Reduce csv content to what's needed for analysis
data_csv = pd.read_csv('transactions.csv')
# --> removing unnecessary data
new_data = data_csv[['Opération', 'Initiateur', 'Montant (centimes)', 'Monnaie',
'Date', 'Résultat', 'Compte marchand', 'Adresse IP Acheteur', 'Marque de carte']]
# --> saving changes...
new_data.to_csv("transactions.csv", index=False)
super().__init__(new_data) //Initialize the base class
def call_sum(self):
print('Glovoapp "montant" generated')
init_eval = self.sum_method() //Call the method from the base class
print(init_eval)
Assume I have two classes that use threads
class foo(threading.Thread):
def __init__(self):
threading.Thread.__init__(self,name="foo=>bar")
self.var1 = {}
def run(self):
while True
value, name = getvalue() // name is an string
self.var1[name] = value
bar(self)
class bar(threading.Thread):
def __init__(self,fooInstance):
threading.Thread.__init__(self,name="bar")
def run(self):
while True
arg = myfunction() // somefunction (not shown for simplicity)
val = myOtherfunction(fooInstance.var1[arg]) //other function
print(val)
f = foo()
f.start()
The variable var1 in foo will change over time and bar needs to be aware of these changes. It makes sense to me, but I wonder if there is something fundamental here that could fail eventually. is this correct in python?
The actual sharing part is the same question as "how do I share a value with another object?" without threads, and all the same solutions will work.
For example. you're already passing the foo instance into the bar initializer, so just get it from there:
class bar(threading.Thread):
def __init__(self,fooInstance):
threading.Thread.__init__(self,name="bar")
self.var1 = fooInstance.var1
But is this thread-safe?
Well, yes, but only because you never actually start the background thread. But I assume in your real code, you're going to have two threads running at the same time, both accessing that var1 value. In which case it's not thread-safe without some kind of synchronization. For example:
class foo(threading.Thread):
def __init__(self):
threading.Thread.__init__(self,name="foo=>bar")
self.var1 = {}
self.var1lock = threading.Lock()
class bar(threading.Thread):
def __init__(self,fooInstance):
threading.Thread.__init__(self,name="bar")
self.var1 = fooInstance.var1
self.var1lock = fooInstance.var1lock
And now, instead of this:
self.var1[name] = value
… you do this:
with self.var1lock:
self.var1[name] = value
And likewise, instead of this:
val = myOtherfunction(fooInstance.var1[arg]) //other function
… you do this:
with self.var1lock:
var1arg = var1[arg]
val = myOtherfunction(var1arg)
Or… as it turns out, in CPython, updating a value for a single key in a dict (only a builtin dict, not a subclass or custom mapping class!) has always been atomic, and probably always will be. If you want to rely on that fact, you can. But I'd only do that if the lock turned out to be a significant performance issue. And I'd comment every use of it to make it clear, too.
If you'd rather pass values instead of share them, the usual answer is queue.Queue or one of its relatives.
But this requires a redesign of your program. For example, maybe you want to pass each new/changed key-value pair over the queue. That would go something like this:
class foo(threading.Thread):
def __init__(self):
threading.Thread.__init__(self,name="foo=>bar")
self.var1 = {}
self.q = queue.Queue()
def run(self):
b = bar(self)
b.start()
while True:
value, name = getvalue() // name is an string
self.var1[name] = value
self.q.put((name, value))
class bar(threading.Thread):
def __init__(self,fooInstance):
threading.Thread.__init__(self,name="bar")
self.var1 = copy.deepcopy(fooInstance.var1)
self.q = fooInstance.q
def _checkq(self):
while True:
try:
key, val = self.q.get_nowait()
except queue.Empty:
break
else:
self.var1[key] = val
def run(self):
while True:
self._checkq()
arg = myfunction() // somefunction (not shown for simplicity)
val = myOtherfunction(fooInstance.var1[arg]) //other function
print(val)
I built a class to handle a lot of different functions that take common inputs. However, I just ran into the situation where one of the variables that's fed down through self needs to be changed. How do I do this? This is an example:
class Test:
def __init__(self, test_variable):
self.test_var = test_variable
#property
def some_function(self):
if self.test_var < 0:
self.test_var = 'New Output' #this is the line that I can't get
#get to work and I was hoping to update it here
#so I could use it in later functions
return self.test_var
Thank you!
You should drop the #property attribute. Then, you can set it by just doing x.test_var = 5. E.g.,
class Test:
def __init__(self, test_variable):
self.test_var = test_variable
def some_function(self):
if self.test_var < 0:
self.test_var = 'New Output' #this is the line that I can't get
#get to work and I was hoping to update it here
#so I could use it in later functions
return self.test_var
x = Test(-1)
print(x.some_function())
x.test_var = 5
print(x.some_function())
returns
New Output
5
I'm new to python and the main() method and class def's are confusing me. I'm trying to create a bloom filter and my program keeps terminating because I don't think I'm calling things correctly.
class BloomFilter(object):
def __init__(self, numBits, numHashFunctions):
self.numBits = numBits
self.bitArray = [0] * numBits
self.hash = bloomFilterHash(numBits, numHashFunctions)
def insert(self, key):
def lookup(self, key):
def rand_inserts(self,num):
def main(): #not sure if i should put this inside or outside class
bloomfilter = BloomFilter(100,5)
bloomfilter.rand_inserts(15)
if __name__ == '__main__':
BloomFilter().main()
So if I wanted to create a bloom filter with 100 numBits and 5 hash functions, should i call that under the if __name__ == '__main__' or under def main()? I'm not sure if I'm calling these correctly as I'm much more familiar with Java. thanks!
def main():
bloomfilter = BloomFilter(100,5)
bloomfilter.rand_inserts(15)
the name == '__main__' clause is to make sure your code only runs when the module is called directly, not, for instance, if you are importing something from the module in another module. main() is not a special method for a python class, so I believe your objective here, in a simplified way, is the following:
class BloomFilter(object):
def __init__(self, numBits, numHashFunctions):
self.numBits = numBits
self.bitArray = [0] * numBits
self.hash = bloomFilterHash(numBits, numHashFunctions)
if __name__ == '__main__':
# creates an instance of the class
bloomfilter = BloomFilter(100,5)
# apply some method to instance...
bloomfilter.rand_inserts(15)
You would want to put main() outside the class:
class BloomFilter(object):
def __init__(self, numBits, numHashFunctions):
self.numBits = numBits
self.bitArray = [0] * numBits
self.hash = bloomFilterHash(numBits, numHashFunctions)
def insert(self, key):
def lookup(self, key):
def rand_inserts(self,num):
def main():
some_value = Bloomfilter(100, 5)
some_value.rand_inserts(15)
main()