I noticed this from the docstring of __build_class__:
__build_class__(func, name, *bases, metaclass=None, **kwds) -> class
Internal helper function used by the class statement.
The part that intrigued me was the **kwds part. Can class definitions take keyword arguments? I tried it, but I got a very strange error:
>>> class Test(a=1):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type() takes 1 or 3 arguments
What's the deal here? Can classes in Python 3 somehow accept keyword arguments? Maybe a special metaclass is required?
Can classes in Python 3 somehow accept keyword arguments?
Yes. Any keyword arguments in the class statement besides metaclass are passed to the metaclass. If the metaclass argument is specified, it's used as the metaclass; otherwise, the metaclass is type. See PEP 3115 for more details.
Related
I have been wondering this for a while now, and I hope this isn't a stupid question with an obvious answer I'm not realizing: Why can't I just call the __init__ method of super() like super()()? I have to call the method like this instead: super().__init__()
Here is an example that gets a TypeError: 'super' object is not callable error when I run it (specifically on line 6 that comes from line 3 in __init__):
class My_Int(int):
def __init__(self,value,extr_data=None):
super()(value)
self.extr_data=extr_data
x=My_Int(3)
Doesn't super() get the inherited class int making super()(value) the same as int(value)?
Furthermore, why can't I use the len function with super() when inheriting from the class list? Doesn't len() do the same as __len__()?
class My_List(list):
def some_method1(self):
print(len(super()))
def some_method2(self):
print(super().__len__())
x=My_List((1,2,3,4))
x.some_method2()
x.some_method1()
This example prints 4 and then an error as expected. Here is the output exactly:
4
Traceback (most recent call last):
File "/home/user/test.py", line 11, in <module>
x.some_method1()
File "/home/user/test.py", line 3, in some_method1
print(len(super()))
TypeError: object of type 'super' has no len()
Notice I called some_method2 before calling some_method1 (sorry for the confusion).
Am I missing something obvious here?
P.S. Thanks for all the help!
super() objects can't intercept most special method calls, because they bypass the instance and look up the method on the type directly, and they don't want to implement all the special methods when many of them won't apply for any given usage. This case gets weirder, super()() would try to lookup a __call__ method on the super type itself, and pass it the super instance.
They don't do this because it's ambiguous, and not particularly explicit. Does super()() mean invoke the super class's __init__? Its __call__? What if we're in a __new__ method, do you invoke __new__, __init__ or both? Does this mean all super uses must implicitly know which method they're called in (even more magical than knowing the class they were defined in and the self passed when constructed with zero arguments)?
Rather than deal with all this, and to avoid implementing all the special methods on super just so it can delegate them if they exist on the instance in question, they required you to explicitly specify the special method you intend to call.
I am trying to create metaclass:
from typing import Tuple
class StructMeta(Tuple):
pass
class Struct(metaclass=StructMeta):
pass
print(type(Struct))
Execute:
Traceback (most recent call last):
File "main.py", line 9, in <module>
class Struct(metaclass=StructMeta):
TypeError: tuple expected at most 1 argument, got 3
Do not understand why this error?
typing.Tuple appears to be a subclass of tuple, which only takes one argument, an iterable.
When creating a class, Python passes 3 arguments to its metaclass: the class name, a tuple of base classes, and a dict representing the class body.
It's not really possible to use typing.Tuple as a metaclass.
I have two classes
class Something(object):
def __init__(self):
self.thing = "thing"
class SomethingElse(Something):
def __init__(self):
self.thing = "another"
as you can see, one inherits from another.
When I run super(SomethingElse), no error is thrown. However, when I run super(SomethingElse).__init__(), I was expecting an unbound function call (unbound to a hypothetical SomethingElse instance) and so was expecting that __init__() would complain about not receiving an object for its self parameter, but instead I get this error:
TypeError: super() takes at least 1 argument (0 given)
What is the meaning of this message?
EDIT: I often see people hand-wave answer a super question, so please don't answer unless you really know how the super delegate is working here, and know about descriptors and how they are used with super.
EDIT: Alex suggested I update my post with more details. I'm getting something different now in both ways I used it for 3.6 (Anaconda). Not sure what is going on. I don't receive what Alex did, but I get:
class Something(object):
def __init__(self):
self.thing = "thing"
class SomethingElse(Something):
def __init__(self):
super(SomethingElse).__init__()
The calls (on Anaconda's 3.6):
SomethingElse()
<no problem>
super(SomethingElse).__init__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: super(): no arguments
super(SomethingElse).__init__(SomethingElse())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: super() argument 1 must be type, not SomethingElse
My understanding of super was that, according to https://docs.python.org/3/library/functions.html#super, that super() with just the first argument would leave the super object unbounded to an instance, so that if you called __init__() on the super object, you'd need to pass in an instance as __init__() would be unbounded as well. However, 3.6 complains about how, with super(SomethingElse).__init__(SomethingElse(), SomethingElse isn't a type, which it should be as it inherits from a parent that inherits from object.
on 2.7.13 gives the original error for super(SomethingElse).__init__(), which was TypeError: super() takes at least 1 argument (0 given). For super(SomethingElse).__init__(SomethingElse()) it throws TypeError: super() argument 1 must be type, not SomethingElse
Calling super with 1 argument produces an "unbound" super object. Those are weird and undocumented and mostly useless, and I won't go into how they were intended to be used, but for the purposes of this answer, we really only need to know one thing about them.
super(SomethingElse).__init__ doesn't go through the usual super proxy logic. You're getting the super instance's own __init__ method, not anything related to SomethingElse.
From there, the rest of the behavior follows. The TypeError: super() takes at least 1 argument (0 given) on Python 2 is because super.__init__ takes at least 1 argument, and you're passing it 0. (You might expect it to say TypeError: super() takes at least 2 arguments (1 given) because it's still getting self - the super object self, not the SomethingElse instance - but due to weird implementation details, methods implemented in C generally don't count self for this kind of error message.)
SomethingElse() succeeds on Python 3 because the super constructor pulls __class__ and self from the usual stack inspection magic.
Calling super(SomethingElse).__init__() manually from outside the class produces RuntimeError: super(): no arguments because super.__init__ tries to do its stack inspection magic and doesn't find __class__ or self.
super(SomethingElse).__init__(SomethingElse()) fails because the first argument to the super constructor is supposed to be a type, not an instance.
I need to pass a kwargs to a Python instance method but get the following error below.
class test(object):
def __init__(self):
print 'Initializaed'
def testmethod(self,**kwargs):
for each in kwargs:
print each
x = test()
x.testmethod({"name":"mike","age":200})
Error:
Traceback (most recent call last):
File "C:\Users\AN\workspace\Scratch\Scratch\test.py", line 20, in <module>
x.testmethod({"name":"mike","age":200})
TypeError: testmethod() takes exactly 1 argument (2 given)
x.testmethod({"name":"mike","age":200})
This invokes testmethod() with two positional arguments - one is implicit (the object instance, i.e. self) and the other one is the dictionary you gave it.
To pass in keyword arguments, use the ** operator for unpacking your dictionary into key=value pairs, like this:
x.testmethod(**{"name":"mike","age":200})
This translates to x.testmethod(name='mike', age=200) which is what you want. You can also read about argument unpacking in the documentation.
I have zero idea as to why I'm getting this error.
as people said, the 2 arguments of issubclass() should be classes, not instances of an object.
consider this sample:
>>> issubclass( 1, int )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: issubclass() arg 1 must be a class
>>> issubclass( type(1), int )
True
>>> isinstance( 1, int )
True
the key is the use of the type() function to get the type of an instance for use with the issubclass() function, which, as noted in another comment, is equivalent to calling isinstance()
It means that you don't provide a class as argument for issubclass(). Both arguments have to be classes. Second argument can also be a tuple of classes.
If you show the code that throws this error, we can help further.
From the documentation:
issubclass(class, classinfo)
Return true if class is a subclass (direct or indirect) of classinfo. A class is considered a subclass of itself. classinfo may be a tuple of class objects, in which case every entry in classinfo will be checked. In any other case, a TypeError exception is raised.
When you use "=" instead of ":" declaring an attibute of class, you get the error:
TypeError: issubclass() arg 1 must be a class. The number 1 say you that you have the error in the first argument
this is incorrect:
class AnyClass(BaseClass):
email = str
this is correct:
class AnyClass(BaseClass):
email : str
For those using Pydantic or FastAPI and having problems with this error.
Here is the answer https://stackoverflow.com/a/70384637/7335848
Basically this method tells you if the first parameter is a subclass of the second. So naturally, both your parameters need to be classes. It appears from your call, that you have called issubclass without any parameters, which confuses the interpreter.
Calling issubclass is like asking the interpreter: "Hey! is this class a subclass of this other class?". However, since you have not provided two classes, you have essentially asked the interpretter: "Hey! I'm not going to show you anything, but tell me if this it's a subclass". This confuses the interpreter and that's why you get this error.
This error message donĀ“t say where is the real problem, for example in my case the first argument of the class was the right one,the problem was I was using a Literal typing in class property declaration. No errors from linter, no errors anywhere but for cause of this, my class was not able to be converted to another class that was needed in runtime. Just removing this Literal type fixed my error.
The first argument to issubclass() needs to be of type "class".
http://pyref.infogami.com/issubclass