How to use the value of a variable as an argument - python

I am trying to use the value of a variable, which is a string, as an argument and I keep getting "'Str' not callable' error. I haven't used str as a variable name I can make the code work with eval, however, I've read dire warnings about eval, so am unsure what to do. My code is below.
from time import sleep
from binance.client import Client
from binance.websockets import BinanceSocketManager
class s33():
def __init__(self):
self.client = Client("", "")
self.bm = BinanceSocketManager(self.client)
def process_trade_message(self, message):
global count, conn_key
print(count)
if count >= 10:
print('closing socket')
# use either stop_socket or close, or both
self.bm.stop_socket(conn_key)
self.bm.close()
# reset the count
count = 0
def go(self, sockb):
global count, conn_key
print(sockb['1'])
sock = 'self.bm.'+sockb['1']
print(sock)
count = 0
conn_key = sock(self.process_trade_message)
self.bm.start()
if __name__ == '__main__':
while True:
s = s33()
socka = {'1':'start_miniticker_socket'}
s.go(socka)
sleep(20)
print('sleeping')
I have read people recommend using a dict, So I passed the dict as the arg and tried to extract the string in the function,which is the code below. I tried to extract the string and pass that as an arg to the function. s.go(socka['1'], I tried passing the just the variable as an arg, socka = 'start_miniticker_socket' and I can get that to work if I use eval('self.bm'+socka) I tried the percentage sign with no luck. Not sure how to do this without using eval. I am still fairly new and can't find an alternative answer after several hours of searching that works. any help would be appreciated.

I think what people meant when suggesting a dict is something like this:
class s33():
# Codes...
def go(self, func_name):
global count, conn_key
print(func_name)
mapper = {
'start_miniticker_socket': self.bm.start_miniticker_socket
}
# Get self.bm.start_miniticker or None
sock = mapper.get(func_name)
print(sock)
if sock:
count = 0
conn_key = sock(self.process_trade_message)
self.bm.start()
else:
pass # Handle when sock is None
if __name__ == '__main__':
while True:
s = s33()
socka = 'start_miniticker_socket'
s.go(socka)
sleep(20)
print('sleeping')

Related

ROS How to pass a callback variable into another file?

I have a callback function in a file "color.py" that constantly recieves incoming data but updates a global variable every 3 seconds:
last_color = ""
last_calltime = datetime.strptime("00:00:00","%H:%M:%S")
def callback(data):
global last_calltime, last_color
cube = data.data
t = time.localtime()
tf = time.strftime("%H:%M:%S",t)
current_time = datetime.strptime(tf, "%H:%M:%S")
delta_time = current_time - last_calltime
if abs(delta_time.total_seconds()) >= 3:
if "Red" in cube:
last_color = "Red"
elif "Green" in cube:
last_color = "Green"
else:
last_color = "Blue"
t = time.localtime()
tf = time.strftime("%H:%M:%S",t)
last_calltime = datetime.strptime(tf, "%H:%M:%S")
return last_color
if __name__ == '__main__':
try:
rospy.init_node('color')
rospy.Subscriber ('/topic',String, callback)
rospy.spin()
In another file, I need to reference this "last_color" variable that updates. So far the function I have in this file:
from color import last_color
a = 0
def observe_color(a)
if a == 0:
return last_color
else:
return "None"
I need this to return the updated variable from the "color.py" file but it only returns the initialized value for last_color which is "". How can I do this?
When you import something in Python, you're effectively asking it to execute everything in that module in the same runtime as your current program.
Suppose I have some module color.py with variable last_color='green'
And in a different program observer.py I have from color import last_color
The last_color that exists in color.py and the last_color that exists in observer.py are different places in computer memory - they do not reference the same string value.
A quick (and maybe dirty) solution to this is just to re-import the module every time you want to observe one of its member variables.
I don't think it's gonna work that way. How about save the value of last_color to a file and monitor it ? Because to me you run 2 separated programs, 1 with the ROS and another just to monitor last_color
while True:
with open(filename, 'r') as f:
color = f.readline()
time.sleep(timesteps)
When write to file in the main, you could also append the read value and also the time, to get timeline data.
Since this is all done in ROS it would be easiest to simply have the separate file initialize as a ros node with a subscriber. If for some reason that's not the case you should make color.py a class and have the other file initialize an object. Take the following simplified example:
color.py
class colorPy:
def __init__(self):
self.last_color = None
rospy.init_node('some_node')
tmp = rospy.Subscriber('/some_topic', self.callback)
def callback(self, msg):
self.last_color = msg.data
other file
from color import colorPy
from time import sleep
local_var = colorPy()
sleep(5)
print(local_var.last_color)

How do I print all of the instances from a set of variables that are undefined from the beginning?

I have a program that I want to be able to print all of the instances of each variable using my method that I created. Problem is I can't figure out a way to print them since each are listed under a different variable that aren't configured from hardcoding them in and I need a way to automatically recall them in my code.
class fit:
def __init__(self,day,did,workout='Not Recorded',time='An unknown amount of',calories='An unknown amount of'):
self.day = day
self.did = did
if did.lower()=='no':
self.workout = 'Not Recorded'
self.time = "An unknown amount of Minutes"
self.calories = "An unknown amount of Calories"
else:
self.workout = workout
self.time = "{} Minutes".format(time)
self.calories = "{} Calories".format(calories)
def formate(self):
self.formate = "{}:\n\nDid you work out: {}\nWorkout focus: {}\nYou worked out for: {}\nYou burned: {}\n\n----------------------------------------------------------".format(self.day,self.did,self.workout,self.time,self.calories)
return self.formate
def reader(day,index):
file = open('readme.txt')
file = file.read()
stripped = file.rsplit("\n")
for i in range(len(stripped)):
stripped[i] = stripped[i].rsplit(" ")
del stripped[-1]
if int(index) >= len(stripped[day-1]):
return "none"
else:
return stripped[day-1][index]
x = 0
def create_new_instance(class_name,instance_name):
globals()[instance_name] = class_name(reader(x,0),reader(x,1),reader(x,2),reader(x,3),reader(x,4))
print('Class instance {} created'.format(instance_name))
while True:
try:
x+=1
ins = 'day_' + str(x)
create_new_instance(fit,ins)
except:
break
break
def printer(instance):
print(.formate())
while True:
x+=1
inst = 'day_' + str(x)
printer(inst)
An example of this might be that I have 8 lines of data from a text document and I have a system that creates instances of day_1, day_2, day_3 ect until day_8 and then I want to print each of those instances out, but again I don't have those instances directly hardcoded into my code so I don't know how I'd do it. I've tried looking into maybe a while loop and increasing a variable by 1 and concatenating it with day and trying to make a variable out of that but the my limited experience with python isn't helping.
A very unpythonic and ugly way would be to use exec, for example:
day_3=5
x = 'day_'+'3'
exec("print("+x+")")
I would recommend another way to store your variables though.

How to parse results from a subprocess

I'm trying to pass a string in Python that was obtained from netstat to awk for use in building a new object.
Any clue why this isn't working? Please excuse the horrible coding, I just started using Python today and trying to learn how to use the language.
class NetstatGenerator():
def __init__(self):
import subprocess
self.results = subprocess.Popen("netstat -anbp tcp", shell=True, stdout=subprocess.PIPE).stdout.read()
self.list = []
self.parse_results()
def parse_results(self):
lines = self.results.splitlines(True)
for line in lines:
if not str(line).startswith("tcp"):
print("Skipping")
continue
line_data = line.split(" ")
self.list.append(NetstatData(self.line_data[0], self.line_data[15], self.line_data[18], self.line_data[23]))
def get_results(self):
return self.list
class NetstatData():
def __init__(self, protocol, local_address, foreign_address, state):
self.protocol = protocol
self.local_address = local_address
self.foreign_address = foreign_address
self.state = state
def get_protocol(self):
return str(self.protocol)
def get_local_address(self):
return str(self.local_address)
def get_foreign_address(self):
return str(self.foreign_address)
def get_state(self):
return str(self.state)
data = NetstatGenerator()
Sorry, netstat does not support -b on Linux, and I don't have a BSD box lying around.
Let's assume you have a list of lines, called netstat_output, with items like this:
tcp 0 0 127.0.0.1:9557 127.0.0.1:56252 ESTABLISHED -
To parse a single line, you split() it and pick elements at indexes 0, 3, 4, 5.
To store the items, you don't need to define a boilerplate holding class; namedtuple does what you want:
from collections import namedtuple
NetstatInfo = namedtuple('NetstatInfo',
['protocol', 'local_address', 'remote_address', 'state'])
Now you can parse a line:
def parseLine(line):
fields = line.split()
if len(fields) == 7 and fields[0] in ('tcp', 'udp'):
# alter this condition to taste;
# remember that netstat injects column headers.
# consider other checks, too.
return NetstatInfo(fields[0], fields[3], fields[4], fields[5])
# otherwise, this function implicitly returns None
Now something like this must be possible:
result = []
for line in subprocess.Popen(...):
item = parseLine(line)
if line: # parsed successfully
result.append(line)
# now result is what you wanted; e.g. access result[0].remote_address

Python decorators to function variables

In Python, is there a way to assign different decorators to functions as variables?
For example (the following code doesn't execute, obviously):
def status_display(function):
def body():
print("Entering", function.__name__)
function()
print("Exited", function.__name__)
return body
def call_counter(function):
counter = 0
def body():
function()
nonlocal counter
counter += 1
print(function.__name__, 'had been executed', counter, 'times')
return body
def a_function():
print('a_function executes')
# problems start here
# is there a working alternative to this false syntax?
#status_display
a_function_with_status_display = a_function()
#call_counter
a_function_with_call_counter = a_function()
# for an even crazier feat
# I knew this wouldn't work even before executing it
a_function_with_status_display = #status_display a_function()
a_function_with_call_counter = #call_counter a_function()
Thanks in advance.
a_function_with_status_display = status_display(a_function)
a_function_with_call_counter = call_counter(a_function)
You seem to be able to write decorators, but you don't know what they do?

Using var from from function A to function B

On this sample code i want to use the variables on the function db_properties at the function connect_and_query. To accomplish that I choose the return. So, using that strategy the code works perfectly. But, in this example the db.properties files only has 4 variables. That said, if the properties file had 20+ variables, should I continue using return? Or is there a most elegant/cleaner/correct way to do that?
import psycopg2
import sys
from ConfigParser import SafeConfigParser
class Main:
def db_properties(self):
cfgFile='c:\test\db.properties'
parser = SafeConfigParser()
parser.read(cfgFile)
dbHost = parser.get('database','db_host')
dbName = parser.get('database','db_name')
dbUser = parser.get('database','db_login')
dbPass = parser.get('database','db_pass')
return dbHost,dbName,dbUser,dbPass
def connect_and_query(self):
try:
con = None
dbHost=self.db_properties()[0]
dbName=self.db_properties()[1]
dbUser=self.db_properties()[2]
dbPass=self.db_properties()[3]
con = None
qry=("select star from galaxy")
con = psycopg2.connect(host=dbHost,database=dbName, user=dbUser,
password=dbPass)
cur = con.cursor()
cur.execute(qry)
data = cur.fetchall()
for result in data:
qryResult = result[0]
print "the test result is : " +qryResult
except psycopg2.DatabaseError, e:
print 'Error %s' % e
sys.exit(1)
finally:
if con:
con.close()
operation=Main()
operation.connect_and_query()
Im using python 2.7
Regards
If there are a lot of variables, or if you want to easily change the variables being read, return a dictionary.
def db_properties(self, *variables):
cfgFile='c:\test\db.properties'
parser = SafeConfigParser()
parser.read(cfgFile)
return {
variable: parser.get('database', variable) for variable in variables
}
def connect_and_query(self):
try:
con = None
config = self.db_properties(
'db_host',
'db_name',
'db_login',
'db_pass',
)
#or you can use:
# variables = ['db_host','db_name','db_login','db_pass','db_whatever','db_whatever2',...]
# config = self.db_properties(*variables)
#now you can use any variable like: config['db_host']
# ---rest of the function here---
Edit: I refactored the code so you can specify the variables you want to load in the calling function itself.
You certainly don't want to call db_properties() 4 times; just call it once and store the result.
It's also almost certainly better to return a dict rather than a tuple, since as it is the caller needs to know what the method returns in order, rather than just having access to the values by their names. As the number of values getting passed around grows, this gets even harder to maintain.
e.g.:
class Main:
def db_properties(self):
cfgFile='c:\test\db.properties'
parser = SafeConfigParser()
parser.read(cfgFile)
configDict= dict()
configDict['dbHost'] = parser.get('database','db_host')
configDict['dbName'] = parser.get('database','db_name')
configDict['dbUser'] = parser.get('database','db_login')
configDict['dbPass'] = parser.get('database','db_pass')
return configDict
def connect_and_query(self):
try:
con = None
conf = self.db_properties()
con = None
qry=("select star from galaxy")
con = psycopg2.connect(host=conf['dbHost'],database=conf['dbName'],
user=conf['dbUser'],
password=conf['dbPass'])
NB: untested
You could change your db_properties to return a dict:
from functools import partial
# call as db_properties('db_host', 'db_name'...)
def db_properties(self, *args):
parser = SafeConfigParser()
parser.read('config file')
getter = partial(parser.get, 'database')
return dict(zip(args, map(getter, args)))
But otherwise it's probably best to keep the parser as an attribute of the instance, and provide a convenience method...
class whatever(object):
def init(self, *args, **kwargs):
# blah blah blah
cfgFile='c:\test\db.properties'
self._parser = SafeConfigParser()
self._parser.read(cfgFile)
#property
def db_config(self, key):
return self._parser.get('database', key)
Then use con = psycopg2.connect(host=self.db_config('db_host')...)
I'd suggest returning a namedtuple:
from collections import namedtuple
# in db_properties()
return namedtuple("dbconfig", "host name user password")(
parser.get('database','db_host'),
parser.get('database','db_name'),
parser.get('database','db_login'),
parser.get('database','db_pass'),
)
Now you have an object that you can access either by index or by attribute.
config = self.db_properties()
print config[0] # db_host
print config.host # same

Categories

Resources