这是我对3年级(使用3.7米,不了解以前版本或2x)的解决办法。
from functools import wraps
from inspect import signature as _signature
class _Bound:
type of bound methodsand classes
def __init__(self, callable):
self._callable = callable
def __get__(self, instance, cls):
called when instance.callable or Class.callable
if instance is None: # called on class, not instance
return self._callable
@wraps(self._callable)
def retf(*a, **k):
try:
return self._callable(instance, *a, **k)
except: # information if failed
# user did `self.callable(*args, **kwargs)` and failed
print(f failed call of {self._callable} )
print(f self: {instance} )
print(f args: {a} )
print(f kwargs: {k} )
raise
# additional wrap to expell first argument
sig = _signature(retf)
retf.__signature__ = sig.replace(parameters=tuple(sig.parameters.values())[1:])
return retf
def __call__(self, *a, **k):
Class.__dict__[ BoundMethod ](instance, *a, **k) (c(), 55, 8, key=9)
return self._callable(*a, **k)
pass
class UnBound:
"similar to static, only doesn t change attribute at all (except for builtin-like method making)"
def __init__(self, callable):
self.callable = callable
pass
class class_(classmethod):
pass
class static(staticmethod):
pass
class NestedType(type):
meta to support nested classes (and other callables)
meta to outer class
@staticmethod
def bind(dict):
for name, attr in dict.items():
if callable(attr) and not isinstance(attr, (class_, static)): #functions, classes, ...
dict[name] = _Bound(attr)
elif isinstance(attr, UnBound):
dict[name] = attr.callable
def __new__(meta, object_or_name, bases, dict):
NestedType.bind(dict)
return type.__new__(meta, object_or_name, bases, dict)
class NestedBase(metaclass=NestedType):
pass
<><>>>
class Outer(<note0>):
class Inner:
def __init__(self, self_): # I prefer self_ above outer
note0: here can come NestedBase
or metaclass=NestedType
(and beware of meta mismatch error)
need to know
Outer.Inner
return class module.Outer.Inner
Outer().Inner
returns bound method
Outer.__dict__[ Inner ]
returns bound object _Bound...
note1
imports are not that important, they only change pop-up when using IDE (VScode python extension doesn t recognize it, so it displays it wrongly, but IDLE does)
classes explained
_Bound
should not be used
used as a decorator:
UnBound
will make old-style binding
class_
same as classmethod
static
same as staticmethod
NestedType
metaclass to the outer class
NestedBase
base to the outer class
only one needed per outer class
note2
inner class that has no decorator UnBound
needs to have init that receives <Outer object>
as 2nd argument
otherwise will write (see _Bound.__get__.retf.except
) and throw TypeError: Inner(?) takes ? arguments
meta mismatch
to see meta mismatch write class M(type): pass
, class A(NestedBase): pass
, class B(metaclass=M): pass
, class C(A, B): pass
solution: create submeta of both metas and, if , call NestedType.bind(dict)
(as in NestedType.__new__
)
note3: overriding __new__
or NestedMeta not 1st in subclassing order (class NewMeta(NotNestedMeta, NestedMeta)
( here NestedMeta
is non-strict submeta of NestedType
)