3

I was reading this interesting post on metaclasses What is a metaclass in Python?. The accepted answer shows how to create a class using type with the following signature.

type(name of the class, tuple of the parent class (for inheritance, can be empty), dictionary containing attributes names and values)

I tried to create 'type' class using the above signature and I was surprised that I was allowed to create one in the first place! Your views are appreciated!

type = type('type',(),{});

Second, after I created a type class using the above syntax, I was not able to do

myclass = type('myclass',(),{}); 

and type = type('type',(),{});

I got an error saying

Traceback (most recent call last): File "", line 1, in TypeError: object.new() takes no parameters

But, when I tried to the following, I could succeed.

class myclass(object):
    pass

I am puzzled coz, according to my understanding the above snippet should invoke type in an attempt to create the class 'myclass'. So whats going on!? Am I missing some detail?

Community
  • 1
  • 1
Karthick
  • 2,844
  • 4
  • 34
  • 55
  • 1
    For the record, type classes used to refer to metaclasses here are a misnomer; [type classes](http://en.wikipedia.org/wiki/Type_class) are a widely used concept in Functional Programming languages such as Haskell and Scala and have nothing to do with metaclasses. – Erik Kaplun Apr 13 '14 at 17:07

2 Answers2

6

You've shadowed type with type with type = type('type',(),{})

Note that semi-colons are redundant in Python.

So you're creating a type that can't do anything.

That's why the later type breaks.

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
  • Yes.. I agree.. I understand thats what is happening. But my question is Why does python even allow that and type being shadowed, how is class myclass(object) successfull? shouldnt it try to use the type class that I have created and therefore fail? – Karthick Jun 25 '12 at 21:09
  • @Karthick Because it has a philosophy of "consenting adults" - you're *allowed* to over-ride any builtins... I could write a module that says str = int, hex = lambda L: return 'FF' - etc... Python is a language that is flexible and allows control if you *explicitly* wish to do so - this is almost always not what is required though, but the *black magic* is there if you find a **need** to use it – Jon Clements Jun 25 '12 at 21:10
  • I can agree with the philosophy, and then again, I still don understand how type('myclass', (), {}) fails but Class myclass(Object) : pass succeeds – Karthick Jun 25 '12 at 21:13
  • Because it's the difference between a definition and a construction – Jon Clements Jun 25 '12 at 21:15
  • Well if I am overshadowing it, I should be able to do it INSTEAD of the default type rite and isnt it the purpose of over shadowing? Like for example, when you overload operator '+' in C++, you see only overloaded '+' not the default one.. You could either invoke it explicitly with a function or just say + . both would invoke my function not the default. – Karthick Jun 25 '12 at 21:17
  • @karthick No - altering `type` only alters it in a certain namespace (if you want C++ terms). The interpreter still uses the internal functions to construct and intialise an object. – Jon Clements Jun 25 '12 at 21:18
  • Yeah.. you are right regarding the same namespace. I am in the same namespace here when I over shadow and try to invoke.. To give you one more analogy, when you override new operator, with a custom new, then my new would be called and all the code in my namespace would be using my overloaded new if I am right – Karthick Jun 25 '12 at 21:23
  • If you're talking about __new__ which has its scope, that should be passed to an __init__ on a suitable class, then that's not really a scope except the attributes/members/methods of the newly intialised class. – Jon Clements Jun 25 '12 at 21:25
0

Definition

>>> shadow = type("type",(),{})
>>> shadow
<class '__main__.type'>
>>> isinstance(shadow,type)
True
>>> issubclass(shadow,type)
False
>>> shadow(int)

Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    shadow(int)
TypeError: object.__new__() takes no parameters

Construction

>>> class shadow(type):
    pass

>>> shadow
<class '__main__.shadow'>
>>> isinstance(shadow,type)
True
>>> issubclass(shadow,type)
True
>>> shadow(int)
<type 'type'>
>>> shadow(type)
<type 'type'>
>>> shadow(1)
<type 'int'>

Python (and Python C API): __new__ versus __init__

Community
  • 1
  • 1
Paul Seeb
  • 6,006
  • 3
  • 26
  • 38