| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 
 | def ref(obj, weak, _plain=0):
    if not _plain and is_callable(obj):
        return CallableReference(obj, weak)
    if weak:
        return WeakReference(obj)
    else:
        return StrongReference(obj)
 
def is_callable(obj):
    if isinstance(obj, collections.Callable): return 1
    try:
        return isinstance(obj[1], collections.Callable)
    except:
        return 0
 
def ref_is(ref1,ref2):
    if ref1 is ref2: return 1
    o1 = ref1 and ref1()
    o2 = ref2 and ref2()
 
    # DEBUG:
    print(repr(o1))
    print(repr(o2))
    #if o1 is None or o2 is None: return 0
 
    return o1 is o2
 
class Reference:
    def callback(self, obj):
        for cb in self.callbacks:
            cb(obj, self)
        self.callbacks = []
    def __init__(self, obj):
        self.obj = self.ref(obj, self.callback)
        self.callbacks = []
        self.hash = generic_hash(obj)
    def __call__(self):
        return self.deref(self.obj)
    def __hash__(self):
        return self.hash
    __eq__ = ref_is
 
class WeakReference(Reference):
    def ref(self, obj, cb):
        global weakref
        if not weakref: import weakref
        return weakref.ref(obj, cb)
    def deref(self, obj):
        return obj()
 
class StrongReference(Reference):
    def ref(self, obj, cb):
        return obj
    def deref(self, obj):
        return obj
 
class CallableWrapper:
    def __init__(self, obj, func):
        self.obj = obj
        self.func = func
    def __call__(self, *args, **kwds):
        if self.obj is None:
            return self.func(*args, **kwds)
        else:
            return self.func(self.obj, *args, **kwds)
 
def is_callable_instance(obj):
    return type(obj) is object and hasattr(obj, '__call__')
 
def is_method(obj):
    return hasattr(obj, 'im_self')
 
def unwrap(func):
    try:
        obj, func = func
    except:
        obj = None
    if is_callable_instance(func):
        func = func.__call__
    if is_method(func):
        if func.__self__ is not None:
            if obj is None: obj = func.__self__
            else: assert obj is func.__self__
        func = func.__func__
    return obj, func
 
class CallableReference:
 
    # RefKeyDictionnary wants it...
    callbacks = []
 
    def __init__(self, func, weak):
        obj, func = unwrap(func)
 
        self.hash = hash((obj, func))
 
        if obj is not None:
            obj = ref(obj, weak, _plain=1)
        self.obj = obj
 
        self.func = ref(func, weak, _plain=1)
 
    def is_dead(self):
        return self.obj is not None and self.obj() is None \
               or self.func() is None
 
    def __call__(self):
        if self.is_dead(): return None
        obj = self.obj
        if obj is not None: obj = obj()
        func = self.func()
        return CallableWrapper(obj, func)
 
    def __eq__(self,other):
        if self.__class__ != other.__class__: return 0
        return (ref_is(self.obj,other.obj) and
                ref_is(self.func,other.func))
    def __hash__(self):
        return self.hash
 
##############################################
class Test:
    def func2(self):
        print(self)
    def __repr__(self):
        return '<Test>'
    def __call__(self, x):
        print(x)
 
test = Test()
sc3 = ref(test.func2, weak=0)
wc3 = ref(test.func2, weak=1)
print(sc3==wc3) | 
Partager