I have a problem with understanding function super() behavior in abc.ABCMeta class in python3.6.
class ParentClass():
def test():
return 1
#six.add_metaclass(ABCMeta)
class ChildClass(ParentClass):
def test(self):
test_ = super().test
test_ = 2
return test_
a = ChildClass()
a.test()
Code failed with 'TypeError: super(type, obj): obj must be an instance or subtype of type'.
When I used super(ChildClass, self).test it worked correctly! Printing from ChildClass test function:
print(__class__)
print(type(__class__))
print(ChildClass)
print(type(ChildClass))
I get next output:
<class '__main__.ChildClass'>
<class 'type'>
<class '__main__.ChildClass'>
<class 'abc.ABCMeta'>
I feel that the reason in object initialization but I can't undersand this information with my current skills in OOP and Python OOP.
0-argument super uses the class in which the call actually appeared, but after #six.add_metaclass(ABCMeta), the class bound to the ChildClass name is a new class created by the decorator. 0-argument super is still using the original class.
If you're going to use 0-argument super, which only works on Python 3, just use Python 3 metaclass syntax instead of six.
Related
This question already has answers here:
Difference between #staticmethod and #classmethod
(35 answers)
Class (static) variables and methods
(27 answers)
Closed 9 months ago.
The output of:
class Dog():
def get_class():
return __class__
class Cat():
def get_class():
return __class__
print(Dog.get_class())
print(Cat.get_class())
is:
<class '__main__.Dog'>
<class '__main__.Cat'>
I want to DRY up my code with a subclass. But the output of:
class BaseClass():
def get_class():
return __class__
class Dog(BaseClass):
pass
class Cat(BaseClass):
pass
print(Dog.get_class())
print(Cat.get_class())
is
<class '__main__.BaseClass'>
<class '__main__.BaseClass'>
How do I change the code in the second case to obtain the same output as the first case?
you are almost there :
class BaseClass:
#classmethod
def get_class(cls):
return cls
class Dog(BaseClass):
pass
class Cat(BaseClass):
pass
print(Dog.get_class())
print(Cat.get_class())
<class '__main__.Dog'>
<class '__main__.Cat'>
There are a few different issues here.
The logic we are implementing is simply "get the class". If you want to do this starting specifically and only from the class, then there is nothing to do, and no reason to implement anything inside the BaseClass or Dog or Cat to get that result - because you already have it.
class BaseClass:
pass
class Dog(BaseClass):
pass
class Cat(BaseClass):
pass
print(Dog)
print(Cat)
__class__ is a special local variable that is used for the implementation of super(). It names the class where the method is defined, regardless of how that method was looked up, or even if it was used as a plain function:
>>> class x:
... def example(self):
... print(__class__)
...
>>> class y(x): pass
...
>>> x().example()
<class '__main__.x'>
>>> y().example()
<class '__main__.x'>
>>> x.example(42)
<class '__main__.x'>
Normally, a method that does not expect to receive an instance of the class should be decorated with either #classmethod or #staticmethod. This way, the code can still be used with either a class or an instance.
The rules are:
#classmethod - called with a class, the first argument is that class itself; called with an instance, the first argument is the instance's class. The parameters should include one at the start to receive that argument. By convention, we call that parameter cls.
#staticmethod - called with either a class or an instance, no argument is added for the call. The parameters should only list what will be explicitly passed.
No decorator - called with a class, no argument is added; called with an instance, the instance is added. This should be used only for instances, thus there should be a parameter to receive the instance argument. By convention, we call that parameter self.
Trying to use a function inside a class without either a decorator or self violates the standard expectations. It tries to treat the class as simply a namespace. This is not what they are for, even thought it sort of works.
Supposing that we want the code to work with either a class (giving us back that class) or an instance (giving us back that instance's class), the code is trivial: a #classmethod-decorated method already receives a parameter that is exactly what we want, in every case, so we simply return that. Thus:
class BaseClass:
#classmethod
def get_class(cls):
return cls
class Dog(BaseClass):
pass
class Cat(BaseClass):
pass
print(Dog.get_class())
print(Dog().get_class())
print(Cat.get_class())
print(Cat().get_class())
I have 2 scripts, 1st is All_Methods, and another is All_Testcases, as I am using unittest framework, so here we go.
All_Methods is like:
class All_Services():
def abc(self):
x =1
def bca(self):
print "My Name is Taimoor"
self.abc()
def cba(self):
self.bca()
and on another script which is All_TestCases is like this:
from All_Methods import All_Services as service
class All_TestCases(unittest.TestCase):
def test_1_running_method(self)
service.cba(self)
Exception showing is:
AttributeError: 'All_TestCases' object has no attribute 'bca'
Kindly someone tell me, what I am missing here?
Thanks.
You are not using classes in the usual way when you pass in self to methods that you call on the class. Common is to call the methods on instances of the class and getting the self argument implicitly.
When you call Method.running_query_Athena(self) self is an instance of All_TestCases which does not have the method connecting_Athena.
Did you mean for All_TestCases to derive from All_Methods?
Why is All_Methods a class at all?
Use proper indentation since python is solely based on the basis of how the code is indented.
Please, Please use proper naming conventions; as advised under PEP 8.
You're trying to access an instance method without an instance.
Try the following:
class MyClass:
def my_instance_method(self):
return True
#classmethod
def my_class_method(cls):
return True
#staticmethod
def my_static_method():
return True
This won't work:
>> MyClass.my_instance_method()
TypeError: my_instance_method() missing 1 required positional argument: 'self'
but these will since they are not bound to a class instance being created.
MyClass.my_class_method()
MyClass.my_static_method()
An instance method requires that you instantiate the Class; meaning you use:
MyClass().my_instance_method()
Since you seem to want to set response_id on the class instance; using the self argument which denotes the class instance to get the response_id. - I suggest that you use an instance method and instantiate the class as shown above (note the () after the class name)
Kindly do fix your formatting in the question.
There are quite a few things wrong with the code in the example, but putting that aside.
The error is caused by passing an instance of class A as the self argument to a (non-static) method of class B.
Python will attempt to call this method on the instance of class A, resulting in the missing attribute error.
Here is a simplified example of the problem:
class A:
def is_ham(self):
# Python secretly does `self.is_ham()` here,
# because `self` is the current instance of Class A.
# Unless you explicitly pass `self` when calling the method.
return True
class B:
def is_it_ham(self):
# Note, `self` is an instance of class B here.
return A.is_ham(self)
spam = B()
spam.is_it_ham()
I have a class object, cls. I want to know its metaclass. How do I do this?
(If I wanted to know its parent classes, I would do cls.__mro__. Is there something like this to get the metaclass?)
Ok - so, a class's metaclass is just its own "type", and can be given by
type(cls) and other means such as cls.__class__.
In Python 3.x there are no further ambiguities - as the syntax for creating a metaclass just passes it as a named parameter on the class declaration statement anyway.
However, the syntax used for creating a metaclass in Python 2.x generates a side-effect that is worth noting.
Upon doing
class A(object):
__metaclass__ = MyMeta
The __metaclass__ attribute is set to that value in the actual class, even if the actual metaclass is another one.
Consider:
def class_pre_decorator(name, bases, namespace):
# do something with namespace
return type(name, bases, namespace)
This is a callable that can be used in the metaclass declaration of both Python 2 and 3 - and it is valid. After resolving, the actual metaclass in both cases will simply be type. However, in Python 2.x, cls.__metaclass__ will point to the callable class_pre_decorator, even tough type(cls) returns type, which is the correct metaclass.(Note that using callables in this way, they will not be used agian when the class is further subclassed)
There is no way in Python 3 to guess the callable actually used to instantiate a class if it gives no other hint (like setting an attribute on the class) that it was used:
# python 2
class A(object):
__metaclass__ = class_pre_decorator
On the console:
In [8]: type(A)
Out[8]: type
In [9]: A.__metaclass__
Out[9]: <unbound method A.class_pre_decorator>
and
# Python 3
class A(metaclass=class_pre_decorator):
pass
And trying to read A.__metaclass__ will simply raise an AttributeError.
I am trying to understand the class methods. From what I have read it looks like for the class methods we have to pass cls as the first argument while defining (Similar to instance methods where we pass the self as the first argument). But I see that even if I pass the self as the first argument for a class method it works. Can someone explain me how this works?
I have seen some usage where they have defined the class as a class method but they still pass self as the first argument instead of cls. I am trying to understand the usage.
#!/usr/bin/python
class A(object):
def foo(self,x):
print "executing foo(%s,%s)"%(self,x)
#classmethod
def class_foo(self,x):
print "executing class_foo(%s,%s)"%(self,x)
>>> A.class_foo(2)
executing class_foo(<class '__main__.A'>,2)
>>>
The use of self and cls is just a naming convention. You can call them whatever you want (don't though!). As such you're still passing in the class object, you've just named it self, rather than cls.
99.999% of Python programmers will expect you to call them self and cls, also a lot of IDEs will complain if you call them anything but self and cls, so please stick to the convention.
i feel like the last answer only discusses the naming convention of the first parameter without explaining what self evaluates to for what is known as a static method vs a regular method. take the following example:
class A(object):
def x(self):
print(self)
#classmethod
def y(self):
print(self)
a = A()
b = A()
c = A()
print(a.x())
print(b.x())
print(c.x())
print()
print(a.y())
print(b.y())
print(c.y())
the output is the following:
<__main__.A object at 0x7fc95c4549d0>
None
<__main__.A object at 0x7fc95c454a10>
None
<__main__.A object at 0x7fc95c454a50>
None
()
<class '__main__.A'>
None
<class '__main__.A'>
None
<class '__main__.A'>
None
notice that the method x called by the 3 objects yields varying hex addresses, meaning that the self object is tied to the instance. the y method shows that self is actually referencing the class itself rather than the instance. that is the difference.
For some reason most instances of classes are returning Type errors saying that insufficient arguments were passed, the problem is with self.
This works fine:
class ExampleClass:
def __init__(self, some_message):
self.message = some_message
print ("New ExampleClass instance created, with message:")
print (self.message)
ex = ExampleClass("message")
However almost every other Class I define and call an instance of returns the same error. The almost identical function:
class Test(object):
def __init__(self):
self.defaultmsg = "message"
def say(self):
print(self.defaultmsg)
test = Test
test.say()
Returns a Type Error, saying that it needs an argument. I'm getting this problem not just with that class, but with pretty much every class I define, and I have no idea what the problem is. I just updated python, but was getting the error before. I'm fairly new to programming.
You have to instantiate the class:
test = Test() #test is an instance of class Test
instead of
test = Test #test is the class Test
test.say() #TypeError: unbound method say() must be called with Test instance as first argum ent (got nothing instead)
if you are curious you can try this:
test = Test
test.say(Test()) #same as Test.say(Test())
It works because I gave the class instance (self) to the unbound method !
Absolutely not recommended to code this way.
You should add parentheses to instantiate a class:
test = Test()
Your test refers to the class itself, rather than an instance of that class. To create an actual test instance, or to 'instantiate' it, add the parentheses. For example:
>>> class Foo(object):
... pass
...
>>> Foo
<class '__main__.Foo'>
>>> Foo()
<__main__.Foo object at 0xa2eb50>
The error message was trying to tell you that there was no such self object to pass in (implicitly) as the function argument, because in your case test.say would be an unbound method.