Abstract attributes in Python












31














What is the shortest / most elegant way to implement the following Scala code with an abstract attribute in Python?



abstract class Controller {

val path: String

}


A subclass of Controller is enforced to define "path" by the Scala compiler. A subclass would look like this:



class MyController extends Controller {

override val path = "/home"

}









share|improve this question


















  • 1




    What have you tried? Please post your Python code with any problems or question you have about your solution.
    – S.Lott
    Apr 29 '10 at 9:54










  • "A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
    – detly
    Apr 29 '10 at 10:38






  • 1




    I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
    – deamon
    Apr 29 '10 at 11:30










  • Related: stackoverflow.com/questions/1151212/…
    – guettli
    Jun 16 '16 at 14:33










  • Possible duplicate of Python Abstract Attribute
    – Pipo
    Nov 7 '17 at 4:40
















31














What is the shortest / most elegant way to implement the following Scala code with an abstract attribute in Python?



abstract class Controller {

val path: String

}


A subclass of Controller is enforced to define "path" by the Scala compiler. A subclass would look like this:



class MyController extends Controller {

override val path = "/home"

}









share|improve this question


















  • 1




    What have you tried? Please post your Python code with any problems or question you have about your solution.
    – S.Lott
    Apr 29 '10 at 9:54










  • "A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
    – detly
    Apr 29 '10 at 10:38






  • 1




    I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
    – deamon
    Apr 29 '10 at 11:30










  • Related: stackoverflow.com/questions/1151212/…
    – guettli
    Jun 16 '16 at 14:33










  • Possible duplicate of Python Abstract Attribute
    – Pipo
    Nov 7 '17 at 4:40














31












31








31


6





What is the shortest / most elegant way to implement the following Scala code with an abstract attribute in Python?



abstract class Controller {

val path: String

}


A subclass of Controller is enforced to define "path" by the Scala compiler. A subclass would look like this:



class MyController extends Controller {

override val path = "/home"

}









share|improve this question













What is the shortest / most elegant way to implement the following Scala code with an abstract attribute in Python?



abstract class Controller {

val path: String

}


A subclass of Controller is enforced to define "path" by the Scala compiler. A subclass would look like this:



class MyController extends Controller {

override val path = "/home"

}






python oop scala abstract-class






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Apr 29 '10 at 9:47









deamon

36.7k85242369




36.7k85242369








  • 1




    What have you tried? Please post your Python code with any problems or question you have about your solution.
    – S.Lott
    Apr 29 '10 at 9:54










  • "A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
    – detly
    Apr 29 '10 at 10:38






  • 1




    I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
    – deamon
    Apr 29 '10 at 11:30










  • Related: stackoverflow.com/questions/1151212/…
    – guettli
    Jun 16 '16 at 14:33










  • Possible duplicate of Python Abstract Attribute
    – Pipo
    Nov 7 '17 at 4:40














  • 1




    What have you tried? Please post your Python code with any problems or question you have about your solution.
    – S.Lott
    Apr 29 '10 at 9:54










  • "A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
    – detly
    Apr 29 '10 at 10:38






  • 1




    I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
    – deamon
    Apr 29 '10 at 11:30










  • Related: stackoverflow.com/questions/1151212/…
    – guettli
    Jun 16 '16 at 14:33










  • Possible duplicate of Python Abstract Attribute
    – Pipo
    Nov 7 '17 at 4:40








1




1




What have you tried? Please post your Python code with any problems or question you have about your solution.
– S.Lott
Apr 29 '10 at 9:54




What have you tried? Please post your Python code with any problems or question you have about your solution.
– S.Lott
Apr 29 '10 at 9:54












"A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
– detly
Apr 29 '10 at 10:38




"A subclass of Controller is enforced to define "path" by the Scala compiler." ... Enforced when? If it's compile time, you're out of luck. If it's runtime, then how exactly do you want it "enforced"? In other words, is there a difference between raising an AttributeError and a NotImplementedError? Why?
– detly
Apr 29 '10 at 10:38




1




1




I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
– deamon
Apr 29 '10 at 11:30




I know that Python is a dynamic language and that the python interpreter cannot enforce static types. It is important to me, that it fails as early as possibly and that it is easy to find the place where the error orrured and why.
– deamon
Apr 29 '10 at 11:30












Related: stackoverflow.com/questions/1151212/…
– guettli
Jun 16 '16 at 14:33




Related: stackoverflow.com/questions/1151212/…
– guettli
Jun 16 '16 at 14:33












Possible duplicate of Python Abstract Attribute
– Pipo
Nov 7 '17 at 4:40




Possible duplicate of Python Abstract Attribute
– Pipo
Nov 7 '17 at 4:40












9 Answers
9






active

oldest

votes


















50














Python has a built-in exception for this, though you won't encounter the exception until runtime.



class Base(object):
@property
def path(self):
raise NotImplementedError


class SubClass(Base):
path = 'blah'





share|improve this answer

















  • 7




    Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
    – Ben James
    Apr 29 '10 at 10:16






  • 4




    I think that raising a NotImplementedError is more explicit and therefore probably better than leaving it to an AttributeError.
    – blokeley
    Apr 29 '10 at 12:48












  • Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
    – Bastien Léonard
    Apr 29 '10 at 14:23










  • See stackoverflow.com/a/1151275/216229 too.
    – Chris Withers
    Apr 14 '14 at 10:26






  • 5




    Not that this only works if path is set directly on the SubClass. Given an instance sc = SubClass(), if you try to set sc.path = 'blah' or have a method that contains something like self.path = 'blah' without defining path directly on SubClass, you will get an AttributeError: can't set attribute.
    – erik
    Mar 31 '15 at 16:59



















44














Python 2.7



There is an @abstractproperty decorator for this:



from abc import ABCMeta, abstractmethod, abstractproperty


class A:
__metaclass__ = ABCMeta

def __init__(self):
# ...
pass

@abstractproperty
def a(self):
pass

@abstractmethod
def b(self):
pass


class B(A):
a = 1

def b(self):
pass


Failure to declare a or b in the derived class B will raise a TypeError such as:




TypeError: Can't instantiate abstract class B with abstract methods a




Python 3.3+



From the documentation:




Deprecated since version 3.3: It is now possible to use property, property.getter(), property.setter() and property.deleter() with abstractmethod(), making this decorator redundant.




The above example essentialy becomes:



from abc import ABCMeta, abstractmethod


class A(metaclass=ABCMeta):
def __init__(self):
# ...
pass

@property
@abstractmethod
def a(self):
pass

@abstractmethod
def b(self):
pass


class B(A):
a = 1

def b(self):
pass





share|improve this answer























  • My "A" class is a subclass of Exception, and this appears to break the example.
    – Chris2048
    Nov 13 '18 at 11:11



















6














You could create an attribute in the abc.ABC abstract base class with a value such as NotImplemented so that if the attribute is not overriden and then used, an error is shown at run time.



The following code uses a PEP 484 type hint to help PyCharm correctly statically analyze the type of the path attribute as well.



import abc


class Controller(abc.ABC):
path = NotImplemented # type: str


class MyController(Controller):
path = '/home'





share|improve this answer





























    5














    Have a look at the abc (Abtract Base Class) module: http://docs.python.org/library/abc.html



    However, in my opinion the simplest and most common solution is to raise an exception when an instance of the base class is created, or when its property is accessed.






    share|improve this answer



















    • 5




      Please elaborate: How does abc module help in this context?
      – guettli
      Jun 16 '16 at 14:32



















    3














    Your base class could implement a __new__ method that check for class attribute:



    class Controller(object):
    def __new__(cls, *args, **kargs):
    if not hasattr(cls,'path'):
    raise NotImplementedError("'Controller' subclasses should have a 'path' attribute")
    return object.__new__(cls,*args,**kargs)

    class C1(Controller):
    path = 42

    class C2(Controller):
    pass


    c1 = C1()
    # ok

    c2 = C2()
    # NotImplementedError: 'Controller' subclasses should have a 'path' attribute


    This way the error raise at instantiation






    share|improve this answer





















    • interestingly, this doesn't work if you need to use def __init__(self).
      – szeitlin
      Oct 6 '15 at 20:30



















    1














    Bastien Léonard's answer mentions the abstract base class module and Brendan Abel's answer deals with non-implemented attributes raising errors. To ensure that the class is not implemented outside of the module, you could prefix the base name with an underscore which denotes it as private to the module (i.e. it is not imported).



    i.e.



    class _Controller(object):
    path = '' # There are better ways to declare attributes - see other answers

    class MyController(_Controller):
    path = '/Home'





    share|improve this answer



















    • 1




      is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
      – Mario F
      Apr 29 '10 at 10:08










    • Wouldn't it be better to leave out the path declaration in _Controller class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need the path field to be defined, there would be no error because there is already a value.
      – deamon
      Apr 29 '10 at 10:25










    • @Mario - yes, Brendan Abel's answer gives a good way to do this
      – Brendan
      Apr 29 '10 at 13:07



















    1














    Python3.6 implementation might looks like this:



    In [20]: class X:
    ...: def __init_subclass__(cls):
    ...: if not hasattr(cls, 'required'):
    ...: raise NotImplementedError

    In [21]: class Y(X):
    ...: required =5
    ...:

    In [22]: Y()
    Out[22]: <__main__.Y at 0x7f08408c9a20>





    share|improve this answer































      0














      class AbstractStuff:
      @property
      @abc.abstractmethod
      def some_property(self):
      pass


      As of 3.3 abc.abstractproperty is deprecated, I think.






      share|improve this answer





























        0














        Since this question was originally asked, python has changed how abstract classes are implemented. I have used a slightly different approach using the abc.ABC formalism in python 3.6. Here I define the constant as a property which must be defined in each subclass.



        from abc import ABC, abstractmethod


        class Base(ABC):

        @property
        @classmethod
        @abstractmethod
        def CONSTANT(cls):
        return NotImplementedError

        def print_constant(self):
        print(type(self).CONSTANT)


        class Derived(Base):
        CONSTANT = 42


        This forces the derived class to define the constant, or else a runtime error will occur when you try to instantiate the subclass. When you want to use the constant for any functionality implemented in the abstract class, you must access the subclass constant by type(self).CONSTANT instead of just CONSTANT, since the value is undefined in the base class.



        There are other ways to implement this, but I like this syntax as it seems to me the most plain and obvious for the reader.



        The previous answers all touched useful points, but I feel the accepted answer does not directly answer the question because




        • The question asks for implementation in an abstract class, but the accepted answer does not follow the abstract formalism.

        • The question asks that implementation is enforced. I would argue that enforcement is stricter in this answer because it causes a runtime error when the subclass is instantiated if CONSTANT is not defined. The accepted answer allows the object to be instantiated and only throws an error when CONSTANT is accessed, making the enforcement less strict.


        This is not to fault the original answers. Major changes to the abstract class syntax have occurred since they were posted, which in this case allow a neater and more functional implementation.






        share|improve this answer





















          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2736255%2fabstract-attributes-in-python%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          9 Answers
          9






          active

          oldest

          votes








          9 Answers
          9






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          50














          Python has a built-in exception for this, though you won't encounter the exception until runtime.



          class Base(object):
          @property
          def path(self):
          raise NotImplementedError


          class SubClass(Base):
          path = 'blah'





          share|improve this answer

















          • 7




            Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
            – Ben James
            Apr 29 '10 at 10:16






          • 4




            I think that raising a NotImplementedError is more explicit and therefore probably better than leaving it to an AttributeError.
            – blokeley
            Apr 29 '10 at 12:48












          • Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
            – Bastien Léonard
            Apr 29 '10 at 14:23










          • See stackoverflow.com/a/1151275/216229 too.
            – Chris Withers
            Apr 14 '14 at 10:26






          • 5




            Not that this only works if path is set directly on the SubClass. Given an instance sc = SubClass(), if you try to set sc.path = 'blah' or have a method that contains something like self.path = 'blah' without defining path directly on SubClass, you will get an AttributeError: can't set attribute.
            – erik
            Mar 31 '15 at 16:59
















          50














          Python has a built-in exception for this, though you won't encounter the exception until runtime.



          class Base(object):
          @property
          def path(self):
          raise NotImplementedError


          class SubClass(Base):
          path = 'blah'





          share|improve this answer

















          • 7




            Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
            – Ben James
            Apr 29 '10 at 10:16






          • 4




            I think that raising a NotImplementedError is more explicit and therefore probably better than leaving it to an AttributeError.
            – blokeley
            Apr 29 '10 at 12:48












          • Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
            – Bastien Léonard
            Apr 29 '10 at 14:23










          • See stackoverflow.com/a/1151275/216229 too.
            – Chris Withers
            Apr 14 '14 at 10:26






          • 5




            Not that this only works if path is set directly on the SubClass. Given an instance sc = SubClass(), if you try to set sc.path = 'blah' or have a method that contains something like self.path = 'blah' without defining path directly on SubClass, you will get an AttributeError: can't set attribute.
            – erik
            Mar 31 '15 at 16:59














          50












          50








          50






          Python has a built-in exception for this, though you won't encounter the exception until runtime.



          class Base(object):
          @property
          def path(self):
          raise NotImplementedError


          class SubClass(Base):
          path = 'blah'





          share|improve this answer












          Python has a built-in exception for this, though you won't encounter the exception until runtime.



          class Base(object):
          @property
          def path(self):
          raise NotImplementedError


          class SubClass(Base):
          path = 'blah'






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Apr 29 '10 at 10:11







          user297250















          • 7




            Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
            – Ben James
            Apr 29 '10 at 10:16






          • 4




            I think that raising a NotImplementedError is more explicit and therefore probably better than leaving it to an AttributeError.
            – blokeley
            Apr 29 '10 at 12:48












          • Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
            – Bastien Léonard
            Apr 29 '10 at 14:23










          • See stackoverflow.com/a/1151275/216229 too.
            – Chris Withers
            Apr 14 '14 at 10:26






          • 5




            Not that this only works if path is set directly on the SubClass. Given an instance sc = SubClass(), if you try to set sc.path = 'blah' or have a method that contains something like self.path = 'blah' without defining path directly on SubClass, you will get an AttributeError: can't set attribute.
            – erik
            Mar 31 '15 at 16:59














          • 7




            Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
            – Ben James
            Apr 29 '10 at 10:16






          • 4




            I think that raising a NotImplementedError is more explicit and therefore probably better than leaving it to an AttributeError.
            – blokeley
            Apr 29 '10 at 12:48












          • Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
            – Bastien Léonard
            Apr 29 '10 at 14:23










          • See stackoverflow.com/a/1151275/216229 too.
            – Chris Withers
            Apr 14 '14 at 10:26






          • 5




            Not that this only works if path is set directly on the SubClass. Given an instance sc = SubClass(), if you try to set sc.path = 'blah' or have a method that contains something like self.path = 'blah' without defining path directly on SubClass, you will get an AttributeError: can't set attribute.
            – erik
            Mar 31 '15 at 16:59








          7




          7




          Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
          – Ben James
          Apr 29 '10 at 10:16




          Specifically, you won't encounter the exception until the attrtibute is accessed, in which case you would have got an AttributeError anyway.
          – Ben James
          Apr 29 '10 at 10:16




          4




          4




          I think that raising a NotImplementedError is more explicit and therefore probably better than leaving it to an AttributeError.
          – blokeley
          Apr 29 '10 at 12:48






          I think that raising a NotImplementedError is more explicit and therefore probably better than leaving it to an AttributeError.
          – blokeley
          Apr 29 '10 at 12:48














          Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
          – Bastien Léonard
          Apr 29 '10 at 14:23




          Also you can add a message such "Can't instantiate abstract class Base" when raising an exception yourself.
          – Bastien Léonard
          Apr 29 '10 at 14:23












          See stackoverflow.com/a/1151275/216229 too.
          – Chris Withers
          Apr 14 '14 at 10:26




          See stackoverflow.com/a/1151275/216229 too.
          – Chris Withers
          Apr 14 '14 at 10:26




          5




          5




          Not that this only works if path is set directly on the SubClass. Given an instance sc = SubClass(), if you try to set sc.path = 'blah' or have a method that contains something like self.path = 'blah' without defining path directly on SubClass, you will get an AttributeError: can't set attribute.
          – erik
          Mar 31 '15 at 16:59




          Not that this only works if path is set directly on the SubClass. Given an instance sc = SubClass(), if you try to set sc.path = 'blah' or have a method that contains something like self.path = 'blah' without defining path directly on SubClass, you will get an AttributeError: can't set attribute.
          – erik
          Mar 31 '15 at 16:59













          44














          Python 2.7



          There is an @abstractproperty decorator for this:



          from abc import ABCMeta, abstractmethod, abstractproperty


          class A:
          __metaclass__ = ABCMeta

          def __init__(self):
          # ...
          pass

          @abstractproperty
          def a(self):
          pass

          @abstractmethod
          def b(self):
          pass


          class B(A):
          a = 1

          def b(self):
          pass


          Failure to declare a or b in the derived class B will raise a TypeError such as:




          TypeError: Can't instantiate abstract class B with abstract methods a




          Python 3.3+



          From the documentation:




          Deprecated since version 3.3: It is now possible to use property, property.getter(), property.setter() and property.deleter() with abstractmethod(), making this decorator redundant.




          The above example essentialy becomes:



          from abc import ABCMeta, abstractmethod


          class A(metaclass=ABCMeta):
          def __init__(self):
          # ...
          pass

          @property
          @abstractmethod
          def a(self):
          pass

          @abstractmethod
          def b(self):
          pass


          class B(A):
          a = 1

          def b(self):
          pass





          share|improve this answer























          • My "A" class is a subclass of Exception, and this appears to break the example.
            – Chris2048
            Nov 13 '18 at 11:11
















          44














          Python 2.7



          There is an @abstractproperty decorator for this:



          from abc import ABCMeta, abstractmethod, abstractproperty


          class A:
          __metaclass__ = ABCMeta

          def __init__(self):
          # ...
          pass

          @abstractproperty
          def a(self):
          pass

          @abstractmethod
          def b(self):
          pass


          class B(A):
          a = 1

          def b(self):
          pass


          Failure to declare a or b in the derived class B will raise a TypeError such as:




          TypeError: Can't instantiate abstract class B with abstract methods a




          Python 3.3+



          From the documentation:




          Deprecated since version 3.3: It is now possible to use property, property.getter(), property.setter() and property.deleter() with abstractmethod(), making this decorator redundant.




          The above example essentialy becomes:



          from abc import ABCMeta, abstractmethod


          class A(metaclass=ABCMeta):
          def __init__(self):
          # ...
          pass

          @property
          @abstractmethod
          def a(self):
          pass

          @abstractmethod
          def b(self):
          pass


          class B(A):
          a = 1

          def b(self):
          pass





          share|improve this answer























          • My "A" class is a subclass of Exception, and this appears to break the example.
            – Chris2048
            Nov 13 '18 at 11:11














          44












          44








          44






          Python 2.7



          There is an @abstractproperty decorator for this:



          from abc import ABCMeta, abstractmethod, abstractproperty


          class A:
          __metaclass__ = ABCMeta

          def __init__(self):
          # ...
          pass

          @abstractproperty
          def a(self):
          pass

          @abstractmethod
          def b(self):
          pass


          class B(A):
          a = 1

          def b(self):
          pass


          Failure to declare a or b in the derived class B will raise a TypeError such as:




          TypeError: Can't instantiate abstract class B with abstract methods a




          Python 3.3+



          From the documentation:




          Deprecated since version 3.3: It is now possible to use property, property.getter(), property.setter() and property.deleter() with abstractmethod(), making this decorator redundant.




          The above example essentialy becomes:



          from abc import ABCMeta, abstractmethod


          class A(metaclass=ABCMeta):
          def __init__(self):
          # ...
          pass

          @property
          @abstractmethod
          def a(self):
          pass

          @abstractmethod
          def b(self):
          pass


          class B(A):
          a = 1

          def b(self):
          pass





          share|improve this answer














          Python 2.7



          There is an @abstractproperty decorator for this:



          from abc import ABCMeta, abstractmethod, abstractproperty


          class A:
          __metaclass__ = ABCMeta

          def __init__(self):
          # ...
          pass

          @abstractproperty
          def a(self):
          pass

          @abstractmethod
          def b(self):
          pass


          class B(A):
          a = 1

          def b(self):
          pass


          Failure to declare a or b in the derived class B will raise a TypeError such as:




          TypeError: Can't instantiate abstract class B with abstract methods a




          Python 3.3+



          From the documentation:




          Deprecated since version 3.3: It is now possible to use property, property.getter(), property.setter() and property.deleter() with abstractmethod(), making this decorator redundant.




          The above example essentialy becomes:



          from abc import ABCMeta, abstractmethod


          class A(metaclass=ABCMeta):
          def __init__(self):
          # ...
          pass

          @property
          @abstractmethod
          def a(self):
          pass

          @abstractmethod
          def b(self):
          pass


          class B(A):
          a = 1

          def b(self):
          pass






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 27 '17 at 15:59

























          answered Jan 27 '17 at 15:47









          Wtower

          10.3k97058




          10.3k97058












          • My "A" class is a subclass of Exception, and this appears to break the example.
            – Chris2048
            Nov 13 '18 at 11:11


















          • My "A" class is a subclass of Exception, and this appears to break the example.
            – Chris2048
            Nov 13 '18 at 11:11
















          My "A" class is a subclass of Exception, and this appears to break the example.
          – Chris2048
          Nov 13 '18 at 11:11




          My "A" class is a subclass of Exception, and this appears to break the example.
          – Chris2048
          Nov 13 '18 at 11:11











          6














          You could create an attribute in the abc.ABC abstract base class with a value such as NotImplemented so that if the attribute is not overriden and then used, an error is shown at run time.



          The following code uses a PEP 484 type hint to help PyCharm correctly statically analyze the type of the path attribute as well.



          import abc


          class Controller(abc.ABC):
          path = NotImplemented # type: str


          class MyController(Controller):
          path = '/home'





          share|improve this answer


























            6














            You could create an attribute in the abc.ABC abstract base class with a value such as NotImplemented so that if the attribute is not overriden and then used, an error is shown at run time.



            The following code uses a PEP 484 type hint to help PyCharm correctly statically analyze the type of the path attribute as well.



            import abc


            class Controller(abc.ABC):
            path = NotImplemented # type: str


            class MyController(Controller):
            path = '/home'





            share|improve this answer
























              6












              6








              6






              You could create an attribute in the abc.ABC abstract base class with a value such as NotImplemented so that if the attribute is not overriden and then used, an error is shown at run time.



              The following code uses a PEP 484 type hint to help PyCharm correctly statically analyze the type of the path attribute as well.



              import abc


              class Controller(abc.ABC):
              path = NotImplemented # type: str


              class MyController(Controller):
              path = '/home'





              share|improve this answer












              You could create an attribute in the abc.ABC abstract base class with a value such as NotImplemented so that if the attribute is not overriden and then used, an error is shown at run time.



              The following code uses a PEP 484 type hint to help PyCharm correctly statically analyze the type of the path attribute as well.



              import abc


              class Controller(abc.ABC):
              path = NotImplemented # type: str


              class MyController(Controller):
              path = '/home'






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Aug 3 '16 at 1:16









              phoenix

              1,52811625




              1,52811625























                  5














                  Have a look at the abc (Abtract Base Class) module: http://docs.python.org/library/abc.html



                  However, in my opinion the simplest and most common solution is to raise an exception when an instance of the base class is created, or when its property is accessed.






                  share|improve this answer



















                  • 5




                    Please elaborate: How does abc module help in this context?
                    – guettli
                    Jun 16 '16 at 14:32
















                  5














                  Have a look at the abc (Abtract Base Class) module: http://docs.python.org/library/abc.html



                  However, in my opinion the simplest and most common solution is to raise an exception when an instance of the base class is created, or when its property is accessed.






                  share|improve this answer



















                  • 5




                    Please elaborate: How does abc module help in this context?
                    – guettli
                    Jun 16 '16 at 14:32














                  5












                  5








                  5






                  Have a look at the abc (Abtract Base Class) module: http://docs.python.org/library/abc.html



                  However, in my opinion the simplest and most common solution is to raise an exception when an instance of the base class is created, or when its property is accessed.






                  share|improve this answer














                  Have a look at the abc (Abtract Base Class) module: http://docs.python.org/library/abc.html



                  However, in my opinion the simplest and most common solution is to raise an exception when an instance of the base class is created, or when its property is accessed.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Apr 29 '10 at 10:23









                  Brendan

                  11.2k137193




                  11.2k137193










                  answered Apr 29 '10 at 10:10









                  Bastien Léonard

                  44k176889




                  44k176889








                  • 5




                    Please elaborate: How does abc module help in this context?
                    – guettli
                    Jun 16 '16 at 14:32














                  • 5




                    Please elaborate: How does abc module help in this context?
                    – guettli
                    Jun 16 '16 at 14:32








                  5




                  5




                  Please elaborate: How does abc module help in this context?
                  – guettli
                  Jun 16 '16 at 14:32




                  Please elaborate: How does abc module help in this context?
                  – guettli
                  Jun 16 '16 at 14:32











                  3














                  Your base class could implement a __new__ method that check for class attribute:



                  class Controller(object):
                  def __new__(cls, *args, **kargs):
                  if not hasattr(cls,'path'):
                  raise NotImplementedError("'Controller' subclasses should have a 'path' attribute")
                  return object.__new__(cls,*args,**kargs)

                  class C1(Controller):
                  path = 42

                  class C2(Controller):
                  pass


                  c1 = C1()
                  # ok

                  c2 = C2()
                  # NotImplementedError: 'Controller' subclasses should have a 'path' attribute


                  This way the error raise at instantiation






                  share|improve this answer





















                  • interestingly, this doesn't work if you need to use def __init__(self).
                    – szeitlin
                    Oct 6 '15 at 20:30
















                  3














                  Your base class could implement a __new__ method that check for class attribute:



                  class Controller(object):
                  def __new__(cls, *args, **kargs):
                  if not hasattr(cls,'path'):
                  raise NotImplementedError("'Controller' subclasses should have a 'path' attribute")
                  return object.__new__(cls,*args,**kargs)

                  class C1(Controller):
                  path = 42

                  class C2(Controller):
                  pass


                  c1 = C1()
                  # ok

                  c2 = C2()
                  # NotImplementedError: 'Controller' subclasses should have a 'path' attribute


                  This way the error raise at instantiation






                  share|improve this answer





















                  • interestingly, this doesn't work if you need to use def __init__(self).
                    – szeitlin
                    Oct 6 '15 at 20:30














                  3












                  3








                  3






                  Your base class could implement a __new__ method that check for class attribute:



                  class Controller(object):
                  def __new__(cls, *args, **kargs):
                  if not hasattr(cls,'path'):
                  raise NotImplementedError("'Controller' subclasses should have a 'path' attribute")
                  return object.__new__(cls,*args,**kargs)

                  class C1(Controller):
                  path = 42

                  class C2(Controller):
                  pass


                  c1 = C1()
                  # ok

                  c2 = C2()
                  # NotImplementedError: 'Controller' subclasses should have a 'path' attribute


                  This way the error raise at instantiation






                  share|improve this answer












                  Your base class could implement a __new__ method that check for class attribute:



                  class Controller(object):
                  def __new__(cls, *args, **kargs):
                  if not hasattr(cls,'path'):
                  raise NotImplementedError("'Controller' subclasses should have a 'path' attribute")
                  return object.__new__(cls,*args,**kargs)

                  class C1(Controller):
                  path = 42

                  class C2(Controller):
                  pass


                  c1 = C1()
                  # ok

                  c2 = C2()
                  # NotImplementedError: 'Controller' subclasses should have a 'path' attribute


                  This way the error raise at instantiation







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Sep 11 '14 at 11:10









                  Juh_

                  6,31432858




                  6,31432858












                  • interestingly, this doesn't work if you need to use def __init__(self).
                    – szeitlin
                    Oct 6 '15 at 20:30


















                  • interestingly, this doesn't work if you need to use def __init__(self).
                    – szeitlin
                    Oct 6 '15 at 20:30
















                  interestingly, this doesn't work if you need to use def __init__(self).
                  – szeitlin
                  Oct 6 '15 at 20:30




                  interestingly, this doesn't work if you need to use def __init__(self).
                  – szeitlin
                  Oct 6 '15 at 20:30











                  1














                  Bastien Léonard's answer mentions the abstract base class module and Brendan Abel's answer deals with non-implemented attributes raising errors. To ensure that the class is not implemented outside of the module, you could prefix the base name with an underscore which denotes it as private to the module (i.e. it is not imported).



                  i.e.



                  class _Controller(object):
                  path = '' # There are better ways to declare attributes - see other answers

                  class MyController(_Controller):
                  path = '/Home'





                  share|improve this answer



















                  • 1




                    is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
                    – Mario F
                    Apr 29 '10 at 10:08










                  • Wouldn't it be better to leave out the path declaration in _Controller class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need the path field to be defined, there would be no error because there is already a value.
                    – deamon
                    Apr 29 '10 at 10:25










                  • @Mario - yes, Brendan Abel's answer gives a good way to do this
                    – Brendan
                    Apr 29 '10 at 13:07
















                  1














                  Bastien Léonard's answer mentions the abstract base class module and Brendan Abel's answer deals with non-implemented attributes raising errors. To ensure that the class is not implemented outside of the module, you could prefix the base name with an underscore which denotes it as private to the module (i.e. it is not imported).



                  i.e.



                  class _Controller(object):
                  path = '' # There are better ways to declare attributes - see other answers

                  class MyController(_Controller):
                  path = '/Home'





                  share|improve this answer



















                  • 1




                    is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
                    – Mario F
                    Apr 29 '10 at 10:08










                  • Wouldn't it be better to leave out the path declaration in _Controller class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need the path field to be defined, there would be no error because there is already a value.
                    – deamon
                    Apr 29 '10 at 10:25










                  • @Mario - yes, Brendan Abel's answer gives a good way to do this
                    – Brendan
                    Apr 29 '10 at 13:07














                  1












                  1








                  1






                  Bastien Léonard's answer mentions the abstract base class module and Brendan Abel's answer deals with non-implemented attributes raising errors. To ensure that the class is not implemented outside of the module, you could prefix the base name with an underscore which denotes it as private to the module (i.e. it is not imported).



                  i.e.



                  class _Controller(object):
                  path = '' # There are better ways to declare attributes - see other answers

                  class MyController(_Controller):
                  path = '/Home'





                  share|improve this answer














                  Bastien Léonard's answer mentions the abstract base class module and Brendan Abel's answer deals with non-implemented attributes raising errors. To ensure that the class is not implemented outside of the module, you could prefix the base name with an underscore which denotes it as private to the module (i.e. it is not imported).



                  i.e.



                  class _Controller(object):
                  path = '' # There are better ways to declare attributes - see other answers

                  class MyController(_Controller):
                  path = '/Home'






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Apr 29 '10 at 13:13

























                  answered Apr 29 '10 at 10:03









                  Brendan

                  11.2k137193




                  11.2k137193








                  • 1




                    is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
                    – Mario F
                    Apr 29 '10 at 10:08










                  • Wouldn't it be better to leave out the path declaration in _Controller class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need the path field to be defined, there would be no error because there is already a value.
                    – deamon
                    Apr 29 '10 at 10:25










                  • @Mario - yes, Brendan Abel's answer gives a good way to do this
                    – Brendan
                    Apr 29 '10 at 13:07














                  • 1




                    is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
                    – Mario F
                    Apr 29 '10 at 10:08










                  • Wouldn't it be better to leave out the path declaration in _Controller class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need the path field to be defined, there would be no error because there is already a value.
                    – deamon
                    Apr 29 '10 at 10:25










                  • @Mario - yes, Brendan Abel's answer gives a good way to do this
                    – Brendan
                    Apr 29 '10 at 13:07








                  1




                  1




                  is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
                  – Mario F
                  Apr 29 '10 at 10:08




                  is it possible to raise some error if the subclass does not redefine the attribute? It would be easy for methods, but how about attributes?
                  – Mario F
                  Apr 29 '10 at 10:08












                  Wouldn't it be better to leave out the path declaration in _Controller class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need the path field to be defined, there would be no error because there is already a value.
                  – deamon
                  Apr 29 '10 at 10:25




                  Wouldn't it be better to leave out the path declaration in _Controller class? Duck Typing wouldn't take effect if there is already a (invalid) value. Otherwise at some point, where I need the path field to be defined, there would be no error because there is already a value.
                  – deamon
                  Apr 29 '10 at 10:25












                  @Mario - yes, Brendan Abel's answer gives a good way to do this
                  – Brendan
                  Apr 29 '10 at 13:07




                  @Mario - yes, Brendan Abel's answer gives a good way to do this
                  – Brendan
                  Apr 29 '10 at 13:07











                  1














                  Python3.6 implementation might looks like this:



                  In [20]: class X:
                  ...: def __init_subclass__(cls):
                  ...: if not hasattr(cls, 'required'):
                  ...: raise NotImplementedError

                  In [21]: class Y(X):
                  ...: required =5
                  ...:

                  In [22]: Y()
                  Out[22]: <__main__.Y at 0x7f08408c9a20>





                  share|improve this answer




























                    1














                    Python3.6 implementation might looks like this:



                    In [20]: class X:
                    ...: def __init_subclass__(cls):
                    ...: if not hasattr(cls, 'required'):
                    ...: raise NotImplementedError

                    In [21]: class Y(X):
                    ...: required =5
                    ...:

                    In [22]: Y()
                    Out[22]: <__main__.Y at 0x7f08408c9a20>





                    share|improve this answer


























                      1












                      1








                      1






                      Python3.6 implementation might looks like this:



                      In [20]: class X:
                      ...: def __init_subclass__(cls):
                      ...: if not hasattr(cls, 'required'):
                      ...: raise NotImplementedError

                      In [21]: class Y(X):
                      ...: required =5
                      ...:

                      In [22]: Y()
                      Out[22]: <__main__.Y at 0x7f08408c9a20>





                      share|improve this answer














                      Python3.6 implementation might looks like this:



                      In [20]: class X:
                      ...: def __init_subclass__(cls):
                      ...: if not hasattr(cls, 'required'):
                      ...: raise NotImplementedError

                      In [21]: class Y(X):
                      ...: required =5
                      ...:

                      In [22]: Y()
                      Out[22]: <__main__.Y at 0x7f08408c9a20>






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Dec 3 '17 at 4:05

























                      answered Nov 23 '17 at 5:38









                      Artem Zhukov

                      538316




                      538316























                          0














                          class AbstractStuff:
                          @property
                          @abc.abstractmethod
                          def some_property(self):
                          pass


                          As of 3.3 abc.abstractproperty is deprecated, I think.






                          share|improve this answer


























                            0














                            class AbstractStuff:
                            @property
                            @abc.abstractmethod
                            def some_property(self):
                            pass


                            As of 3.3 abc.abstractproperty is deprecated, I think.






                            share|improve this answer
























                              0












                              0








                              0






                              class AbstractStuff:
                              @property
                              @abc.abstractmethod
                              def some_property(self):
                              pass


                              As of 3.3 abc.abstractproperty is deprecated, I think.






                              share|improve this answer












                              class AbstractStuff:
                              @property
                              @abc.abstractmethod
                              def some_property(self):
                              pass


                              As of 3.3 abc.abstractproperty is deprecated, I think.







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Aug 3 '18 at 4:10









                              grisaitis

                              1,09311121




                              1,09311121























                                  0














                                  Since this question was originally asked, python has changed how abstract classes are implemented. I have used a slightly different approach using the abc.ABC formalism in python 3.6. Here I define the constant as a property which must be defined in each subclass.



                                  from abc import ABC, abstractmethod


                                  class Base(ABC):

                                  @property
                                  @classmethod
                                  @abstractmethod
                                  def CONSTANT(cls):
                                  return NotImplementedError

                                  def print_constant(self):
                                  print(type(self).CONSTANT)


                                  class Derived(Base):
                                  CONSTANT = 42


                                  This forces the derived class to define the constant, or else a runtime error will occur when you try to instantiate the subclass. When you want to use the constant for any functionality implemented in the abstract class, you must access the subclass constant by type(self).CONSTANT instead of just CONSTANT, since the value is undefined in the base class.



                                  There are other ways to implement this, but I like this syntax as it seems to me the most plain and obvious for the reader.



                                  The previous answers all touched useful points, but I feel the accepted answer does not directly answer the question because




                                  • The question asks for implementation in an abstract class, but the accepted answer does not follow the abstract formalism.

                                  • The question asks that implementation is enforced. I would argue that enforcement is stricter in this answer because it causes a runtime error when the subclass is instantiated if CONSTANT is not defined. The accepted answer allows the object to be instantiated and only throws an error when CONSTANT is accessed, making the enforcement less strict.


                                  This is not to fault the original answers. Major changes to the abstract class syntax have occurred since they were posted, which in this case allow a neater and more functional implementation.






                                  share|improve this answer


























                                    0














                                    Since this question was originally asked, python has changed how abstract classes are implemented. I have used a slightly different approach using the abc.ABC formalism in python 3.6. Here I define the constant as a property which must be defined in each subclass.



                                    from abc import ABC, abstractmethod


                                    class Base(ABC):

                                    @property
                                    @classmethod
                                    @abstractmethod
                                    def CONSTANT(cls):
                                    return NotImplementedError

                                    def print_constant(self):
                                    print(type(self).CONSTANT)


                                    class Derived(Base):
                                    CONSTANT = 42


                                    This forces the derived class to define the constant, or else a runtime error will occur when you try to instantiate the subclass. When you want to use the constant for any functionality implemented in the abstract class, you must access the subclass constant by type(self).CONSTANT instead of just CONSTANT, since the value is undefined in the base class.



                                    There are other ways to implement this, but I like this syntax as it seems to me the most plain and obvious for the reader.



                                    The previous answers all touched useful points, but I feel the accepted answer does not directly answer the question because




                                    • The question asks for implementation in an abstract class, but the accepted answer does not follow the abstract formalism.

                                    • The question asks that implementation is enforced. I would argue that enforcement is stricter in this answer because it causes a runtime error when the subclass is instantiated if CONSTANT is not defined. The accepted answer allows the object to be instantiated and only throws an error when CONSTANT is accessed, making the enforcement less strict.


                                    This is not to fault the original answers. Major changes to the abstract class syntax have occurred since they were posted, which in this case allow a neater and more functional implementation.






                                    share|improve this answer
























                                      0












                                      0








                                      0






                                      Since this question was originally asked, python has changed how abstract classes are implemented. I have used a slightly different approach using the abc.ABC formalism in python 3.6. Here I define the constant as a property which must be defined in each subclass.



                                      from abc import ABC, abstractmethod


                                      class Base(ABC):

                                      @property
                                      @classmethod
                                      @abstractmethod
                                      def CONSTANT(cls):
                                      return NotImplementedError

                                      def print_constant(self):
                                      print(type(self).CONSTANT)


                                      class Derived(Base):
                                      CONSTANT = 42


                                      This forces the derived class to define the constant, or else a runtime error will occur when you try to instantiate the subclass. When you want to use the constant for any functionality implemented in the abstract class, you must access the subclass constant by type(self).CONSTANT instead of just CONSTANT, since the value is undefined in the base class.



                                      There are other ways to implement this, but I like this syntax as it seems to me the most plain and obvious for the reader.



                                      The previous answers all touched useful points, but I feel the accepted answer does not directly answer the question because




                                      • The question asks for implementation in an abstract class, but the accepted answer does not follow the abstract formalism.

                                      • The question asks that implementation is enforced. I would argue that enforcement is stricter in this answer because it causes a runtime error when the subclass is instantiated if CONSTANT is not defined. The accepted answer allows the object to be instantiated and only throws an error when CONSTANT is accessed, making the enforcement less strict.


                                      This is not to fault the original answers. Major changes to the abstract class syntax have occurred since they were posted, which in this case allow a neater and more functional implementation.






                                      share|improve this answer












                                      Since this question was originally asked, python has changed how abstract classes are implemented. I have used a slightly different approach using the abc.ABC formalism in python 3.6. Here I define the constant as a property which must be defined in each subclass.



                                      from abc import ABC, abstractmethod


                                      class Base(ABC):

                                      @property
                                      @classmethod
                                      @abstractmethod
                                      def CONSTANT(cls):
                                      return NotImplementedError

                                      def print_constant(self):
                                      print(type(self).CONSTANT)


                                      class Derived(Base):
                                      CONSTANT = 42


                                      This forces the derived class to define the constant, or else a runtime error will occur when you try to instantiate the subclass. When you want to use the constant for any functionality implemented in the abstract class, you must access the subclass constant by type(self).CONSTANT instead of just CONSTANT, since the value is undefined in the base class.



                                      There are other ways to implement this, but I like this syntax as it seems to me the most plain and obvious for the reader.



                                      The previous answers all touched useful points, but I feel the accepted answer does not directly answer the question because




                                      • The question asks for implementation in an abstract class, but the accepted answer does not follow the abstract formalism.

                                      • The question asks that implementation is enforced. I would argue that enforcement is stricter in this answer because it causes a runtime error when the subclass is instantiated if CONSTANT is not defined. The accepted answer allows the object to be instantiated and only throws an error when CONSTANT is accessed, making the enforcement less strict.


                                      This is not to fault the original answers. Major changes to the abstract class syntax have occurred since they were posted, which in this case allow a neater and more functional implementation.







                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Nov 21 '18 at 17:26









                                      James

                                      11




                                      11






























                                          draft saved

                                          draft discarded




















































                                          Thanks for contributing an answer to Stack Overflow!


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid



                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.


                                          To learn more, see our tips on writing great answers.





                                          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                          Please pay close attention to the following guidance:


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid



                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.


                                          To learn more, see our tips on writing great answers.




                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function () {
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f2736255%2fabstract-attributes-in-python%23new-answer', 'question_page');
                                          }
                                          );

                                          Post as a guest















                                          Required, but never shown





















































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown

































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown







                                          Popular posts from this blog

                                          404 Error Contact Form 7 ajax form submitting

                                          How to know if a Active Directory user can login interactively

                                          TypeError: fit_transform() missing 1 required positional argument: 'X'