Skip to content

Instantly share code, notes, and snippets.

@bl4ck5un
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bl4ck5un/07945d9e197baf17338e to your computer and use it in GitHub Desktop.
Save bl4ck5un/07945d9e197baf17338e to your computer and use it in GitHub Desktop.
Flavors of descriptor
#!/usr/bin/python
class simple_tracer_as_cls:
def __init__(self, func):
self.calls = 0
self.func = func
def __call__(self, *args, **kargs):
self.calls += 1
print('call %s to %s' % (self.calls, self.func.__name__))
return self.func(*args, **kargs)
def simple_tracer_as_func(func):
""" For Python 3 ONLY """
calls = 0
def wrapper(*args, **kwargs):
""" if no `nonlocals`
UnboundLocalError: "local variable 'calls' referenced before assignment"
"""
# nonlocal calls
calls += 1
print('call %s to %s' % (calls, func.__name__))
return func(*args, **kwargs)
return wrapper
# @simple_tracer_as_cls
# def foo(a, b, c):
# print (a+b+c)
#
# foo(1, 2, 3)
# foo(1, 2, 3)
class tracer_as_decorator_method_compatible(object):
def __init__(self, func):
self.calls = 0
self.func = func
def __call__(self, *args, **kwargs):
self.calls += 1
print ('call %s to %s' % (self.calls, self.func.__name__))
return self.func(*args, **kwargs)
def __get__(self, instance, owner):
""" Called when accessing decorated method.
Return a callable that can remember *instance*
"""
def wrapper(*args, **kwargs):
""" *instance* is store in this scope
even after `wrapper` being returned.
"""
return self(instance, *args, **kwargs)
return wrapper
# ===========================================
# Testing Code for all three method decorator
# ===========================================
# class Foo:
# def __init__(self):
# self.word = 'hello'
#
# @tracer_as_decorator_method_compatible
# def foo(self, word):
# print '%s %s' % (self.word, word)
#
# f = Foo()
# f.foo('world')
# f.foo('python')
# f.foo('decorator')
# import sys; sys.exit()
class tracer_as_decorator_method_compatible_v2(object):
""" version 2: Use class as new scope.
0. Cls.__init__(spam), which makes spam a descriptor
1. p.spam -> __get__(p, p.__class__)
2. __get__() returns instance of wrapper, to which `p.spam` is bound.
3. call wrapper.__call__ -> desc.__call__(p, ...) -> func(p, ...)
"""
def __init__(self, func):
self.calls = 0
self.func = func
def __call__(self, *args, **kwargs):
self.calls += 1
print ('call %s to %s' % (self.calls, self.func.__name__))
return self.func(*args, **kwargs)
def __get__(self, instance, owner):
class wrapper:
def __init__(self, desc, subj):
self.desc = desc
self.subj = subj
def __call__(self, *args, **kwargs):
return self.desc(self.subj, *args, **kwargs)
return wrapper(self, instance)
class my_own_method_compatible_tracer(object):
def __init__(self, func):
""" NOTE: func is a <function>, neither <bound> nor <unbound>
"""
# print func
self.calls = 0
self.func = func
def __call__(self, *args, **kwargs):
self.calls += 1
print ('call %s to %s' % (self.calls, self.func.__name__))
return self.func(self.wrapped, *args, **kwargs)
def __get__(self, instance, owner):
self.wrapped = instance
return self
#================
# With parameters
#================
import time
def timer(label='', trace=True):
""" outside decorator behaves like a factory """
class Timer:
""" inner wrapper is the one does real work
a callable returns another callable.
"""
def __init__(self, func):
self.func = func
self.alltime = 0
def __call__(self, *args, **kwargs):
start = time.clock()
result = self.func(*args, **kwargs)
elapsed = time.clock() - start
self.alltime += elapsed
if trace:
format = '%s <%s> round:%.5f all:%.5f'
value = (label, self.func.__name__, elapsed, self.alltime)
print (format % value)
return result
# factory's return
return Timer
# @timer(label='[CCC]==>', trace=True)
# def listcomp(N):
# return [x * 2 for x in range(N)]
#
# print listcomp # instance of Timer
# listcomp(1000)
# listcomp(10000)
# listcomp(100000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment