This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Monkeypatching using metaclass
Type: behavior Stage: resolved
Components: None Versions: Python 2.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Artem.Tomilov, daniel.urban, eric.araujo, ezio.melotti
Priority: normal Keywords:

Created on 2011-10-25 12:45 by Artem.Tomilov, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (5)
msg146366 - (view) Author: Artem Tomilov (Artem.Tomilov) Date: 2011-10-25 12:45
from abc import ABCMeta

class Meta(ABCMeta):
    def __instancecheck__(cls, instance):
        # monkeypatching class method
        cls.__subclasscheck__ = super(Meta, cls).__subclasscheck__
        return super(Meta, cls).__instancecheck__(instance)

    def __subclasscheck__(cls, sub):
        return cls in sub.mro()

class A(object):
    __metaclass__ = Meta

class B(object): pass

# registering class 'B' as a virtual subclass of 'A'
A.register(B)

>>> issubclass(B, A)
False
>>> isinstance(B(), A) # => method __subclasscheck__ is now monkeypatched
True
>>> issubclass(B, A) # => desire to get 'True' because 'B' is a virtual subclass
False
msg146395 - (view) Author: Daniel Urban (daniel.urban) * (Python triager) Date: 2011-10-25 19:40
> class Meta(ABCMeta):
>     def __instancecheck__(cls, instance):
>         # monkeypatching class method
>         cls.__subclasscheck__ = super(Meta, cls).__subclasscheck__

This line is approximately the same as:
        cls.__dict__['__subclasscheck__'] = ...
So it will put the object in the namespace of cls. The function in the namespace of type(cls) will remain there. (Also, the object you put in there is a bound method, so this is probably not what you want.)


>         return super(Meta, cls).__instancecheck__(instance)
> 
>     def __subclasscheck__(cls, sub):
>         return cls in sub.mro()
> 
> class A(object):
>     __metaclass__ = Meta
> 
> class B(object): pass
> 
> # registering class 'B' as a virtual subclass of 'A'
> A.register(B)
> 
> >>> issubclass(B, A)
> False
> >>> isinstance(B(), A) # => method __subclasscheck__ is now
> monkeypatched

A.__dict__['__subclasscheck__'] is now indeed the other method you put in there, but issubclass will call  type(A).__dict__['__subclasscheck__'] which remain the same. (Because __special__ methods a looked up directly in the namespace of the type of an object, see http://docs.python.org/dev/py3k/reference/datamodel#special-lookup).
msg147483 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2011-11-12 13:47
It seems to me this is not a bug.  Closing?
msg147528 - (view) Author: Daniel Urban (daniel.urban) * (Python triager) Date: 2011-11-12 19:40
> It seems to me this is not a bug.

+1
msg147593 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2011-11-14 13:24
Artem, if you have further information to make us reconsider this issue, please add a new message.
History
Date User Action Args
2022-04-11 14:57:23adminsetgithub: 57473
2011-11-14 13:24:35eric.araujosetstatus: open -> closed
resolution: not a bug
messages: + msg147593

stage: resolved
2011-11-12 19:40:19daniel.urbansetmessages: + msg147528
2011-11-12 13:47:25eric.araujosetnosy: + eric.araujo
messages: + msg147483
2011-10-25 19:40:44daniel.urbansetmessages: + msg146395
2011-10-25 18:49:00daniel.urbansetnosy: + daniel.urban
2011-10-25 12:49:05ezio.melottisetnosy: + ezio.melotti
2011-10-25 12:45:05Artem.Tomilovcreate