问题描述:

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.

相关阅读:
Top