Skip to content

Instantly share code, notes, and snippets.

@danhodge
Last active September 14, 2024 02:12
Show Gist options
  • Save danhodge/723c6b6f975f0aebf58ef05181a8d8b8 to your computer and use it in GitHub Desktop.
Save danhodge/723c6b6f975f0aebf58ef05181a8d8b8 to your computer and use it in GitHub Desktop.
Python Notes
# debugging
import pdb
pdb.set_trace()
# override a class method in a subclass (Python 2.x)
class Foo(object):
@classmethod
def baz(cls, x):
return x + 3
class Bar(Foo):
@classmethod
def baz(cls, x):
return super(Bar, cls).baz(x) + 3
# parse & pretty print JSON
import json
print(json.dumps(json.loads(data), indent=4))
# imports: http://bhfsteve.blogspot.com/2012/06/patching-tip-using-mocks-in-python-unit.html
# this approach actually imports baz into the namespace of the module that imported it, so
# its fully-qualified name is now: my.module.file.baz (assuming it was imported in: my/module/file.py)
from foo.bar import baz
# this approach imports the whole foo package (and all of its subpackages), so the fully-qualified
# name of the baz function is still foo.bar.baz
import foo
# monkey patching - you need to take the import style into account when monkey patching
# in my.module.file.py
from foo.bar import baz
my.module.file.baz = monkey_baz
# in my.other.module.file.py
import foo
foo.bar.baz = monkey_baz
# dynamic method dispatch
class Foo:
def bar(self, x):
return x + 2
def dispatch(self, method_name, *args):
m = getattr(self, method_name)
return m(*args)
# Generators calling generators
class Generator:
def outer(self):
for result in self.inner():
print("outer yield: {}".format(result))
for value in result["values"]:
yield value
def inner(self):
for i in range(3):
print("inner yield")
yield {"values":range(i, 3)}
# in Python 3, yield from can be used to yield from can be used
class Generator:
def outer(self):
for i in range(3):
print("outer yield from: {}".format(i))
yield from self.inner(i)
def inner(self, start_idx):
for value in range(start_idx, 3):
print("inner yield")
yield value
for (i, val) in enumerate(Generator().outer()):
print("{}: {}".format(i, val))
# gevent & exceptions
from gevent.pool import Pool
pool = Pool(16)
def flaky_func(arg):
if (arg + 1) % 7 == 0:
raise Exception("Problem")
return (arg * 3) - 4
# this raises an exception as soon as imap iterates to a result that raised an exception
unsafe_results = pool.imap(flaky_func, range(100))
for (i, val) in enumerate(unsafe_results):
print("{}: {}".format(i, val))
def safe_func(fn):
def safe(*args, **kwargs):
try:
return fn(*args, **kwargs)
except Exception as e:
return None
return safe
# this does not raise
safe_results = pool.imap(safe_func(flaky_func), range(100))
for (i, val) in enumerate(safe_results):
print("{}: {}".format(i, val))
# can also use the built-in wrap_errors() function to catch the exception and return it as the value
from gevent.util import wrap_errors
safe_results = pool.imap(wrap_errors((Exception,), flaky_func), range(100))
# invoke a decorated method without going through its decorator
# (ugly, but can be useful in cases like tests for a method with a retry decorator where you want to avoid retrying)
class Foo:
@some_decorator
def some_method(self):
pass
result = Foo().some_method.__wrapped__()
# secondary constructor
class Foo(object):
@classmethod
def for_x(cls, x):
val = cls.__new__(cls)
val.bar = x
return val
def __init__(self):
self.bar = "baz"
## Descriptors
# definition
class Descriptor:
def __get__(self, obj, objtype=None):
return "baz"
# usage
class Bar:
foo = Descriptor() # must be stored as a class variable in another class
Bar.foo # returns "baz"
## Print stack trace
import traceback
traceback.print_stack(file=sys.stdout)
## Reverse a string/array
"Some Text"[::-1] # "texT emoS"
## Class methods, inheritance, class variables, and instances
class Descriptor:
def __get__(self, obj, objtype=None):
return "DESC1"
class Base(object):
VALUE = "base"
@classmethod
def the_value(cls):
return cls.VALUE # returns "base"
class Sub1(Base):
THING = "sub1"
@classmethod
def the_value(cls):
return cls.THING # returns "sub1"
# inherits the_value classmethod from Base
class Sub2(Base):
VALUE = Descriptor()
b = Base()
# accesses the VALUE class variable via the instance
b.VALUE # => 'base'
# calls the classmethod via the instance
b.the_value() # => 'base
s1 = Sub1()
s1.THING # => 'sub1
s1.the_value() # => 'sub1'
s2 = Sub2()
s2.VALUE # => 'DESC1'
s2.the_value() # => 'DESC1'
# conditionally transforming values in a dict comprehension
transformed = {k: v.upper() if k == "special" else v.lower() for (k, v) in dict.items()}
# Setup logging to write to STDOUT
import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
# Update a local variable from a nested function
def outer():
val = 1
def inner():
nonlocal val
val += 1
# Suppress including the causal chain from an exception raised from an except block
try:
...
except SomeException:
# note: the causal exception is still included in the exception that is raised,
# but __suppress_context__ is True, which tells exception handlers to ignore it
raise OtherException("message") from None
# Function decorators are composed in the order that they are applied
class InnerException(Exception):
pass
class OuterException(Exception):
pass
def innerToOuter(function):
def fn(*args, **kwargs):
try:
function(*args, **kwargs)
except InnerException:
raise OuterException()
return fn
def handleOuter(function):
def fn(*args, **kwargs):
try:
function(*args, **kwargs)
except OuterException:
print("Handled an OuterException")
except Exception as e:
print(f"Handled a non-OuterException: {e}")
return fn
class Foo:
# works correctly, InnerExceptionis converted to an OuterException and handled
@classmethod
@handleOuter
@innerToOuter
def perform1(cls):
raise InnerException()
# does not work correctly, InnerException is caught and handled before it can be converted to an OuterException
@classmethod
@innerToOuter
@handleOuter
def perform2(cls):
raise InnerException()
# Flatten a List of Lists
# - only works for for Lists of Lists, fails if any elements are scalars
# - does not flatten anything deeper (i.e. a List of Lists of Lists)
list = [[1,2,3], [4,5], [6]]
flattened = [item for sublist in list for item in sublist]
# Parse args/kwargs into the parameter values
import inspect
def some_function(foo, bar, baz=1, qux=None):
....
sig = inspect.signature(some_function)
bound_args = sig.bind(*args, **kwargs)
bound_args.arguments['foo']
bound_args.arguments['qux']
# Define class dynamically
MyClass = type("MyClass", (object,), { "foo": 42, "bar": 1, "do_it": lambda self: return self.foo })
# Dynamically add class (dynamically created or regular) to a module
import foo.bar.baz
baz.SomeClass = MyClass
# can now reference foo.bar.baz.SomeClass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment