I have written the follow code to demonstrate abstract methods that must be implemented by its subclasses. I read that when a method in a parent class is decorated as abstract, its subclass must implement it otherwise it cannot be instantiated. However, in the following code, the 'Slug' subclass does not implement the abstract method, yet it can still instantiate without errors being thrown. I thought in this case Python will complain?
Have I misunderstood something?
Thanks
import abc
class Animal(object):
__metaclass__ = abc.ABCMeta
def __init__(self, species):
self._species=species
def get_species(self):
return self._species
#abc.abstractmethod
def eat(self):
pass
class Slug(Animal):
def __init(self, species):
super(species)
def run(self):
print("running")
# def eat(self):
# pass
sl = Slug("slug")
print(sl.get_species())
no, you understood perfectly well! it is just that the python 3 syntax for abc.ABCMeta is:
class Animal(metaclass=abc.ABCMeta):
...
instead of __metaclass__ = abc.ABCMeta which was used in python 2. alternatively you can just inherit from ABC: class Animal(abc.ABC):. see doc.
and then:
class Slug(Animal):
def __init(self, species):
super.__init__(species)
...
this will result in
Traceback (most recent call last):
File "/home/.../...py", line 33, in <module>
sl = Slug("slug")
TypeError: Can't instantiate abstract class Slug with abstract methods eat
Related
I have searched around for an answer to this question but couldn't find anything. My apologies if this was already asked before.
Of the 3-4 methods I know for enforcing from a parent class a given method on a child class (editing the __new__ method of a metaclass, hooking into builtins.__build_class__, use of __init_subclass__ or using abc.abstractmethod) I usually end up using the __init_subclass__, basically because of ease of use and, unlike #abc.abstractmethod, the constraint on the child class is checked upon child class definition and not class instantiation. Example:
class Par():
def __init_subclass__(self, *args, **kwargs):
must_have = 'foo'
if must_have not in list(self.__dict__.keys()):
raise AttributeError(f"Must have {must_have}")
def __init__(self):
pass
class Chi(Par):
def __init__(self):
super().__init__()
This example code will obviously throw an error, since Chi does not have a foo method. Nevertheless, I kind of just came across the fact that this constraint from the upstream class can be by-passed by using a simple class decorator:
def add_hello_world(Cls):
class NewCls(object):
def __init__(self, *args, **kwargs):
self.instance = Cls(*args, **kwargs)
def hello_world(self):
print("hello world")
return NewCls
#add_hello_world
class Par:
def __init_subclass__(self, *args, **kwargs):
must_have = "foo"
if must_have not in list(self.__dict__.keys()):
raise AttributeError(f"Must have {must_have}")
def __init__(self):
pass
class Chi(Par):
def __init__(self):
super().__init__()
c = Chi()
c.hello_world()
The above code runs without a problem. Now, disregarding the fact that the class I have decorated is Par (and, of course, if Par is library code I might not even have access to it as a user code developer), I cannot really explain this behavior. It is obvious to me that one could use a decorator to add a method or functionality to an existing class, but I had never seen an unrelated decorator (just prints hello world, doesn't even mess with class creation) disable a method already present in the class.
Is this an intended Python behavior? Or is this some kind of bug? To be honest, in my understanding, this might present some security concerns.
Does this happen only to the __init_subclass__ data model? Or also to others?
Remember, decorator syntax is just function application:
class Par:
def __init_subclass__(...):
...
Par = add_hello_world(Par)
The class originally bound to Par defined __init_subclass__; the new class defined inside add_hello_world does not, and that's the class that the post-decoration name Par refers to, and the class that you are subclassing.
Incidentally, you can still access the original class Par via __init__.
Calling the decorator explicitly:
class Par:
def __init_subclass__(self, *args, **kwargs):
must_have = "foo"
if must_have not in list(self.__dict__.keys()):
raise AttributeError(f"Must have {must_have}")
def __init__(self):
pass
Foo = Par # Keep this for confirmation
Par = add_hello_world(Par)
we can confirm that the closure keeps a reference to the original class:
>>> Par.__init__.__closure__[0].cell_contents
<class '__main__.Par'>
>>> Par.__init__.__closure__[0].cell_contents is Par
False
>>> Par.__init__.__closure__[0].cell_contents is Foo
True
And if you did try to subclass it, you would get the expected error:
>>> class Bar(Par.__init__.__closure__[0].cell_contents):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "tmp.py", line 16, in __init_subclass__
raise AttributeError(f"Must have {must_have}")
AttributeError: Must have foo
Here is my code:
from abc import ABC
from abc import abstractmethod
class Mamifiero(ABC):
"""docstring for Mamifiero"""
def __init__(self):
self.alimentacion = 'carnivoro'
#abstractmethod
def __respirar(self):
print('inhalar... exhalar')
class Perro(Mamifiero):
"""docstring for Perro"""
def __init__(self, ojos=2,):
self.ojos = ojos
I want that perro.respirar() prints 'inhalar... exhalar' but when I want to instantiate a Perro class show me this error. I want to know what is wrong with my script
By definition (read the docs), an abstract call is a class which CANNOT be instantiated until it has any abstract methods not overridden. So as in the Object-Oriented Programming by design.
You have an abstract method Perro.__respirar() not overridden, as inherited from the parent class. Or, override it with a method Perro.__respirar(), and do something there (maybe even call the parent's method; but not in case it is private with double-underscore, of course).
If you want to instantiate Perro, just do not make that method abstract. Make it normal. Because it also has some implementation, which suggests it is a normal base-class'es method, not an abstract method.
You need to override __respirar() abstract method in Perro class as shown below:
from abc import ABC
from abc import abstractmethod
class Mamifiero(ABC):
"""docstring for Mamifiero"""
def __init__(self):
self.alimentacion = 'carnivoro'
#abstractmethod
def __respirar(self):
print('inhalar... exhalar')
class Perro(Mamifiero):
"""docstring for Perro"""
def __init__(self, ojos=2,):
self.ojos = ojos
# You need to override
def __respirar(self):
print('Hello')
I'm having problem using super command
class s:
def __init__(self,a):
self.a=a
def show(self):
print self.a
class t:
def __init__(self,b):
self.b=b
def show2(self):
print self.b
class w(s):
def __init__(self,a,b,c):
super(w,self).__init__()
self.b=b
self.c=c
def show3(self):
super(w,self).show()
print self.b
print self.c
whenever i make an object it gives the following error
x=w(1,2,3)
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
x=w(1,2,3)
File "C:\Users\GURSAHEJ\Desktop\k.py", line 13, in __init__
super(w,self).__init__()
TypeError: must be type, not classobj
The super function will Return a proxy object that delegates method calls to a parent or sibling class of type so when you want to use it you need to pass the parent name to it,and since here your w class inherit from s you might want to pass s to super:
class w(s):
def __init__(self,a,b,c):
super(s,self).__init__()
self.b=b
self.c=c
Also don't forget to pass the object to your parent class to make it a new style class :
class s(object):
def __init__(self,a):
self.a=a
def show(self):
print self.a
Read about new style and classic classes it in python documentation https://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes
Because you are using super on an old-style class
In Python 2.x (>= 2.2), there are two type of classes. Old style classes and new-style classes. In python 3.x, old-style classes are removed and all classes are new-style class.
Python's build-in function super works properly on new-style classes.
Simply, new-style classes extends object while old style classes not.
Old Sytle Class
class s:
def __init__(self,a):
self.a=a
New Style Class
class s(object):
def __init__(self,a):
self.a=a
So, your classes which is not inherited from another class should be inherited from object to be a new style class.
You can either use new-style or use old-skool inheritance __init__
class w(s):
def __init__(self,a,b,c):
s.__init__(self, a)
This is an example of old-style solution, but I do not flag this question as a duplicate because new-style class usage is encouraged and you should avoid using old-style classes.
I'm working on a kind of lib, and I'm getting an error.
Here is my code. Of course #abc.abstractmethod have to be uncommented
Here are my tests
Sorry couldn't just copy and paste it
I went on the basis that the code below works.
test.py:
import abc
import six
#six.add_metaclass(abc.ABCMeta)
class Base(object):
#abc.abstractmethod
def whatever(self,):
raise NotImplementedError
class SubClass(Base):
def __init__(self,):
super(Base, self).__init__()
self.whatever()
def whatever(self,):
print("whatever")
In the python shell:
>>> from test import *
>>> s = SubClass()
whatever
For my roster module, why am I getting this error:
Can't instantiate abstract class Player with abstract methods _Base__json_builder, _Base__xml_builder
Your issue comes because you have defined the abstract methods in your base abstract class with __ (double underscore) prepended. This causes python to do name mangling at the time of definition of the classes.
The names of the function change from __json_builder to _Base__json_builder or __xml_builder to _Base__xml_builder . And this is the name you have to implement/overwrite in your subclass.
To show this behavior in your example -
>>> import abc
>>> import six
>>> #six.add_metaclass(abc.ABCMeta)
... class Base(object):
... #abc.abstractmethod
... def __whatever(self):
... raise NotImplementedError
...
>>> class SubClass(Base):
... def __init__(self):
... super(Base, self).__init__()
... self.__whatever()
... def __whatever(self):
... print("whatever")
...
>>> a = SubClass()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class SubClass with abstract methods _Base__whatever
When I change the implementation to the following, it works
>>> class SubClass(Base):
... def __init__(self):
... super(Base, self).__init__()
... self._Base__whatever()
... def _Base__whatever(self):
... print("whatever")
...
>>> a = SubClass()
whatever
But this is very tedious , you may want to think about if you really want to define your functions with __ (double underscore) . You can read more about name mangling here .
I got the same error below:
TypeError: Can't instantiate abstract class Animal with abstract methods sound
When I tried to instantiate Animal abstract class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
print("Wow!!")
obj = Animal() # Here
obj.sound()
And also, I got the same error below:
TypeError: Can't instantiate abstract class Cat with abstract methods sound
When I didn't override sound() abstract method in Cat class, then I instantiated Cat class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
print("Wow!!")
class Cat(Animal):
pass # I didn't override "sound()" abstract method
obj = Cat() # Here
obj.sound()
So, I overrided sound() abstract method in Cat class, then I instantiated Cat class as shown below:
from abc import ABC, abstractmethod
class Animal(ABC):
#abstractmethod
def sound(self):
print("Wow!!")
# I overrided "sound()" abstract method
class Cat(Animal):
def sound(self):
print("Meow!!")
obj = Cat() # Here
obj.sound()
Then, I could solve the error:
Meow!!
Easiest way to make it behave like it did in Python 2 is to use
exec('print("your code")', globals())
This will allow your code to access imports, classes and functions defined in the code will work correctly, etc.
This should only be done w/ code you trust.
I'd like to automatically run some code upon class creation that can call other class methods. I have not found a way of doing so from within the class declaration itself and end up creating a #classmethod called __clsinit__ and call it from the defining scope immediately after the class declaration. Is there a method I can define such that it will get automatically called after the class object is created?
You can do this with a metaclass or a class decorator.
A class decorator (since 2.6) is probably easier to understand:
def call_clsinit(cls):
cls._clsinit()
return cls
#call_clsinit
class MyClass:
#classmethod
def _clsinit(cls):
print "MyClass._clsinit()"
Metaclasses are more powerful; they can call code and modify the ingredients of the class before it is created as well as afterwards (also, they can be inherited):
def call_clsinit(*args, **kwargs):
cls = type(*args, **kwargs)
cls._clsinit()
return cls;
class MyClass(object):
__metaclass__ = call_clsinit
#classmethod
def _clsinit(cls):
print "MyClass._clsinit()"