Fundamentals 17 min read

Python Gotchas, C/C++ Migration Tips, and Handy Utilities

This article presents a collection of Python pitfalls such as random sampling, lambda binding, copying, equality vs identity, and type checks, followed by a concise guide for C/C++ programmers transitioning to Python, and showcases useful tools like CSV handling, itertools, collections, and performance‑debugging techniques.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Python Gotchas, C/C++ Migration Tips, and Handy Utilities

1. Commonly Confusing Operations

This section compares several Python operations that are often confused.

1.1 Random sampling with and without replacement

import random
random.choices(seq, k=1)  # list of length k, sampling with replacement
random.sample(seq, k)     # list of length k, sampling without replacement

1.2 Lambda function arguments

func = lambda y: x + y          # x is bound at function execution time
func = lambda y, x=x: x + y     # x is bound at function definition time

1.3 copy vs deepcopy

import copy
y = copy.copy(x)      # shallow copy, only top‑level objects are copied
y = copy.deepcopy(x)  # deep copy, all nested objects are copied

When combined with variable aliases, copying can be confusing:

a = [1, 2, [3, 4]]

# Alias.
b_alias = a
assert b_alias == a and b_alias is a

# Shallow copy.
b_shallow_copy = a[:]
assert b_shallow_copy == a and b_shallow_copy is not a and b_shallow_copy[2] is a[2]

# Deep copy.
import copy
b_deep_copy = copy.deepcopy(a)
assert b_deep_copy == a and b_deep_copy is not a and b_deep_copy[2] is not a[2]

Modifying an alias affects the original variable; shallow copies keep references to inner objects, while deep copies are fully independent.

1.4 == vs is

x == y  # compare values
x is y  # compare object identity

1.5 Type checking

type(a) == int      # ignores polymorphism
isinstance(a, int)  # respects polymorphism

1.6 String searching

str.find(sub, start=None, end=None)   # returns -1 if not found
str.index(sub, start=None, end=None)  # raises ValueError if not found

1.7 List reverse indexing

Python allows reverse indexing; using the bitwise NOT operator (~) can start reverse indices at 0.

print(a[-1], a[-2], a[-3])
print(a[~0], a[~1], a[~2])

2. Guide for C/C++ Users

Many Python users come from C/C++; this section highlights syntactic and idiomatic differences.

2.1 Very large and very small numbers

a = float('inf')
b = float('-inf')

2.2 Boolean values

a = True
b = False

2.3 Checking for emptiness

In C/C++ a null pointer is checked with if (a) or if (!a). In Python use:

if x is None:
    pass

Using if not x treats empty strings, lists, tuples, dicts, etc., as false.

2.4 Swapping values

C/C++ typically uses a temporary variable; Python can swap in one line: a, b = b, a 2.5 Comparisons

C/C++ often writes two separate conditions; Python supports chained comparisons:

if 0 < a < 5:
    pass

2.6 Class member getters and setters

While C/C++ encourages private members with explicit get/set functions, Python can use @property but should avoid unnecessary abstraction because it can be 4‑5× slower than direct access.

2.7 Function input/output parameters

C/C++ passes output parameters via pointers and returns a status code. Python raises exceptions directly for error handling.

2.8 File reading

Python simplifies file I/O; opened files are iterable line by line:

with open(file_path, 'rt', encoding='utf-8') as f:
    for line in f:
        print(line)  # trailing '
' is retained

2.9 Path concatenation

Instead of manual string concatenation, use os.path.join:

import os
os.path.join('usr', 'lib', 'local')

2.10 Command‑line option parsing

Python’s argparse.ArgumentParser is more powerful than manually handling sys.argv.

2.11 Invoking external commands

Prefer subprocess.check_output over os.system for better control:

import subprocess
# Simple call, raises CalledProcessError on non‑zero exit
result = subprocess.check_output(['cmd', 'arg1', 'arg2']).decode('utf-8')
# Capture stderr as well
result = subprocess.check_output(['cmd', 'arg1', 'arg2'], stderr=subprocess.STDOUT).decode('utf-8')
# Run a shell pipeline
result = subprocess.check_output('grep python | wc > out', shell=True).decode('utf-8')

2.12 Avoid reinventing the wheel

Python follows the “batteries‑included” philosophy, providing many ready‑made solutions.

3. Common Tools

3.1 Reading and writing CSV files

import csv
# No header
with open(name, 'rt', encoding='utf-8', newline='') as f:
    for row in csv.reader(f):
        print(row[0], row[1])
with open(name, mode='wt') as f:
    f_csv = csv.writer(f)
    f_csv.writerow(['symbol', 'change'])

# With header
with open(name, mode='rt', newline='') as f:
    for row in csv.DictReader(f):
        print(row['symbol'], row['change'])
with open(name, mode='wt') as f:
    header = ['symbol', 'change']
    f_csv = csv.DictWriter(f, header)
    f_csv.writeheader()
    f_csv.writerow({'symbol': xx, 'change': xx})

For very large CSV files, increase the field size limit:

import sys
csv.field_size_limit(sys.maxsize)

CSV can also read tab‑delimited data:

f = csv.reader(f, delimiter='\t')

3.2 itertools utilities

import itertools
itertools.islice(iterable, start=None, stop, step=None)
itertools.filterfalse(predicate, iterable)
itertools.takewhile(predicate, iterable)
itertools.dropwhile(predicate, iterable)
itertools.compress(iterable, selectors)
sorted(iterable, key=None, reverse=False)
itertools.groupby(iterable, key=None)
itertools.permutations(iterable, r=None)
itertools.combinations(iterable, r=None)
itertools.combinations_with_replacement(...)
itertools.chain(*iterables)
import heapq
heapq.merge(*iterables, key=None, reverse=False)
zip(*iterables)
itertools.zip_longest(*iterables, fillvalue=None)

3.3 Counter

import collections
counter = collections.Counter(iterable)
freq = collections.Counter[key]
most_common = collections.Counter.most_common(n=None)
counter.update(iterable)
counter1 + counter2
counter1 - counter2
collections.Counter(list1) == collections.Counter(list2)

3.4 defaultdict with default values

import collections
d = collections.defaultdict(type)  # type() called with no args for missing keys

3.5 OrderedDict

import collections
od = collections.OrderedDict(items=None)  # preserves insertion order during iteration

4. High‑Performance Programming and Debugging

4.1 Writing errors and warnings

import sys
sys.stderr.write('error message')
import warnings
warnings.warn(message, category=UserWarning)
# Categories: DeprecationWarning, SyntaxWarning, RuntimeWarning, ResourceWarning, FutureWarning

Control warning output from the command line:

$ python -W all     # show all warnings
$ python -W ignore  # ignore all warnings
$ python -W error   # turn warnings into exceptions

4.2 In‑code testing (debug prints)

# Debug block
if __debug__:
    print('debug info')

Running Python with -O removes these blocks.

$ python -O main.py

4.3 Code style checking

pylint main.py

4.4 Measuring execution time

$ python -m cProfile main.py

Timing a specific block:

from contextlib import contextmanager
from time import perf_counter

@contextmanager
def timeblock(label):
    tic = perf_counter()
    try:
        yield
    finally:
        toc = perf_counter()
        print('%s : %s' % (label, toc - tic))

with timeblock('counting'):
    pass

Performance‑optimisation principles:

Focus on bottlenecks, not the whole code.

Avoid global variables; local look‑ups are faster.

Prefer local variable access over attribute access.

Use built‑in data structures (str, list, set, dict) implemented in C.

Avoid unnecessary intermediate variables and copy.deepcopy().

Prefer ':'.join([...]) over repeated string concatenation.

5. Other Python Tricks

5.1 argmin and argmax

items = [2, 1, 3, 4]
argmin = min(range(len(items)), key=items.__getitem__)
# argmax is analogous

5.2 Transposing a 2‑D list

A = [['a11', 'a12'], ['a21', 'a22'], ['a31', 'a32']]
A_transpose = list(zip(*A))               # list of tuples
A_transpose = [list(col) for col in zip(*A)]  # list of lists

5.3 Converting a 1‑D list to a 2‑D list

A = [1, 2, 3, 4, 5, 6]
# Preferred method
list(zip(*[iter(A)] * 2))
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performancePythonCode ExamplesStandard LibraryTips
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.