print different variables at one time in python - python

Have a question about how to print several separate variable with one command in python. E.g.I have A0=5,A1=6,A2="what",A3=[1,2,3],A4=(10,100)
I can do print(A0), print(A1), print(A2), etc
But what if I have 100 such variable which starting with same character (in this case is 'A'), how to print them out with one command?

Though I don't think that it is a good idea, but yes, you can do it:
A0 = 5
A1 = 2
A3 = 232
.
..
A999 = 25
for i in range(1000):
line = 'print(A{0})'.format(i)
exec(line)

if you "have 100 such variables which starting with same character (in this case is 'A')" and have a need to treat them as a collection, then obviously the proper solution is to use a collection instead of distinct "A0", "A1", ... "AN" variables. Whenever you end up doing something awkward (like here), ask yourself if your data are properly structured. Chances are it's not.

Related

Using variables as function parameters in VBA, specifically Cells() Function

I am working with loops & arrays in VBA.
I watched a bunch of videos online and none of the instructors have gone over this.
In Python, you can dynamically access values from an array by setting the index of my variable:
array1 = [1,2,3,4,5]
b = 0
while(b < len(array1)):
print(array1[b])
b = b + 1
You can do something similar with pandas indexing iloc capability....this way I can change the variable _currentRow7 to whatever I want....I just need to do _currentRow7 = _currentrow7+1
Array.iloc[_currentRow7, 11])
With the VBA Cells function, I get an error. Essentially I want to access values from Excel dynamically. For example - Cells(variable, 1)....then as the variable changes, I am accessing the value in the next cell.
Sub HomeRunCounterFNCTN()
Dim HomeRuns(27) As Integer
Dim HRCounter As Variant
Worksheets("Baseball").Activate
Range("L3").Activate
For HRCounter = 0 To 27
HomeRuns(HRCounter) = ActiveCell.Offset(HRCounter, 0).Value
If (HomeRuns(HRCounter) >= 45) Then MsgBox (HomeRuns(HRCounter))
MsgBox (Cells(HRCounter & 1))
Next HRCounter
End Sub
Essentially I would like the MsgBox (Cells(HRCounter & 1)) to update dynamically as the variable HRCounter changes.
I was able to run your code without error, so as #Tim Williams says, it would be helpful to describe the error you are getting.
I did spot one non-fatal flaw in this line:
MsgBox (Cells(HRCounter & 1)
You probably meant Cells(HRCounter, 1). The typo doesn't cause a program error, but the line fails to capture what you intended to capture.
Aside from the typo, the code seems to do what you intended it to do. However, to answer your question more directly, you can certainly work with variable cell references. In basic pattern, simply use SomeWorksheet.Cells(MyVar,1).Value, where MyVar is the variable holding your row number.
To write efficient VBA code, learn to avoid Activate and Select whenever possible. Think of them as code imitating the actions of a human user, which is rarely required. Instead, work directly with Excel objects and their properties. Your code can be recast as follows, which will also make the use of a variable row reference more visible:
Sub HomeRunCounterFNCTN()
Dim HomeRuns(27) As Integer, ReadRow As Integer
Dim HRCounter As Variant
With Worksheets("Baseball")
For HRCounter = 0 To 27
ReadRow = HRCounter + 3
HomeRuns(HRCounter) = .Cells(ReadRow, 12).Value
If (HomeRuns(HRCounter) >= 45) Then MsgBox HomeRuns(HRCounter)
Next HRCounter
End With
End Sub

Python: Change variable suffix with for loop

I know this was asked a lot but I can not work with/understand the answers so far.
I want to change the suffix of variables in a for loop.
I tried all answers the stackoverflow search provides. But it is difficult to understand specific codes the questioner often presents.
So for clarification I use an easy example. This is not meant as application-oriented. I just want to understand how I can change the suffix.
var_1 = 10
var_2 = 100
var_3 = 1000
for i in range(1,4):
test_i = var_i + 1
print(test_i)
Expected result:
creating and printing variables:
test_1 = 11
test_2 = 101
test_3 = 1001
Expected Output
11
101
1001
Error: var_i is read as a variable name without the changes for i.
I would advise against using eval in 99.99% of all cases. What you could do is use the built-in getattr function:
import sys
var_1 = 10
var_2 = 100
var_3 = 1000
for i in range(1,4):
test_i = getattr(sys.modules[__name__], f"var_{i}") + 1
print(test_i)
Instead of doing a convoluted naming convention, try to conceive of your problem using a data structure like dictionaries, for example.
var={}
var[1] = 10
var[2] = 100
var[3] = 1000
test={}
for i in range(1,4):
test[i] = var[i] +1
print(test)
If somehow you are given var_1 etc as input, maybe use .split("_") to retrieve the index number and use that as the dictionary keys (they can be strings or values).
Small explanation about using indexing variable names. If you are starting out learning to program, there are many reasons not to use the eval, exec, or getattr methods. Most simply, it is inefficient, not scalable, and is extremely hard to use anywhere else in the script.
I am not one to insist on "best practices" if there is an easier way to do something, but this is something you will want to learn to avoid. We write programs to avoid having to type things like this.
If you are given that var_2 text as a starting point, then I would use string parsing tools to split and convert the string to values and variable names.
By using a dictionary, you can have 1000 non-consecutive variables and simply loop through them or assign new associations. If you are doing an experiment, for example, and call your values tree_1, tree_10 etc, then you will always be stuck typing out the full variable names in your code rather than simply looping through all the entries in a container called tree.
This is a little related to using a bunch of if:else statements to assign values:
# inefficient way -- avoid
if name == 'var_1' then:
test_1=11
elif name == 'var_2' then:
test_2=101
It is so much easier just to say:
test[i]= var[i]+1
and that one line will work for any number of values.
for i in range(1, 4):
print(eval('var_' + str(i)))
Step by step:
1) Make your variables strings:
stringified_number = str(i)
2) evaluate your expression during runtime:
evaluated_variable = eval('var_' + stringified_number)

Refactoring variable to monkey-patched attribute in PyCharm

In Pycharm a segment of my code in the editor looks like this:
q = slice(0, 6)
q1 = 0
q2 = 1
q3 = 2
q4 = 3
q5 = 4
q6 = 5
But now I want to do:
q.q1 = 0
q.q2 = 1
q.q3 = 2
q.q4 = 3
q.q5 = 4
q.q6 = 5
So that these variables are now monkey-patched attributes of q. These are used in several places in my project so I'd like to refactor. First I tried highlighting q1 then going Refactor->Rename... and then changing the name to q.q1, however this gives me the message, "'q.q1' is not a valid identifier".
Is there any way in PyCharm to do this type of refactor? I tried doing a simple find and replace but there are a lot of other function names that contain q1 and this is only a subset of the refactoring that I need to do. I know that I could use a regex to do this but am wondering if there is any other way?
As per the answer here, this actually isn't a simple refactor like it sounds.
You're two main options are: 1) To try and use the Refactor -> Extract option instead or 2) to use a Find and Replace (I appreciate that's far more manual and potentially time consuming!).
I'm not sure how well the Extract option works with monkey patched variables like yours. I'll investigate further.

Concatenating strings more efficiently in Python

I've been learning Python for a couple of months, and wanted to understand a cleaner and more efficient way of writing this function. It's just a basic thing I use to look up bus times near me, then display the contents of mtodisplay on an LCD, but I'm not sure about the mtodisplay=mtodisplay+... line. There must be a better, smarter, more Pythonic way of concatenating a string, without resorting to lists (I want to output this string direct to LCD. Saves me time. Maybe that's my problem ... I'm taking shortcuts).
Similarly, my method of using countit and thebuslen seems a bit ridiculous! I'd really welcome some advice or pointers in making this better. Just wanna learn!
Thanks
json_string = requests.get(busurl)
the_data = json_string.json()
mtodisplay='220 buses:\n'
countit=0
for entry in the_data['departures']:
for thebuses in the_data['departures'][entry]:
if thebuses['line'] == '220':
thebuslen=len(the_data['departures'][entry])
print 'buslen',thebuslen
countit += 1
mtodisplay=mtodisplay+thebuses['expected_departure_time']
if countit != thebuslen:
mtodisplay=mtodisplay+','
return mtodisplay
Concatenating strings like this
mtodisplay = mtodisplay + thebuses['expected_departure_time']
Used to be very inefficient, but for a long time now, Python does reuse the string being catentated to (as long as there are no other references to it), so it's linear performance instead of the older quadratic performance which should definitely be avoided.
In this case it looks like you already have a list of items that you want to put commas between, so
','.join(some_list)
is probably more appropriate (and automatically means you don't get an extra comma at the end).
So next problem is to construct the list(could also be a generator etc.). #bgporter shows how to make the list, so I'll show the generator version
def mtodisplay(busurl):
json_string = requests.get(busurl)
the_data = json_string.json()
for entry in the_data['departures']:
for thebuses in the_data['departures'][entry]:
if thebuses['line'] == '220':
thebuslen=len(the_data['departures'][entry])
print 'buslen',thebuslen
yield thebuses['expected_departure_time']
# This is where you would normally just call the function
result = '220 buses:\n' + ','.join(mtodisplay(busurl))
I'm not sure what you mean by 'resorting to lists', but something like this:
json_string = requests.get(busurl)
the_data = json_string.json()
mtodisplay= []
for entry in the_data['departures']:
for thebuses in the_data['departures'][entry]:
if thebuses['line'] == '220':
thebuslen=len(the_data['departures'][entry])
print 'buslen',thebuslen
mtodisplay.append(thebuses['expected_departure_time'])
return '220 buses:\n' + ", ".join(mtodisplay)

What is the Pythonic way to implement a simple FSM?

Yesterday I had to parse a very simple binary data file - the rule is, look for two bytes in a row that are both 0xAA, then the next byte will be a length byte, then skip 9 bytes and output the given amount of data from there. Repeat to the end of the file.
My solution did work, and was very quick to put together (even though I am a C programmer at heart, I still think it was quicker for me to write this in Python than it would have been in C) - BUT, it is clearly not at all Pythonic and it reads like a C program (and not a very good one at that!)
What would be a better / more Pythonic approach to this? Is a simple FSM like this even still the right choice in Python?
My solution:
#! /usr/bin/python
import sys
f = open(sys.argv[1], "rb")
state = 0
if f:
for byte in f.read():
a = ord(byte)
if state == 0:
if a == 0xAA:
state = 1
elif state == 1:
if a == 0xAA:
state = 2
else:
state = 0
elif state == 2:
count = a;
skip = 9
state = 3
elif state == 3:
skip = skip -1
if skip == 0:
state = 4
elif state == 4:
print "%02x" %a
count = count -1
if count == 0:
state = 0
print "\r\n"
The coolest way I've seen to implement FSMs in Python has to be via generators and coroutines. See this Charming Python post for an example. Eli Bendersky also has an excellent treatment of the subject.
If coroutines aren't familiar territory, David Beazley's A Curious Course on Coroutines and Concurrency is a stellar introduction.
You could give your states constant names instead of using 0, 1, 2, etc. for improved readability.
You could use a dictionary to map (current_state, input) -> (next_state), but that doesn't really let you do any additional processing during the transitions. Unless you include some "transition function" too to do extra processing.
Or you could do a non-FSM approach. I think this will work as long as 0xAA 0xAA only appears when it indicates a "start" (doesn't appear in data).
with open(sys.argv[1], 'rb') as f:
contents = f.read()
for chunk in contents.split('\xaa\xaa')[1:]:
length = ord(chunk[0])
data = chunk[10:10+length]
print data
If it does appear in data, you can instead use string.find('\xaa\xaa', start) to scan through the string, setting the start argument to begin looking where the last data block ended. Repeat until it returns -1.
I am a little apprehensive about telling anyone what's Pythonic, but here goes. First, keep in mind that in python functions are just objects. Transitions can be defined with a dictionary that has the (input, current_state) as the key and the tuple (next_state, action) as the value. Action is just a function that does whatever is necessary to transition from the current state to the next state.
There's a nice looking example of doing this at http://code.activestate.com/recipes/146262-finite-state-machine-fsm. I haven't used it, but from a quick read it seems like it covers everything.
A similar question was asked/answered here a couple of months ago: Python state-machine design. You might find looking at those responses useful as well.
I think your solution looks fine, except you should replace count = count - 1 with count -= 1.
This is one of those times where fancy code-show-offs will come up ways of have dicts mapping states to callables, with a small driver function, but it isn't better, just fancier, and using more obscure language features.
I suggest checking out chapter 4 of Text Processing in Python by David Mertz. He implements a state machine class in Python that is very elegant.
I think the most pythonic way would by like what FogleBird suggested, but mapping from (current state, input) to a function which would handle the processing and transition.
You can use regexps. Something like this code will find the first block of data. Then it's just a case of starting the next search from after the previous match.
find_header = re.compile('\xaa\xaa(.).{9}', re.DOTALL)
m = find_header.search(input_text)
if m:
length = chr(find_header.group(1))
data = input_text[m.end():m.end() + length]

Categories

Resources