Python 2 and 3 compatibility utilities
—
Functions for dictionary iteration and general iterator handling that work consistently across Python versions. These utilities provide unified interfaces for dictionary operations and iterator handling that were changed between Python 2 and 3.
Functions that return iterators over dictionary contents, providing consistent behavior across Python versions.
def iterkeys(d: dict, **kw) -> Iterator[Any]
"""Return iterator over dictionary keys."""
def itervalues(d: dict, **kw) -> Iterator[Any]
"""Return iterator over dictionary values."""
def iteritems(d: dict, **kw) -> Iterator[tuple[Any, Any]]
"""Return iterator over dictionary items as (key, value) pairs."""
def iterlists(d: dict, **kw) -> Iterator[list[Any]]
"""Return iterator over dictionary lists (for MultiDict-like objects)."""Parameters:
d: Dictionary to iterate over**kw: Additional keyword arguments forwarded to the underlying dictionary methodUsage Examples:
import six
data = {"a": 1, "b": 2, "c": 3}
# Iterate over keys
for key in six.iterkeys(data):
print(key) # Prints: a, b, c
# Iterate over values
for value in six.itervalues(data):
print(value) # Prints: 1, 2, 3
# Iterate over items
for key, value in six.iteritems(data):
print(f"{key}: {value}") # Prints: a: 1, b: 2, c: 3
# Memory efficient iteration over large dictionaries
large_dict = {str(i): i for i in range(10000)}
for key, value in six.iteritems(large_dict):
if value > 5000:
breakFunctions that return dictionary views (Python 3 behavior) or equivalent iterators (Python 2).
def viewkeys(d: dict) -> Any
"""Return dictionary keys view."""
def viewvalues(d: dict) -> Any
"""Return dictionary values view."""
def viewitems(d: dict) -> Any
"""Return dictionary items view."""Usage Examples:
import six
data = {"a": 1, "b": 2, "c": 3}
# Get keys view/equivalent
keys_view = six.viewkeys(data)
print("a" in keys_view) # True
# Get values view/equivalent
values_view = six.viewvalues(data)
print(1 in values_view) # True
# Get items view/equivalent
items_view = six.viewitems(data)
print(("a", 1) in items_view) # True
# Set operations on views (Python 3 behavior)
dict1 = {"a": 1, "b": 2}
dict2 = {"b": 2, "c": 3}
common_keys = six.viewkeys(dict1) & six.viewkeys(dict2) # {'b'}General utilities for working with iterators across Python versions.
def advance_iterator(it: Iterator) -> Any
"""Advance an iterator by one step and return the next value."""
def next(it: Iterator, default: Any = None) -> Any
"""Get next item from iterator with optional default."""
def callable(obj: Any) -> bool
"""Test if an object is callable."""Usage Examples:
import six
# Advance iterator manually
data = iter([1, 2, 3, 4, 5])
first = six.advance_iterator(data) # 1
second = six.next(data) # 2
# Use with default value
empty_iter = iter([])
value = six.next(empty_iter, "default") # "default"
# Test callability
def my_function():
pass
print(six.callable(my_function)) # True
print(six.callable("string")) # False
print(six.callable(lambda x: x)) # TrueBase class for creating cross-version compatible iterators.
class Iterator:
"""Base iterator class for Python 2 compatibility."""
def __iter__(self) -> Iterator
def __next__(self) -> AnyThis class provides the correct iterator protocol for both Python versions, handling the __next__ vs next method difference.
Usage Example:
import six
class CountdownIterator(six.Iterator):
def __init__(self, start):
self.start = start
def __iter__(self):
return self
def __next__(self):
if self.start <= 0:
raise StopIteration
self.start -= 1
return self.start + 1
# Use the iterator
countdown = CountdownIterator(3)
for num in countdown:
print(num) # Prints: 3, 2, 1Functions for accessing method and function attributes consistently across Python versions.
def get_method_function(method: Any) -> Any
"""Get function from method object."""
def get_method_self(method: Any) -> Any
"""Get self from method object."""
def get_function_closure(func: Any) -> Any
"""Get closure from function object."""
def get_function_code(func: Any) -> Any
"""Get code object from function."""
def get_function_defaults(func: Any) -> Any
"""Get defaults from function object."""
def get_function_globals(func: Any) -> Any
"""Get globals from function object."""Usage Examples:
import six
class MyClass:
def my_method(self, x, y=10):
z = x + y
return lambda: z
obj = MyClass()
method = obj.my_method
# Access method components
func = six.get_method_function(method) # Unbound function
self_obj = six.get_method_self(method) # The instance (obj)
# Access function components
code = six.get_function_code(func) # Code object
defaults = six.get_function_defaults(func) # (10,)
globals_dict = six.get_function_globals(func) # Global namespace
# Example with closure
closure_func = obj.my_method(5)
closure = six.get_function_closure(closure_func) # Closure variablesFunctions for creating bound and unbound methods across Python versions.
def get_unbound_function(func: Any) -> Any
"""Get function from possibly unbound function."""
def create_bound_method(func: Callable, instance: Any) -> Any
"""Create a bound method from function and instance."""
def create_unbound_method(func: Callable, cls: type) -> Any
"""Create an unbound method from function and class."""Usage Examples:
import six
class MyClass:
def my_method(self):
return "Hello from method"
# Get unbound function
unbound = six.get_unbound_function(MyClass.my_method)
# Create bound method manually
instance = MyClass()
bound_method = six.create_bound_method(unbound, instance)
result = bound_method() # "Hello from method"
# Create unbound method (primarily for Python 2 compatibility)
unbound_method = six.create_unbound_method(unbound, MyClass)import six
# Efficient dictionary processing
def process_large_dict(data_dict):
"""Process dictionary without creating intermediate lists."""
result = {}
# Memory-efficient iteration
for key, value in six.iteritems(data_dict):
if isinstance(value, six.string_types):
result[key] = value.upper()
elif six.callable(value):
result[key] = value()
else:
result[key] = str(value)
return result
# Custom iterator with cross-version compatibility
class ChunkedIterator(six.Iterator):
"""Iterator that yields chunks of data."""
def __init__(self, data, chunk_size):
self.data = iter(data)
self.chunk_size = chunk_size
def __iter__(self):
return self
def __next__(self):
chunk = []
try:
for _ in range(self.chunk_size):
chunk.append(six.next(self.data))
except StopIteration:
if chunk:
return chunk
raise
return chunk
# Use chunked iterator
data = range(10)
chunked = ChunkedIterator(data, 3)
for chunk in chunked:
print(chunk) # [0, 1, 2], [3, 4, 5], [6, 7, 8], [9]
# Method introspection and modification
def analyze_methods(cls):
"""Analyze all methods in a class."""
methods_info = {}
for name in dir(cls):
attr = getattr(cls, name)
if six.callable(attr) and hasattr(attr, '__func__'):
func = six.get_method_function(attr) if hasattr(attr, '__self__') else attr
methods_info[name] = {
'defaults': six.get_function_defaults(func),
'code': six.get_function_code(func),
'arg_count': six.get_function_code(func).co_argcount
}
return methods_infoInstall with Tessl CLI
npx tessl i tessl/pypi-six