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.
Related
I want to write a LibreOffice Calc document from within a Python3 program. Using pyoo I can do almost everything I want, including formatting and merging cells. But I cannot adjust row heights and column widths.
I found Change the column width and row height very helpful, and have been experimenting with it, but I can't seem to get quite the result I want. My present test file, based on the answer mentioned above, looks like this:
#! /usr/bin/python3
import os, pyoo, time, uno
s = '-'
while s != 'Y':
s = input("Have you remembered to start Calc? ").upper()
os.popen("soffice --accept=\"socket,host=localhost,port=2002;urp;\" --norestore --nologo --nodefault")
time.sleep(2)
desktop = pyoo.Desktop('localhost', 2002)
doc = desktop.create_spreadsheet()
class ofic:
sheet_idx = 0
row_num = 0
sheet = None
o = ofic()
uno_localContext = uno.getComponentContext()
uno_resolver = uno_localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", uno_localContext )
uno_ctx = uno_resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext" )
uno_smgr = uno_ctx.ServiceManager
uno_desktop = uno_smgr.createInstanceWithContext( "com.sun.star.frame.Desktop", uno_ctx)
uno_model = uno_desktop.getCurrentComponent()
uno_controller = uno_model.getCurrentController()
uno_sheet_count = 0
doc.sheets.create("Page {}".format(1), index=o.sheet_idx)
o.sheet = doc.sheets[o.sheet_idx]
o.sheet[0, 0].value = "The quick brown fox jumps over the lazy dog"
o.sheet[1, 1].value = o.sheet_idx
uno_controller.setActiveSheet(uno_model.Sheets.getByIndex(uno_sheet_count))
uno_sheet_count += 1
uno_active_sheet = uno_model.CurrentController.ActiveSheet
uno_columns = uno_active_sheet.getColumns()
uno_column = uno_columns.getByName("B")
uno_column.Width = 1000
The main problem with the above is that I have 2 Calc documents on the screen, one of which is created before the Python program gets going; the other is created from Python with a pyoo function. The first document gets the column width change, and the second receives the text input etc. I want just the second document, and of course I want the column width change applied to it.
I am sure the answer must be fairly straightforward, but after hours of experimentation I still can't find it. Could someone point me in the right direction, please?
Your code alternates between pyoo and straight Python-UNO, so it's no wonder that it's giving messy results. Pick one or the other. Personally, I use straight Python-UNO and don't see the benefit of adding the extra pyoo library.
the other is created from Python with a pyoo function
Do you mean this line of code from your question, and is this the "second document" that you want the column change applied to?
doc = desktop.create_spreadsheet()
If so, then get objects from that document instead of whichever window the desktop happens to have selected.
controller = doc.getCurrentController()
sheets = doc.getSheets()
Or perhaps you want the other document, the one that didn't get created from Python. In that case, grab a reference to that document before creating the second one.
first_doc = uno_desktop.getCurrentComponent()
second_doc = desktop.create_spreadsheet()
controller = first_doc.getCurrentController()
sheets = first_doc.getSheets()
If you don't have a reference to the document, you can find it by iterating through the open windows.
oComponents = desktop.getComponents()
oDocs = oComponents.createEnumeration()
Finally, how to resize a column. The link in your question is for Excel and VBA (both from Microsoft), so I'm not sure why you think that would be relevant. Here is a Python-UNO example of resizing columns.
oColumns = oSheet.getColumns()
oColumn = oColumns.getByName("A")
oColumn.Width = 7000
oColumn = oColumns.getByName("B")
oColumn.OptimalWidth = True
Im trying to create and run a program that allows the user to insert 2 drug names and receive their outcome. This is what my code looks like so far, yet I cant figure out the syntax error or if it's the best way to go about my plan
a = int(input("A.C"))
B = int(input("Opioid"))
sum = a + b
print("Incompatible, increased death rate", sum)
In your code, you make an assignment to B and then attempt to read from b. Those are two different variables. All names in Python are case-sensitive.
You need to change the variable name(b), also I added the new line when user wants to enter a value. I used fprint to print the output.
a = int(input("A.C \n") )
b = int(input("Opioid \n"))
sum = a+b
print(f'Incompatible, increased death rate, {sum}')
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
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)
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.