Last active
September 14, 2024 02:12
-
-
Save danhodge/723c6b6f975f0aebf58ef05181a8d8b8 to your computer and use it in GitHub Desktop.
Python Notes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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