Effective Python: 90 Specific Ways to Write Better Python, 2nd Edition by Brett Slatkin
Author:Brett Slatkin [Brett Slatkin]
Language: eng
Format: epub
Publisher: Addison-Wesley Professional
Published: 2019-11-21T16:00:00+00:00
✦ Descriptors and metaclasses make a powerful combination for declarative behavior and runtime introspection.
✦ Define __set_name__ on your descriptor classes to allow them to take into account their surrounding class and its property names.
✦ Avoid memory leaks and the weakref built-in module by having descriptors store data they manipulate directly within a class’s instance dictionary.
Item 51: Prefer Class Decorators Over Metaclasses for Composable Class Extensions
Although metaclasses allow you to customize class creation in multiple ways (see Item 48: “Validate Subclasses with __init_subclass__” and Item 49: “Register Class Existence with __init_subclass__”), they still fall short of handling every situation that may arise.
For example, say that I want to decorate all of the methods of a class with a helper that prints arguments, return values, and exceptions raised. Here, I define the debugging decorator (see Item 26: “Define Function Decorators with functools.wraps” for background):
Click here to view code image
from functools import wraps def trace_func(func): if hasattr(func, 'tracing'): # Only decorate once return func @wraps(func) def wrapper(*args, **kwargs): result = None try: result = func(*args, **kwargs) return result except Exception as e: result = e raise finally: print(f'{func.__name__}({args!r}, {kwargs!r}) -> ' f'{result!r}') wrapper.tracing = True return wrapper
I can apply this decorator to various special methods in my new dict subclass (see Item 43: “Inherit from collections.abc for Custom Container Types” for background):
Click here to view code image
class TraceDict(dict): @trace_func def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @trace_func def __setitem__(self, *args, **kwargs): return super().__setitem__(*args, **kwargs) @trace_func def __getitem__(self, *args, **kwargs): return super().__getitem__(*args, **kwargs) ...
And I can verify that these methods are decorated by interacting with an instance of the class:
Click here to view code image
trace_dict = TraceDict([('hi', 1)]) trace_dict['there'] = 2 trace_dict['hi'] try: trace_dict['does not exist'] except KeyError: pass # Expected >>> __init__(({'hi': 1}, [('hi', 1)]), {}) -> None __setitem__(({'hi': 1, 'there': 2}, 'there', 2), {}) -> None __getitem__(({'hi': 1, 'there': 2}, 'hi'), {}) -> 1 __getitem__(({'hi': 1, 'there': 2}, 'does not exist'), ➥ {}) -> KeyError('does not exist')
The problem with this code is that I had to redefine all of the methods that I wanted to decorate with @trace_func. This is redundant boilerplate that’s hard to read and error prone. Further, if a new method is later added to the dict superclass, it won’t be decorated unless I also define it in TraceDict.
One way to solve this problem is to use a metaclass to automatically decorate all methods of a class. Here, I implement this behavior by wrapping each function or method in the new type with the trace_func decorator:
Click here to view code image
import types trace_types = ( types.MethodType, types.FunctionType, types.BuiltinFunctionType, types.BuiltinMethodType, types.MethodDescriptorType, types.ClassMethodDescriptorType) class TraceMeta(type): def __new__(meta, name, bases, class_dict): klass = super().__new__(meta, name, bases, class_dict) for key in dir(klass): value = getattr(klass, key) if isinstance(value, trace_types): wrapped = trace_func(value) setattr(klass, key, wrapped) return klass
Now, I can declare my dict subclass by using the TraceMeta metaclass and verify that it works as expected:
Click here to view code image
class TraceDict(dict, metaclass=TraceMeta): pass trace_dict = TraceDict([('hi', 1)]) trace_dict['there'] = 2 trace_dict['hi'] try: trace_dict['does not exist'] except KeyError: pass # Expected >>> __new__((<class '__main__.
Download
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.
What's Done in Darkness by Kayla Perrin(26520)
Shot Through the Heart: DI Grace Fisher 2 by Isabelle Grey(19006)
The Fifty Shades Trilogy & Grey by E L James(18957)
Shot Through the Heart by Mercy Celeste(18878)
Wolf & Parchment: New Theory Spice & Wolf, Vol. 10 by Isuna Hasekura and Jyuu Ayakura(16981)
Python GUI Applications using PyQt5 : The hands-on guide to build apps with Python by Verdugo Leire(16873)
Peren F. Statistics for Business and Economics...Essential Formulas 3ed 2025 by Unknown(16803)
Wolf & Parchment: New Theory Spice & Wolf, Vol. 03 by Isuna Hasekura and Jyuu Ayakura & Jyuu Ayakura(16697)
Wolf & Parchment: New Theory Spice & Wolf, Vol. 01 by Isuna Hasekura and Jyuu Ayakura & Jyuu Ayakura(16321)
The Subtle Art of Not Giving a F*ck by Mark Manson(14258)
The 3rd Cycle of the Betrayed Series Collection: Extremely Controversial Historical Thrillers (Betrayed Series Boxed set) by McCray Carolyn(14071)
Stepbrother Stories 2 - 21 Taboo Story Collection (Brother Sister Stepbrother Stepsister Taboo Pseudo Incest Family Virgin Creampie Pregnant Forced Pregnancy Breeding) by Roxi Harding(13419)
Scorched Earth by Nick Kyme(12713)
Drei Generationen auf dem Jakobsweg by Stein Pia(10921)
Suna by Ziefle Pia(10845)
Scythe by Neal Shusterman(10268)
International Relations from the Global South; Worlds of Difference; First Edition by Arlene B. Tickner & Karen Smith(9474)
Successful Proposal Strategies for Small Businesses: Using Knowledge Management ot Win Govenment, Private Sector, and International Contracts 3rd Edition by Robert Frey(9314)
This is Going to Hurt by Adam Kay(9096)
