Python: How can a class inherit from a function? - python

Here's a piece of code that I cannot understand:
class COWMeta(type):
pass
class COWDictMeta(COWMeta):
....
I know how to create a new class in python:
class MyClass(BaseClass):
...
But as the manual states, 'type' is function.
type(...)
Function of __builtin__ module
type(object) -> the object’s type type(name, bases, dict) -> a new type
How can a class inherit from a function? And what does that piece of code mean?

type is the basic object type in python. Like many object types in python, it acts as a constructor for creating new types, but in it's simplest form it'll return the type of existing objects. It then looks like a function. Compare this to int() and list(), for example.
In python, you can create new types, also called metaclasses, allowing you to do all sorts of powerful and interesting tricks in Python. Basing a class definition on type means you are creating a new metaclass.
See What is a metaclass in Python? for an in-depth answer on what metaclasses are.

type is not a function in the same way that, eg:
def foo():
pass
is a function. It is callable like a function (and like many other objects in Python), but it is actually coded as a class. type itself can show you this difference:
>>> type(type)
<class 'type'>
>>> type(foo)
<class 'function'>
The docs call it a 'function' not because of how it is implemented, but because of how it is commonly used. This is broadly similar to, for example, itertools.permutations, which while not explicitly called a function by the docs is implied to be one:
Return successive r length permutations of elements in the iterable.
But itertools.permutations is implemented as a class:
>>> type(itertools.permutations)
<class 'type'>

Related

Are "Iterable", "Iterator" examples of types in python?

This is a question about how python's (dynamic) type system works. I have read articles online saying that to define a class to be "an iterable", we need to define a __iter__ function for it. We don't in fact have to explicitly state that that class "is an iterable". I would have guessed based on experience with other languages that I'd have to write something like
class Foo extends Iterable:
def __iter__(self):
return self
When I test the type of Foo and one of its instances I get:
print(type(Foo))
print(type(Foo()))
print(isinstance(Foo(), collections.abc.Iterable))
Output:
<class 'type'>
<class '__main__.Foo'>
True
My question is: What is the status of a concept like "Iterable" in python's (dynamic) type system? Should I think of it as having anything to do with types at all?
A type is what python calls any object that's been defined via a class statement. Using Java as a reference point, type is akin to java.lang.Class - the class that represents classes.
"Iterable" is more akin to an interface than a class - whereas a class/type defines both an internal state and certain methods, an interface only defines those methods. Python doesn't formalize this like other languages, but the principle is used in most of python's "hidden" methods (the ones that have two underscores on both sides). If a particular hidden method is defined for a class (for example, __iter__()), then that class is considered to be iterable*.
In your example, you use isinstance() to prove your point. The python documentation actually has a page on collections.abc, which goes into detail about their behavior:
This module provides abstract base classes that can be used to test whether a class provides a particular interface; for example, whether it is hashable or whether it is a mapping.
(bold added for emphasis).
And it even mentions Iterators specifically:
class collections.abc.Iterable
ABC for classes that provide the __iter__() method.
Checking isinstance(obj, Iterable) detects classes that are registered as Iterable or that have an __iter__() method, but it does not detect classes that iterate with the __getitem__() method. The only reliable way to determine whether an object is iterable is to call iter(obj).
Python allows for ABC classes essentially hijack the builtin isinstance() call via defining the __instancecheck__() metaclass method, which is why isinstance(Foo(), Iterable) is able to return True despite Foo not inheriting from Iterable.
*while the inputs and outputs for these functions aren't as strictly defined as in static-typed languages like Java, the built-in methods that call them have very specific expectations that, in effect, result in the same thing. For example, I once ran into a problem trying to override __len__() on an object to return a float instead of an int, because the built-in len() threw an error when I tried to use it on that object.

Python introspection: Where does the mro() method live?

I am trying to acquire a basic understanding of python introspection and in doing so I found the in that regard useful mro() method mentioned here.
When I (as an introspection exercise) tried to use said method and the builtin dir() function in an attempt to find out where mro() might live, I however was unable to succeed. Why?
Here is my approach:
the mro() method obviously is available without any imports (unlike inspect.getmro() which is part of the inspect module; e.g. str.mro() returns [<class 'str'>, <class 'object'>]
Since str.mro() returns [<class 'str'>, <class 'object'>], the mro() method should live somewhere in str and/or object.
Yet neither dir(str) nor dir(object) appear to contain the mro() method. Also help() and help(str.mro) do not enlighten the puzzled student of introspection.
If you look with dir(type) you'll find the magic method attribute __mro__. Quoted from here:
class.__mro__
This attribute is a tuple of classes that are considered when looking for base classes during method resolution.
class.mro()
This method can be overridden by a metaclass to customize the method resolution order for its instances. It is called at class instantiation, and its result is stored in mro
Look at this answer for more about type which is the usual metaclass used in Python. Quoted from there:
type is the usual metaclass in Python. type is itself a class, and it is its own type. You won't be able to recreate something like type purely in Python, but Python cheats a little. To create your own metaclass in Python you really just want to subclass type.

Change the behavior of the type() function on a user-created class

So I want to change how the type() function works on a class that I create. I'll create two classes, one "old style" class and one "new style" which inherits from object, to demonstrate what I mean:
class Foo:
pass
class Bar(object):
pass
Now I'll create an instance of each of those:
spam = Foo()
eggs = Bar()
What happens if I use the type() function on each of these classes?
>>> type(spam)
<type 'instance'>
>>> type(eggs)
<class '__main__.Bar'>
I'm looking for a way to alter the behavior of this so that it appears more like this:
>>> type(spam)
<type 'foo'>
I've seen many other objects do this (besides the default data types obviously). For example:
>>> x = iter(['a', 'b', 'c'])
>>> type(x)
<type 'listiterator'>
>>> y = (i for i in range(10))
>>> type(y)
<type 'generator'>
Something like this would come pretty close, but I would prefer not to have the membership dot in the middle if I can help it. (Yes, the code I am using this in will be an imported file.)
>>> from itertools import *
>>> z = imap(pow, (2, 3, 4), (5, 2, 4))
>>> type(z)
<type 'itertools.imap'>
I'm sure the answer to this question is really simple, but for whatever reason I can't figure out how to word a search query on this. Any help would be appreciated.
What type returns when called with a single is the class of an object. The string you see printed there is its "representation", and it is generated by a call to repr for the class. itself - the repr is called by the interactive prompt. Python objects customize their representation by defining a __repr__ method.
Since you want to customize the __repr__ of the class, and not of its instances, you have to overide the method in the class's class itself. In Python that is called metaclass.
The base metaclass for all Python "new style" objects is type itself. type is much more than a simple function to return an object's class - it is actually that thing: the "base metaclass" for everything. (Old style classes have a different metaclass - but them you should not be using old style classes for anything. At all. Seriously. Actually, you should be using Python 3 by now - but if you aren't changing, please just forget old style classes exist)
So, to customize a class's class, you create a new class inheriting from type itself. You will find several blog posts and documentation explaining how to do that and override __new__, or __init__. But in this case, you
don't need to change the actual behavior of your classes cretion - just the way they are represented.
You can just do:
class MyType(type):
def __repr__(cls):
return "<type '{}'>".format (cls.__name__)
class Foo(object):
__metaclass__ = MyType
And it will work as you want. Note that I put the argument for the metaclass' __repr__ as cls instead of self - that is jsut for semantic purposes - it will receive an "instance" of itself - but the instance is a class. It would just work if "self" was used.
And finally, that will also change how your instances are represented by default - and that represenation can get ugly. If you dislike it, just write the __repr__ method for your class as well (not just for the metaclass) , further customizing how it renders its representation to string form.

What is 'type' in Python?

>>> type(type)
<type 'type'>
I expect the type of type to be a function since it's used to return the type of the argument. Does this mean a type can accept arguments? Is type something unusual/special?
type is a metaclass: a class whose instances are also classes. The type of any other builtin class will also be type - eg:
>>> type(object)
<class 'type'>
>>> type(list)
<class 'type'>
Indeed, every (new-style) class will also be an instance of type, although if it is defined with a custom metaclass, type(my_class) will be that metaclass. But since every metaclass is required to inherit from type, you will have, for any class:
>>> isinstance(my_class, type)
True
Classes are objects. All objects are instances of a class. So since a class is an object, it is an instance of some class. The class that a class is an instance of is named type. It is the base metaclass.
Originally type() was just a function that returned an object's class. In Python 2.2, user-defined classes and built-in types were unified, and type became a class. For backward compatibility, it still behaves like the old type() function when called with one argument.
type is Python's class ur-type. When called with a single argument it returns the type of the argument. When called with 3 arguments it returns a class whose characteristics are determined by the arguments.
As can be clearly seen in the documentations -
class type(object)
class type(name, bases, dict)
With one argument, return the type of an object. The return value is a type object. The isinstance() built-in function is recommended for testing the type of an object.
type is a class, not a function.

Why do metaclass have a type?

I've little bit test to fully understand metaclass in python.
class Test(object):
pass
print Test.__class__
print Test.__class__.__class__
print Test.__class__.__class__.__class__
All of result is same type. but each of their address is not same
I can't really understand why metaclass has a metaclass recursively.
Explain me please?
Actually, addresses are the same:
>>> id(Test.__class__)
6384576
>>> id(Test.__class__.__class__)
6384576
>>> id(Test.__class__.__class__.__class__)
6384576
Everything is an object in Python, and each object must have a class (it should belong to some type). You can access that class/type reference by __class__ attribute, e.g.:
>>> (1).__class__
<type 'int'>
Everything includes classes itself, which are of class/type called type:
>>> (1).__class__.__class__
<type 'type'>
In the same time type 'type'> is also an object and should reference to some class/type. But since this is kind of special object, its __class__ attribute refers to itself:
>>> (1).__class__.__class__.__class__ is (1).__class__.__class__
True
When you do Test.__class__, you get back the type of Test, which is type (because Test is a class identifier).
type itself is again a class identifier, so you can call __class__ (which is inherited from object) on it and you get back that its type is, again, type because it is a class identifier.
Because you will always get back type which is a class itself, you can do this infinitely many times and will always get back that the current object's type is type.
All classes are classes which means they are derived from a class called class...
All the python's class object is build by the built-in function type(). You could also try this.
>>> T.__class__ == type
True
>>> type(type)
<type 'type'>
The T.class is equal to the build-in function type which is also an object implemented the call function. It's a attribute will be interpret as class(T). As your T class have no base class so type() is used which will return the type object.
You could check the python doc about customizing class creation to get detail about class creation.
To determining the appropriate metaclass
if no bases and no explicit metaclass are given, then type() is used
if an explicit metaclass is given and it is not an instance of type(), then it is used directly as the metaclass
if an instance of type() is given as the explicit metaclass, or bases are defined, then the most derived metaclass is used

Categories

Resources