On the inheritance relationship of overloaded isinstance in Python

Source: Internet
Author: User
This article mainly introduces the question about the inheritance relation of the overloaded isinstance in Python, has certain reference value, now share to everybody, the need friend can refer to

Judging inheritance Relationships

The built-in method Isinstance (object, ClassInfo) can determine whether an object is an instance of a class. This relationship can be direct, indirect, or abstract.

The check of the instance is to allow the overloaded, visible document Customizing-instance-and-subclass-checks. Based on the description of PEP 3119:

The primary mechanism proposed here are to allow overloading the built-in functions isinstance () and Issubclass (). The overloading works as Follows:the call Isinstance (x, C) first checks whether c.__instancecheck__ exists, and if so, CA LLS c.__instancecheck__ (x) instead of its normal implementation.

This passage means that when isinstance (x, C) is called for detection, it will first check for the presence of c.__instancecheck__, and if so, call c.__instancecheck__ (x), and the result of the return is the result of the instance detection. The default way of judging is gone.

This approach helps us to check the duck type, which I measured with the code.

Class sizeable (object):  def __instancecheck__ (CLS, instance):    print ("__instancecheck__ call")    return Hasattr (instance, "__len__") class B (object):  PASSB = B () print (Isinstance (b, sizeable)) # Output:false

Only False is printed, and __instancecheck__ is not called. What's going on.

No running __instancecheck__

The document is not clearly written, in order to find the problem, we start tracking from the isinstance source code.

[Abstract.c]intpyobject_isinstance (Pyobject *inst, Pyobject *cls) {  _py_identifier (__instancecheck__);  Pyobject *checker;  /* Quick test for an exact match */  if (py_type (inst) = = (Pytypeobject *) CLS)    return 1;  ....}

Py_type (Inst) = = (Pytypeobject *) CLS This is a quick match, equivalent to the TYPE (inst) is CLS, and this fast way of matching succeeds does not check for __instancecheck__. So there is c.__instancecheck__ error in the priority check in the document. Continue to look down the source:

  /* We know what type ' s __instancecheck__ does. */  if (Pytype_checkexact (CLS)) {    return recursive_isinstance (Inst, CLS);  }

Expand Macro Pytype_checkexact:

[Object.h] #define PYTYPE_CHECKEXACT (OP) (Py_type (OP) = = &pytype_type)

In other words, the CLS is a class constructed directly from the type, then the judgment language is established. In addition to the metaclass specified in the class declaration, the basic is constructed directly from the type. From the test code to know that the judgment is established, into the recursive_isinstance. But in this function I did not find the code about __instancecheck__, Recursive_isinstance's judgment logic is roughly:

def recursive_isinstance (Inst, CLS):  return Pytype_issubtype (Inst, CLS) def Pytype_issubtype (A, B): For  MRO in a . __mro__:    If MRO is B:      return True  return False

is judged from the __mro__ inheritance order. Go back to the pyobject_isinstance function and look down:

if (Pytuple_check (CLS)) {  ...}

This is when the second parameter of instance (x, C) is a tuple, where the processing is recursively called pyobject_isinstance (Inst, item). Keep looking down:

Checker = _pyobject_lookupspecial (CLS, &pyid___instancecheck__), if (checker! = NULL) {  res = pyobject_ Callfunctionobjargs (Checker, Inst, NULL);  OK = pyobject_istrue (res);  return OK;}

Obviously, this is the place to get __instancecheck__, in order for the inspection process to come here, the defined class to indicate metaclass. The rest is to track down _pyobject_lookupspecial on it:

[TYPEOBJECT.C] Pyobject *_pyobject_lookupspecial (Pyobject *self, _py_identifier *attrid) {  pyobject *res;  res = _pytype_lookupid (Py_type (self), attrid);  Have callback words to handle callback  //...  return res;}

The Py_type (self) is taken, meaning that __instancecheck__ is defined within the specified metaclass.

Summarize

Now, summarize the conditions for overloading the isinstance (x, C) behavior:

    1. The X object cannot be instantiated directly by C;

    2. Class C designation Metaclass;

    3. __INSTANCECHECK__ is defined in the specified Metaclass class.

Test code:

Class Metasizeable (Type):  def __instancecheck__ (CLS, instance):    print ("__instancecheck__ call")    return Hasattr (instance, "__len__") class sizeable (metaclass=metasizeable):  passclass B (object):  PASSB = B () print ( Isinstance (b, sizeable)) # Output:falseprint (Isinstance ([], sizeable)) # Output:true

The documentation may be a bit old. The environment for this test is Python3.6.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.