Converting VBA macros to Python is more than swapping syntax. VBA and Python handle fundamental operations differently, and the gaps are subtle enough that your code can look correct while producing wrong results. These are the 10 gotchas we see most often in real-world migrations.
1. Array Indexing: 1-Based vs 0-Based
VBA arrays default to 1-based indexing (unless Option Base 0 is set). Python lists are always 0-based. This means every array index in your converted code is potentially off by one.
' VBA — first element is at index 1
Dim arr(1 To 5) As Integer
arr(1) = 10 ' First element
# Python — first element is at index 0
arr = [0] * 5
arr[0] = 10 # First element
What breaks: Loops using For i = 1 To UBound(arr) need to become for i in range(len(arr)), not for i in range(1, len(arr) + 1). Get this wrong and you either skip the first element or hit an IndexError.
2. Integer Division Truncation Direction
VBA's Int() function rounds toward negative infinity (like math.floor), while Python's int() truncates toward zero. This only matters with negative numbers, which makes it hard to catch in testing.
' VBA
Debug.Print Int(-3.7) ' Returns -4 (rounds down)
Debug.Print Fix(-3.7) ' Returns -3 (truncates)
# Python
import math
print(math.floor(-3.7)) # -4 (equivalent to VBA Int)
print(int(-3.7)) # -3 (equivalent to VBA Fix)
What breaks: Financial calculations with negative values. A rounding difference of 1 in a payroll module can cascade through every downstream calculation.
3. String Concatenation Type Coercion
VBA's & operator automatically converts numbers to strings. Python's + operator raises a TypeError if you mix strings and numbers.
' VBA — this just works
Dim msg As String
msg = "Total: " & 42 & " items"
# Python — this crashes
msg = "Total: " + 42 + " items" # TypeError!
# Fix: use f-strings
msg = f"Total: {42} items"
What breaks: Every string concatenation line that includes a numeric variable. Our converter handles this automatically with f-strings, but if you're converting manually, you'll miss some.
4. Backslash Escape Sequences in File Paths
VBA treats backslashes as literal characters. Python interprets \t as tab, \n as newline, and \b as backspace inside strings.
' VBA — backslashes are literal
filePath = "C:\test\new\backup.txt"
# Python — \t = tab, \n = newline, \b = backspace!
file_path = "C:\test\new\backup.txt" # BROKEN
file_path = "C:\\test\\new\\backup.txt" # Correct
file_path = r"C:\test\new\backup.txt" # Also correct (raw string)
What breaks: Any hardcoded Windows file path. The code runs without errors but writes to the wrong location or produces garbled filenames.
5. Nothing vs None — Object Comparison
VBA uses Is Nothing to check for null objects. In Python, the equivalent is is None (not == None).
' VBA
If obj Is Nothing Then
MsgBox "Object not set"
End If
# Python
if obj is None: # Correct
print("Object not set")
if obj == None: # Works but wrong — use 'is'
print("Unreliable comparison")
What breaks: Using == instead of is for None checks. It usually works, but custom classes can override __eq__ and make obj == None return True for non-None objects.
6. ByRef Is the Default in VBA — ByVal Is the Default in Python
VBA passes arguments ByRef by default, meaning the called function can modify the caller's variables. Python passes object references, but reassigning a parameter name doesn't affect the caller.
' VBA — modifies the caller's variable
Sub DoubleIt(x As Integer)
x = x * 2
End Sub
Sub Test()
Dim n As Integer
n = 5
DoubleIt n
Debug.Print n ' Prints 10
End Sub
# Python — does NOT modify the caller's variable
def double_it(x):
x = x * 2 # Only changes local binding
n = 5
double_it(n)
print(n) # Still 5!
What breaks: Any VBA Sub that modifies its parameters (common in sorting, swapping, and accumulator patterns). You need to return values instead.
7. Select Case Ranges vs Python If/Elif
VBA's Select Case supports ranges (Case 1 To 10) and comparisons (Case Is > 100). Python's match/case (3.10+) doesn't support ranges, so these must become if/elif chains.
' VBA
Select Case score
Case 90 To 100: grade = "A"
Case 80 To 89: grade = "B"
Case Is < 60: grade = "F"
End Select
# Python — must use if/elif
if 90 <= score <= 100:
grade = "A"
elif 80 <= score <= 89:
grade = "B"
elif score < 60:
grade = "F"
What breaks: Direct translation of Case x To y into case x only matches the exact value, not the range.
8. Error Handling Scope
VBA's On Error Resume Next silently ignores ALL errors after that line until On Error GoTo 0 resets it. Python's try/except only catches errors within its block.
' VBA — ignores ALL errors in the rest of the sub
On Error Resume Next
result = riskyOperation()
If Err.Number <> 0 Then
' Handle error
Err.Clear
End If
anotherOperation() ' Also error-protected!
# Python — each risky operation needs its own try/except
try:
result = risky_operation()
except Exception as e:
# Handle error
pass
another_operation() # NOT protected — will crash on error
What breaks: Code that relies on Resume Next to silently skip failures in multiple consecutive operations. Each one needs its own try/except block.
9. Date Arithmetic
VBA dates are numeric (serial date format). You can add days by adding integers. Python's datetime objects require timedelta for arithmetic.
' VBA — just add a number
Dim tomorrow As Date
tomorrow = Date + 1
# Python — need timedelta
import datetime
tomorrow = datetime.date.today() + datetime.timedelta(days=1)
What breaks: Any code that does date + n or date - n. The Python equivalent is verbose but explicit.
10. Boolean to Integer Coercion
VBA's True is -1 (not 1). Python's True is 1. This matters when you use Boolean values in arithmetic.
' VBA
Dim x As Integer
x = True ' x = -1
x = True + True ' x = -2
# Python
x = True # x = 1 (not -1!)
x = True + True # x = 2 (not -2!)
What breaks: Any code that relies on True = -1 for bit manipulation, array sizing, or conditional arithmetic. Replace with explicit values.
How Our Converter Handles These
VBAtoPython.com's deterministic converter addresses all 10 of these gotchas:
- Gotchas 1-2:
Int()maps tomath.floor(), array indices are flagged for review - Gotcha 3: String concatenation auto-converts to f-strings
- Gotcha 4: Backslashes in VBA strings are escaped during pre-processing
- Gotcha 5:
Is Nothingconverts tois None - Gotcha 6: ByRef parameters get a comment warning about Python's pass-by-object behavior
- Gotcha 7:
Select Caseranges convert to properif/elifchains - Gotcha 8:
On Error Resume Nextgenerates a warning explaining the scope difference - Gotcha 9: Date functions map to
datetimewith helper functions forDateAdd,DateDiff, etc. - Gotcha 10: VBA boolean constants map correctly
Every conversion is verified with Python's ast.parse() to catch syntax errors before you do. Try it free with up to 100 lines.