from fastdebug.utils import *
from fastdebug.core import *
from fastcore.meta import *
07_BypassNewMeta
Reading official docs
BypassNewMeta > BypassNewMeta (name, bases, dict)
Metaclass: casts x to this class if it’s of type cls._bypass_type
BypassNewMeta is identical to NewChkMeta, except for checking for a class as the same type, we instead check for a class of type specified in attribute _bypass_type.
In NewChkMeta, objects of the same type passed to the constructor (without arguments) would result into a new variable referencing the same object.
However, with BypassNewMeta this only occurs if the type matches the _bypass_type
of the class you are defining:
# class _TestA: pass
# class _TestB: pass
# class _T(_TestA, metaclass=BypassNewMeta):
# _bypass_type=_TestB
# def __init__(self,x): self.x=x
In the below example, t does not refer to t2 because t is of type _TestA while _T._bypass_type is of type TestB:
# t = _TestA()
# t2 = _T(t)
# assert t is not t2
However, if t is set to _TestB to match _T._bypass_type, then both t and t2 will refer to the same object.
# t = _TestB()
# t2 = _T(t)
# t2.new_attr = 15
# test_is(t, t2)
# # since t2 just references t these will be the same
# test_eq(t.new_attr, t2.new_attr)
# # likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
# t.new_attr = 9
# test_eq(t2.new_attr, 9)
# t = _TestB(); t
# isinstance(t, _TestB)
# id(_TestB)
# # t2 = _T(t)
# # t, t2
Inspecting class
inspect_class(BypassNewMeta)
class BypassNewMeta(FixSigMeta):
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"
def __call__(cls, x=None, *args, **kwargs):
if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs)
elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs):
x = super().__call__(*((x,)+args), **kwargs)
if cls!=x.__class__: x.__class__ = cls
return x
is BypassNewMeta a metaclass: True
is BypassNewMeta created by a metaclass: False
BypassNewMeta is created by <class 'type'>
BypassNewMeta.__new__ is object.__new__: False
BypassNewMeta.__new__ is type.__new__: False
BypassNewMeta.__new__: <function FixSigMeta.__new__>
BypassNewMeta.__init__ is object.__init__: False
BypassNewMeta.__init__ is type.__init__: True
BypassNewMeta.__init__: <slot wrapper '__init__' of 'type' objects>
BypassNewMeta.__call__ is object.__call__: False
BypassNewMeta.__call__ is type.__call__: False
BypassNewMeta.__call__: <function BypassNewMeta.__call__>
BypassNewMeta.__class__: <class 'type'>
BypassNewMeta.__bases__: (<class 'fastcore.meta.FixSigMeta'>,)
BypassNewMeta.__mro__: (<class 'fastcore.meta.BypassNewMeta'>, <class 'fastcore.meta.FixSigMeta'>, <class 'type'>, <class 'object'>)
BypassNewMeta's function members are:
{'__call__': <function BypassNewMeta.__call__>,
'__new__': <function FixSigMeta.__new__>}
BypassNewMeta's method members are:
{}
BypassNewMeta's class members are:
{'__base__': <class 'fastcore.meta.FixSigMeta'>, '__class__': <class 'type'>}
BypassNewMeta's namespace are:
mappingproxy({'__call__': <function BypassNewMeta.__call__>,
'__doc__': "Metaclass: casts `x` to this class if it's of type "
'`cls._bypass_type`',
'__module__': 'fastcore.meta'})
Initiating with examples
= locals()
g = Fastdb(BypassNewMeta, outloc=g)
fdb = """
fdb.eg class _TestA: pass
class _TestB: pass
class _T(_TestA, metaclass=BypassNewMeta):
_bypass_type=_TestB
def __init__(self,x): self.x=x
t = _TestA()
print(t)
t2 = _T(t)
print(t2)
assert t is not t2
"""
= """
fdb.eg class _TestA: pass
class _TestB: pass
class _T(_TestA, metaclass=BypassNewMeta):
_bypass_type=_TestB
def __init__(self,x): self.x=x
t = _TestB()
t2 = _T(t)
t2.new_attr = 15
test_is(t, t2)
# since t2 just references t these will be the same
test_eq(t.new_attr, t2.new_attr)
# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
t.new_attr = 9
test_eq(t2.new_attr, 9)
# both t and t2's __class__ is _T
test_eq(t.__class__, t2.__class__)
test_eq(t.__class__, _T)
"""
Snoop
fdb.snoop()
23:28:43.69 >>> Call to BypassNewMeta.__call__ in File "/tmp/BypassNewMeta.py", line 5
23:28:43.69 .......... cls = <class '__main__._T'>
23:28:43.69 .......... x = <__main__._TestB object>
23:28:43.69 .......... args = ()
23:28:43.69 .......... kwargs = {}
23:28:43.69 .......... __class__ = <class 'fastcore.meta.BypassNewMeta'>
23:28:43.69 5 | def __call__(cls, x=None, *args, **kwargs):
23:28:43.69 6 | if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs)
23:28:43.69 7 | elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs):
23:28:43.69 9 | if cls!=x.__class__: x.__class__ = cls
23:28:43.69 ...... x = <__main__._T object>
23:28:43.69 10 | return x
23:28:43.69 <<< Return value from BypassNewMeta.__call__: <__main__._T object>
====================================================== Investigating BypassNewMeta =======================================================
============================================================== on line None ==============================================================
with example
class _TestA: pass
class _TestB: pass
class _T(_TestA, metaclass=BypassNewMeta):
_bypass_type=_TestB
def __init__(self,x): self.x=x
t = _TestB()
t2 = _T(t)
t2.new_attr = 15
test_is(t, t2)
# since t2 just references t these will be the same
test_eq(t.new_attr, t2.new_attr)
# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
t.new_attr = 9
test_eq(t2.new_attr, 9)
# both t and t2's __class__ is _T
test_eq(t.__class__, t2.__class__)
test_eq(t.__class__, _T)
fdb.debug()
BypassNewMeta's dbsrc code: ==============
class BypassNewMeta(FixSigMeta):
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"
import snoop
@snoop
def __call__(cls, x=None, *args, **kwargs):
if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs)
elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs):
x = super().__call__(*((x,)+args), **kwargs)
if cls!=x.__class__: x.__class__ = cls
return x
BypassNewMeta's example processed with dbsrc: ===============
class _TestA: pass
class _TestB: pass
class _T(_TestA, metaclass=self.dbsrc):
_bypass_type=_TestB
def __init__(self,x): self.x=x
t = _TestB()
t2 = _T(t)
t2.new_attr = 15
test_is(t, t2)
# since t2 just references t these will be the same
test_eq(t.new_attr, t2.new_attr)
# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
t.new_attr = 9
test_eq(t2.new_attr, 9)
# both t and t2's __class__ is _T
test_eq(t.__class__, t2.__class__)
test_eq(t.__class__, _T)
Document
3, "If the instance class like _T has attr '_new_meta', then run it with param x;", "x", \
fdb.docsrc("cls", "getattr(cls,'_bypass_type',object)", "isinstance(x, _TestB)", "isinstance(x,getattr(cls,'_bypass_type',object))")
4, "when x is not an instance of _T's _bypass_type; or when a positional param is given; or when a keyword arg is given; \
fdb.docsrc(let's run _T's super's __call__ function with x as param; and assign the result to x")
6, "If x.__class__ is not cls or _T, then make it so")
fdb.docsrc(1, "BypassNewMeta allows its instance class e.g., _T to choose a specific class e.g., _TestB and \
fdb.docsrc(change `__class__` of an object e.g., t of _TestB to _T without creating a new object")
====================================================== Investigating BypassNewMeta =======================================================
=============================================================== on line 3 ================================================================
with example
class _TestA: pass
class _TestB: pass
class _T(_TestA, metaclass=BypassNewMeta):
_bypass_type=_TestB
def __init__(self,x): self.x=x
t = _TestB()
t2 = _T(t)
t2.new_attr = 15
test_is(t, t2)
# since t2 just references t these will be the same
test_eq(t.new_attr, t2.new_attr)
# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
t.new_attr = 9
test_eq(t2.new_attr, 9)
# both t and t2's __class__ is _T
test_eq(t.__class__, t2.__class__)
test_eq(t.__class__, _T)
print selected srcline with expands below--------
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`" (1)
def __call__(cls, x=None, *args, **kwargs): (2)
if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs)=============================================================================(3)
If the instance class like _T has attr '_new_meta', then run it with param x;
elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs): (4)
x = super().__call__(*((x,)+args), **kwargs) (5)
==================================================================================================================Start of my srcline exploration:
x => x : <__main__._TestB object>
cls => cls : <class '__main__._T'>
getattr(cls,'_bypass_type',object) => getattr(cls,'_bypass_type',object) : <class '__main__._TestB'>
isinstance(x, _TestB) => isinstance(x, _TestB) : True
isinstance(x,getattr(cls,'_bypass_type',object)) => isinstance(x,getattr(cls,'_bypass_type',object)) : True
====================================================================================================================End of my srcline exploration:
Review srcode with all comments added so far======================================================================================================
class BypassNewMeta(FixSigMeta):==========================================================(0)
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"===============(1)
def __call__(cls, x=None, *args, **kwargs):===========================================(2)
if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs)===============(3) # If the instance class like _T has attr '_new_meta', then run it with param x;;
elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs): (4)
x = super().__call__(*((x,)+args), **kwargs)==================================(5)
if cls!=x.__class__: x.__class__ = cls============================================(6)
return x==========================================================================(7)
(8)
part No.1 out of 1 parts
====================================================== Investigating BypassNewMeta =======================================================
=============================================================== on line 4 ================================================================
with example
class _TestA: pass
class _TestB: pass
class _T(_TestA, metaclass=BypassNewMeta):
_bypass_type=_TestB
def __init__(self,x): self.x=x
t = _TestB()
t2 = _T(t)
t2.new_attr = 15
test_is(t, t2)
# since t2 just references t these will be the same
test_eq(t.new_attr, t2.new_attr)
# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
t.new_attr = 9
test_eq(t2.new_attr, 9)
# both t and t2's __class__ is _T
test_eq(t.__class__, t2.__class__)
test_eq(t.__class__, _T)
print selected srcline with expands below--------
def __call__(cls, x=None, *args, **kwargs): (2)
if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs) (3)
elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs):==========================================================(4)
when x is not an instance of _T's _bypass_type; or when a positional param is given; or when a keyword arg is given; let's run _T's super's __call__ function with x as param; and assign the result to x
x = super().__call__(*((x,)+args), **kwargs) (5)
if cls!=x.__class__: x.__class__ = cls (6)
Review srcode with all comments added so far======================================================================================================
class BypassNewMeta(FixSigMeta):==========================================================(0)
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"===============(1)
def __call__(cls, x=None, *args, **kwargs):===========================================(2)
if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs)===============(3) # If the instance class like _T has attr '_new_meta', then run it with param x;;
elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs): # when x is not an instance of _T's _bypass_type; or when a positional param is given; or when a keyword arg is given; let's run _T's super's __call__ function with x as param; and assign the result to x; (4)
x = super().__call__(*((x,)+args), **kwargs)==================================(5)
if cls!=x.__class__: x.__class__ = cls============================================(6)
return x==========================================================================(7)
(8)
part No.1 out of 1 parts
====================================================== Investigating BypassNewMeta =======================================================
=============================================================== on line 6 ================================================================
with example
class _TestA: pass
class _TestB: pass
class _T(_TestA, metaclass=BypassNewMeta):
_bypass_type=_TestB
def __init__(self,x): self.x=x
t = _TestB()
t2 = _T(t)
t2.new_attr = 15
test_is(t, t2)
# since t2 just references t these will be the same
test_eq(t.new_attr, t2.new_attr)
# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
t.new_attr = 9
test_eq(t2.new_attr, 9)
# both t and t2's __class__ is _T
test_eq(t.__class__, t2.__class__)
test_eq(t.__class__, _T)
print selected srcline with expands below--------
elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs): (4)
x = super().__call__(*((x,)+args), **kwargs) (5)
if cls!=x.__class__: x.__class__ = cls==========================================================================================================(6)
If x.__class__ is not cls or _T, then make it so
return x (7)
(8)
Review srcode with all comments added so far======================================================================================================
class BypassNewMeta(FixSigMeta):==========================================================(0)
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"===============(1)
def __call__(cls, x=None, *args, **kwargs):===========================================(2)
if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs)===============(3) # If the instance class like _T has attr '_new_meta', then run it with param x;;
elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs): # when x is not an instance of _T's _bypass_type; or when a positional param is given; or when a keyword arg is given; let's run _T's super's __call__ function with x as param; and assign the result to x; (4)
x = super().__call__(*((x,)+args), **kwargs)==================================(5)
if cls!=x.__class__: x.__class__ = cls============================================(6) # If x.__class__ is not cls or _T, then make it so;
return x==========================================================================(7)
(8)
part No.1 out of 1 parts
====================================================== Investigating BypassNewMeta =======================================================
=============================================================== on line 1 ================================================================
with example
class _TestA: pass
class _TestB: pass
class _T(_TestA, metaclass=BypassNewMeta):
_bypass_type=_TestB
def __init__(self,x): self.x=x
t = _TestB()
t2 = _T(t)
t2.new_attr = 15
test_is(t, t2)
# since t2 just references t these will be the same
test_eq(t.new_attr, t2.new_attr)
# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
t.new_attr = 9
test_eq(t2.new_attr, 9)
# both t and t2's __class__ is _T
test_eq(t.__class__, t2.__class__)
test_eq(t.__class__, _T)
print selected srcline with expands below--------
class BypassNewMeta(FixSigMeta): (0)
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"=============================================================================(1)
BypassNewMeta allows its instance class e.g., _T to choose a specific class e.g., _TestB and change `__class__` of an object e.g., t of _TestB to _T without creating a new object
def __call__(cls, x=None, *args, **kwargs): (2)
if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs) (3)
Review srcode with all comments added so far======================================================================================================
class BypassNewMeta(FixSigMeta):==========================================================(0)
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"===============(1) # BypassNewMeta allows its instance class e.g., _T to choose a specific class e.g., _TestB and change `__class__` of an object e.g., t of _TestB to _T without creating a new object;
def __call__(cls, x=None, *args, **kwargs):===========================================(2)
if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs)===============(3) # If the instance class like _T has attr '_new_meta', then run it with param x;;
elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs): # when x is not an instance of _T's _bypass_type; or when a positional param is given; or when a keyword arg is given; let's run _T's super's __call__ function with x as param; and assign the result to x; (4)
x = super().__call__(*((x,)+args), **kwargs)==================================(5)
if cls!=x.__class__: x.__class__ = cls============================================(6) # If x.__class__ is not cls or _T, then make it so;
return x==========================================================================(7)
(8)
part No.1 out of 1 parts
'cls._bypass_type', "isinstance(x,getattr(cls,'_bypass_type',object))"]) fdb.snoop([
23:28:43.75 >>> Call to BypassNewMeta.__call__ in File "/tmp/BypassNewMeta.py", line 5
23:28:43.75 .......... cls = <class '__main__._T'>
23:28:43.75 .......... x = <__main__._TestB object>
23:28:43.75 .......... args = ()
23:28:43.75 .......... kwargs = {}
23:28:43.75 .......... __class__ = <class 'fastcore.meta.BypassNewMeta'>
23:28:43.75 .......... cls._bypass_type = <class '__main__._TestB'>
23:28:43.75 .......... isinstance(x,getattr(cls,'_bypass_type',object)) = True
23:28:43.75 5 | def __call__(cls, x=None, *args, **kwargs):
23:28:43.76 6 | if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs)
23:28:43.76 7 | elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs):
23:28:43.76 9 | if cls!=x.__class__: x.__class__ = cls
23:28:43.76 ...... x = <__main__._T object>
23:28:43.76 ...... isinstance(x,getattr(cls,'_bypass_type',object)) = False
23:28:43.76 10 | return x
23:28:43.76 <<< Return value from BypassNewMeta.__call__: <__main__._T object>
====================================================== Investigating BypassNewMeta =======================================================
============================================================== on line None ==============================================================
with example
class _TestA: pass
class _TestB: pass
class _T(_TestA, metaclass=BypassNewMeta):
_bypass_type=_TestB
def __init__(self,x): self.x=x
t = _TestB()
t2 = _T(t)
t2.new_attr = 15
test_is(t, t2)
# since t2 just references t these will be the same
test_eq(t.new_attr, t2.new_attr)
# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
t.new_attr = 9
test_eq(t2.new_attr, 9)
# both t and t2's __class__ is _T
test_eq(t.__class__, t2.__class__)
test_eq(t.__class__, _T)
fdb.debug()
BypassNewMeta's dbsrc code: ==============
class BypassNewMeta(FixSigMeta):
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"
import snoop
@snoop(watch=("cls._bypass_type","isinstance(x,getattr(cls,'_bypass_type',object))"))
def __call__(cls, x=None, *args, **kwargs):
if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs)
elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs):
x = super().__call__(*((x,)+args), **kwargs)
if cls!=x.__class__: x.__class__ = cls
return x
BypassNewMeta's example processed with dbsrc: ===============
class _TestA: pass
class _TestB: pass
class _T(_TestA, metaclass=self.dbsrc):
_bypass_type=_TestB
def __init__(self,x): self.x=x
t = _TestB()
t2 = _T(t)
t2.new_attr = 15
test_is(t, t2)
# since t2 just references t these will be the same
test_eq(t.new_attr, t2.new_attr)
# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
t.new_attr = 9
test_eq(t2.new_attr, 9)
# both t and t2's __class__ is _T
test_eq(t.__class__, t2.__class__)
test_eq(t.__class__, _T)
print() fdb.
====================================================== Investigating BypassNewMeta =======================================================
============================================================== on line None ==============================================================
with example
class _TestA: pass
class _TestB: pass
class _T(_TestA, metaclass=BypassNewMeta):
_bypass_type=_TestB
def __init__(self,x): self.x=x
t = _TestB()
t2 = _T(t)
t2.new_attr = 15
test_is(t, t2)
# since t2 just references t these will be the same
test_eq(t.new_attr, t2.new_attr)
# likewise, chaning an attribute on t will also affect t2 because they both point to the same object.
t.new_attr = 9
test_eq(t2.new_attr, 9)
# both t and t2's __class__ is _T
test_eq(t.__class__, t2.__class__)
test_eq(t.__class__, _T)
class BypassNewMeta(FixSigMeta):==========================================================(0)
"Metaclass: casts `x` to this class if it's of type `cls._bypass_type`"===============(1) # BypassNewMeta allows its instance class e.g., _T to choose a specific class e.g., _TestB and change `__class__` of an object e.g., t of _TestB to _T without creating a new object;
def __call__(cls, x=None, *args, **kwargs):===========================================(2)
if hasattr(cls, '_new_meta'): x = cls._new_meta(x, *args, **kwargs)===============(3) # If the instance class like _T has attr '_new_meta', then run it with param x;;
elif not isinstance(x,getattr(cls,'_bypass_type',object)) or len(args) or len(kwargs): # when x is not an instance of _T's _bypass_type; or when a positional param is given; or when a keyword arg is given; let's run _T's super's __call__ function with x as param; and assign the result to x; (4)
x = super().__call__(*((x,)+args), **kwargs)==================================(5)
if cls!=x.__class__: x.__class__ = cls============================================(6) # If x.__class__ is not cls or _T, then make it so;
return x==========================================================================(7)
(8)