Extending a class by parameter in Python

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
15
down vote

favorite
2












I want to expand the class Foo by the class Bar, the issue that I have is that I can't expand it in the usual way (class Foo(Bar)) because the class Bar is somewhat dynamically generated.



I made this small example to illustrate my desired outcome:



class Bar:
def super_cool_function():
print("Cool")

class Foo:
def __init__(self, another_class):
# I want to extend Foo by another_class

# Desired result
foobar = Foo(Bar)
foobar.super_cool_function()


Again this is not what I'm looking for:



class Foo(Bar):
pass

foobar = Foo()
foobar.super_cool_function()






share|improve this question


















  • 2




    At what point is Bar known? class Foo(X): works just fine even if X is a variable, not the literal name of the parent class.
    – jasonharper
    Aug 12 at 21:12










  • I should point out that, in order for super_cool_function to be callable by an instance of Foo, it'd need the self parameter (def super_cool_function(self):). I'm not going to edit your question to correct it, because that would invalidate abarnert's answer.
    – coldspeed
    Aug 13 at 3:16











  • You can also consider the strategy pattern: sourcemaking.com/design_patterns/strategy/python/1
    – Tjorriemorrie
    Aug 30 at 23:50














up vote
15
down vote

favorite
2












I want to expand the class Foo by the class Bar, the issue that I have is that I can't expand it in the usual way (class Foo(Bar)) because the class Bar is somewhat dynamically generated.



I made this small example to illustrate my desired outcome:



class Bar:
def super_cool_function():
print("Cool")

class Foo:
def __init__(self, another_class):
# I want to extend Foo by another_class

# Desired result
foobar = Foo(Bar)
foobar.super_cool_function()


Again this is not what I'm looking for:



class Foo(Bar):
pass

foobar = Foo()
foobar.super_cool_function()






share|improve this question


















  • 2




    At what point is Bar known? class Foo(X): works just fine even if X is a variable, not the literal name of the parent class.
    – jasonharper
    Aug 12 at 21:12










  • I should point out that, in order for super_cool_function to be callable by an instance of Foo, it'd need the self parameter (def super_cool_function(self):). I'm not going to edit your question to correct it, because that would invalidate abarnert's answer.
    – coldspeed
    Aug 13 at 3:16











  • You can also consider the strategy pattern: sourcemaking.com/design_patterns/strategy/python/1
    – Tjorriemorrie
    Aug 30 at 23:50












up vote
15
down vote

favorite
2









up vote
15
down vote

favorite
2






2





I want to expand the class Foo by the class Bar, the issue that I have is that I can't expand it in the usual way (class Foo(Bar)) because the class Bar is somewhat dynamically generated.



I made this small example to illustrate my desired outcome:



class Bar:
def super_cool_function():
print("Cool")

class Foo:
def __init__(self, another_class):
# I want to extend Foo by another_class

# Desired result
foobar = Foo(Bar)
foobar.super_cool_function()


Again this is not what I'm looking for:



class Foo(Bar):
pass

foobar = Foo()
foobar.super_cool_function()






share|improve this question














I want to expand the class Foo by the class Bar, the issue that I have is that I can't expand it in the usual way (class Foo(Bar)) because the class Bar is somewhat dynamically generated.



I made this small example to illustrate my desired outcome:



class Bar:
def super_cool_function():
print("Cool")

class Foo:
def __init__(self, another_class):
# I want to extend Foo by another_class

# Desired result
foobar = Foo(Bar)
foobar.super_cool_function()


Again this is not what I'm looking for:



class Foo(Bar):
pass

foobar = Foo()
foobar.super_cool_function()








share|improve this question













share|improve this question




share|improve this question








edited Aug 13 at 3:15









coldspeed

102k1787153




102k1787153










asked Aug 12 at 21:09









Ivy F.

804




804







  • 2




    At what point is Bar known? class Foo(X): works just fine even if X is a variable, not the literal name of the parent class.
    – jasonharper
    Aug 12 at 21:12










  • I should point out that, in order for super_cool_function to be callable by an instance of Foo, it'd need the self parameter (def super_cool_function(self):). I'm not going to edit your question to correct it, because that would invalidate abarnert's answer.
    – coldspeed
    Aug 13 at 3:16











  • You can also consider the strategy pattern: sourcemaking.com/design_patterns/strategy/python/1
    – Tjorriemorrie
    Aug 30 at 23:50












  • 2




    At what point is Bar known? class Foo(X): works just fine even if X is a variable, not the literal name of the parent class.
    – jasonharper
    Aug 12 at 21:12










  • I should point out that, in order for super_cool_function to be callable by an instance of Foo, it'd need the self parameter (def super_cool_function(self):). I'm not going to edit your question to correct it, because that would invalidate abarnert's answer.
    – coldspeed
    Aug 13 at 3:16











  • You can also consider the strategy pattern: sourcemaking.com/design_patterns/strategy/python/1
    – Tjorriemorrie
    Aug 30 at 23:50







2




2




At what point is Bar known? class Foo(X): works just fine even if X is a variable, not the literal name of the parent class.
– jasonharper
Aug 12 at 21:12




At what point is Bar known? class Foo(X): works just fine even if X is a variable, not the literal name of the parent class.
– jasonharper
Aug 12 at 21:12












I should point out that, in order for super_cool_function to be callable by an instance of Foo, it'd need the self parameter (def super_cool_function(self):). I'm not going to edit your question to correct it, because that would invalidate abarnert's answer.
– coldspeed
Aug 13 at 3:16





I should point out that, in order for super_cool_function to be callable by an instance of Foo, it'd need the self parameter (def super_cool_function(self):). I'm not going to edit your question to correct it, because that would invalidate abarnert's answer.
– coldspeed
Aug 13 at 3:16













You can also consider the strategy pattern: sourcemaking.com/design_patterns/strategy/python/1
– Tjorriemorrie
Aug 30 at 23:50




You can also consider the strategy pattern: sourcemaking.com/design_patterns/strategy/python/1
– Tjorriemorrie
Aug 30 at 23:50












2 Answers
2






active

oldest

votes

















up vote
22
down vote



accepted










"The class Bar is somewhat dynamically generated" That's fine... as long as it follows the blueprint (of a class that should be extended by Foo), you can leverage python closures here. Dynamically create a new class by creating it inside, and returning it from a function.



def get_class(superclass):
class Foo(superclass):
def __init__(self, ...):
...

return Foo

DynamicFoo = get_class(Bar)
myobj = DynamicFoo()


This is a common pattern you'll see in python - leveraging closures to dynamically create callbacks and classes.




The answer above assumes that Bar is correctly defined, when it in fact is not. The super_cool_function is missing a self parameter. Instance methods are always called with the first parameter (the instance itself) automatically being passed in as the first attribute.



So, the correct definition for Bar would be:



class Bar:
def super_cool_function(self):
print("Cool")


Now, defining get_class with the simplest definition of the inner class Foo:



def get_class(superclass):
class Foo(superclass):
pass

return Foo

DynamicFoo = get_class(Bar)
myobj = DynamicFoo()
myobj.super_cool_function()
# Cool





share|improve this answer





























    up vote
    4
    down vote













    Your desired use is a little strange:



    foobar = Foo(Bar)


    You're constructing a Foo instance by handing it the Bar class object, and expecting to get back something that acts like a Bar instance. Normally, a proxy class is designed to take an object to proxy to, or look on up somewhere, not just construct one with no arguments.



    But, other than that oddness, which just means an __init__ method that constructs the object, this is just a bog-standard proxy class. So:



    class Foo:
    def __init__(self, cls):
    self._inst = cls()
    def __getattr__(self, name):
    return getattr(self._inst, name)
    def __setattr__(self, name, value):
    if name in '_inst':
    super().__setattr__(name, value)
    else:
    setattr(self._inst, name, value)
    def __delattr__(self, name):
    delattr(self._inst, name)



    Of course you still won't be able to call that super_cool_function on a foobar any more than you could on a Bar instance, because it's defined as a method and doesn't have a self parameter. But you'll get the same error from the Foo instance that you would have gotten from a Bar instance:



    >>> foobar.super_cool_function
    <bound method Bar.super_cool_function of <__main__.Bar object at 0x129f95080>>
    >>> foobar.super_cool_function()
    TypeError: super_cool_function() takes 0 positional arguments but 1 was





    share|improve this answer


















    • 1




      Any reason why you used object.__setattr__ instead of super().__setattr__?
      – Aran-Fey
      Aug 12 at 21:23










    • @Aran-Fey Probably just habit left over from Guido's original Python 2.2 examples or something, and I can't see any good reason not to use super, so… edited.
      – abarnert
      Aug 12 at 21:25











    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',
    convertImagesToLinks: true,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    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%2f51812872%2fextending-a-class-by-parameter-in-python%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    22
    down vote



    accepted










    "The class Bar is somewhat dynamically generated" That's fine... as long as it follows the blueprint (of a class that should be extended by Foo), you can leverage python closures here. Dynamically create a new class by creating it inside, and returning it from a function.



    def get_class(superclass):
    class Foo(superclass):
    def __init__(self, ...):
    ...

    return Foo

    DynamicFoo = get_class(Bar)
    myobj = DynamicFoo()


    This is a common pattern you'll see in python - leveraging closures to dynamically create callbacks and classes.




    The answer above assumes that Bar is correctly defined, when it in fact is not. The super_cool_function is missing a self parameter. Instance methods are always called with the first parameter (the instance itself) automatically being passed in as the first attribute.



    So, the correct definition for Bar would be:



    class Bar:
    def super_cool_function(self):
    print("Cool")


    Now, defining get_class with the simplest definition of the inner class Foo:



    def get_class(superclass):
    class Foo(superclass):
    pass

    return Foo

    DynamicFoo = get_class(Bar)
    myobj = DynamicFoo()
    myobj.super_cool_function()
    # Cool





    share|improve this answer


























      up vote
      22
      down vote



      accepted










      "The class Bar is somewhat dynamically generated" That's fine... as long as it follows the blueprint (of a class that should be extended by Foo), you can leverage python closures here. Dynamically create a new class by creating it inside, and returning it from a function.



      def get_class(superclass):
      class Foo(superclass):
      def __init__(self, ...):
      ...

      return Foo

      DynamicFoo = get_class(Bar)
      myobj = DynamicFoo()


      This is a common pattern you'll see in python - leveraging closures to dynamically create callbacks and classes.




      The answer above assumes that Bar is correctly defined, when it in fact is not. The super_cool_function is missing a self parameter. Instance methods are always called with the first parameter (the instance itself) automatically being passed in as the first attribute.



      So, the correct definition for Bar would be:



      class Bar:
      def super_cool_function(self):
      print("Cool")


      Now, defining get_class with the simplest definition of the inner class Foo:



      def get_class(superclass):
      class Foo(superclass):
      pass

      return Foo

      DynamicFoo = get_class(Bar)
      myobj = DynamicFoo()
      myobj.super_cool_function()
      # Cool





      share|improve this answer
























        up vote
        22
        down vote



        accepted







        up vote
        22
        down vote



        accepted






        "The class Bar is somewhat dynamically generated" That's fine... as long as it follows the blueprint (of a class that should be extended by Foo), you can leverage python closures here. Dynamically create a new class by creating it inside, and returning it from a function.



        def get_class(superclass):
        class Foo(superclass):
        def __init__(self, ...):
        ...

        return Foo

        DynamicFoo = get_class(Bar)
        myobj = DynamicFoo()


        This is a common pattern you'll see in python - leveraging closures to dynamically create callbacks and classes.




        The answer above assumes that Bar is correctly defined, when it in fact is not. The super_cool_function is missing a self parameter. Instance methods are always called with the first parameter (the instance itself) automatically being passed in as the first attribute.



        So, the correct definition for Bar would be:



        class Bar:
        def super_cool_function(self):
        print("Cool")


        Now, defining get_class with the simplest definition of the inner class Foo:



        def get_class(superclass):
        class Foo(superclass):
        pass

        return Foo

        DynamicFoo = get_class(Bar)
        myobj = DynamicFoo()
        myobj.super_cool_function()
        # Cool





        share|improve this answer














        "The class Bar is somewhat dynamically generated" That's fine... as long as it follows the blueprint (of a class that should be extended by Foo), you can leverage python closures here. Dynamically create a new class by creating it inside, and returning it from a function.



        def get_class(superclass):
        class Foo(superclass):
        def __init__(self, ...):
        ...

        return Foo

        DynamicFoo = get_class(Bar)
        myobj = DynamicFoo()


        This is a common pattern you'll see in python - leveraging closures to dynamically create callbacks and classes.




        The answer above assumes that Bar is correctly defined, when it in fact is not. The super_cool_function is missing a self parameter. Instance methods are always called with the first parameter (the instance itself) automatically being passed in as the first attribute.



        So, the correct definition for Bar would be:



        class Bar:
        def super_cool_function(self):
        print("Cool")


        Now, defining get_class with the simplest definition of the inner class Foo:



        def get_class(superclass):
        class Foo(superclass):
        pass

        return Foo

        DynamicFoo = get_class(Bar)
        myobj = DynamicFoo()
        myobj.super_cool_function()
        # Cool






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Aug 13 at 3:21

























        answered Aug 12 at 21:14









        coldspeed

        102k1787153




        102k1787153






















            up vote
            4
            down vote













            Your desired use is a little strange:



            foobar = Foo(Bar)


            You're constructing a Foo instance by handing it the Bar class object, and expecting to get back something that acts like a Bar instance. Normally, a proxy class is designed to take an object to proxy to, or look on up somewhere, not just construct one with no arguments.



            But, other than that oddness, which just means an __init__ method that constructs the object, this is just a bog-standard proxy class. So:



            class Foo:
            def __init__(self, cls):
            self._inst = cls()
            def __getattr__(self, name):
            return getattr(self._inst, name)
            def __setattr__(self, name, value):
            if name in '_inst':
            super().__setattr__(name, value)
            else:
            setattr(self._inst, name, value)
            def __delattr__(self, name):
            delattr(self._inst, name)



            Of course you still won't be able to call that super_cool_function on a foobar any more than you could on a Bar instance, because it's defined as a method and doesn't have a self parameter. But you'll get the same error from the Foo instance that you would have gotten from a Bar instance:



            >>> foobar.super_cool_function
            <bound method Bar.super_cool_function of <__main__.Bar object at 0x129f95080>>
            >>> foobar.super_cool_function()
            TypeError: super_cool_function() takes 0 positional arguments but 1 was





            share|improve this answer


















            • 1




              Any reason why you used object.__setattr__ instead of super().__setattr__?
              – Aran-Fey
              Aug 12 at 21:23










            • @Aran-Fey Probably just habit left over from Guido's original Python 2.2 examples or something, and I can't see any good reason not to use super, so… edited.
              – abarnert
              Aug 12 at 21:25















            up vote
            4
            down vote













            Your desired use is a little strange:



            foobar = Foo(Bar)


            You're constructing a Foo instance by handing it the Bar class object, and expecting to get back something that acts like a Bar instance. Normally, a proxy class is designed to take an object to proxy to, or look on up somewhere, not just construct one with no arguments.



            But, other than that oddness, which just means an __init__ method that constructs the object, this is just a bog-standard proxy class. So:



            class Foo:
            def __init__(self, cls):
            self._inst = cls()
            def __getattr__(self, name):
            return getattr(self._inst, name)
            def __setattr__(self, name, value):
            if name in '_inst':
            super().__setattr__(name, value)
            else:
            setattr(self._inst, name, value)
            def __delattr__(self, name):
            delattr(self._inst, name)



            Of course you still won't be able to call that super_cool_function on a foobar any more than you could on a Bar instance, because it's defined as a method and doesn't have a self parameter. But you'll get the same error from the Foo instance that you would have gotten from a Bar instance:



            >>> foobar.super_cool_function
            <bound method Bar.super_cool_function of <__main__.Bar object at 0x129f95080>>
            >>> foobar.super_cool_function()
            TypeError: super_cool_function() takes 0 positional arguments but 1 was





            share|improve this answer


















            • 1




              Any reason why you used object.__setattr__ instead of super().__setattr__?
              – Aran-Fey
              Aug 12 at 21:23










            • @Aran-Fey Probably just habit left over from Guido's original Python 2.2 examples or something, and I can't see any good reason not to use super, so… edited.
              – abarnert
              Aug 12 at 21:25













            up vote
            4
            down vote










            up vote
            4
            down vote









            Your desired use is a little strange:



            foobar = Foo(Bar)


            You're constructing a Foo instance by handing it the Bar class object, and expecting to get back something that acts like a Bar instance. Normally, a proxy class is designed to take an object to proxy to, or look on up somewhere, not just construct one with no arguments.



            But, other than that oddness, which just means an __init__ method that constructs the object, this is just a bog-standard proxy class. So:



            class Foo:
            def __init__(self, cls):
            self._inst = cls()
            def __getattr__(self, name):
            return getattr(self._inst, name)
            def __setattr__(self, name, value):
            if name in '_inst':
            super().__setattr__(name, value)
            else:
            setattr(self._inst, name, value)
            def __delattr__(self, name):
            delattr(self._inst, name)



            Of course you still won't be able to call that super_cool_function on a foobar any more than you could on a Bar instance, because it's defined as a method and doesn't have a self parameter. But you'll get the same error from the Foo instance that you would have gotten from a Bar instance:



            >>> foobar.super_cool_function
            <bound method Bar.super_cool_function of <__main__.Bar object at 0x129f95080>>
            >>> foobar.super_cool_function()
            TypeError: super_cool_function() takes 0 positional arguments but 1 was





            share|improve this answer














            Your desired use is a little strange:



            foobar = Foo(Bar)


            You're constructing a Foo instance by handing it the Bar class object, and expecting to get back something that acts like a Bar instance. Normally, a proxy class is designed to take an object to proxy to, or look on up somewhere, not just construct one with no arguments.



            But, other than that oddness, which just means an __init__ method that constructs the object, this is just a bog-standard proxy class. So:



            class Foo:
            def __init__(self, cls):
            self._inst = cls()
            def __getattr__(self, name):
            return getattr(self._inst, name)
            def __setattr__(self, name, value):
            if name in '_inst':
            super().__setattr__(name, value)
            else:
            setattr(self._inst, name, value)
            def __delattr__(self, name):
            delattr(self._inst, name)



            Of course you still won't be able to call that super_cool_function on a foobar any more than you could on a Bar instance, because it's defined as a method and doesn't have a self parameter. But you'll get the same error from the Foo instance that you would have gotten from a Bar instance:



            >>> foobar.super_cool_function
            <bound method Bar.super_cool_function of <__main__.Bar object at 0x129f95080>>
            >>> foobar.super_cool_function()
            TypeError: super_cool_function() takes 0 positional arguments but 1 was






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Aug 12 at 21:29

























            answered Aug 12 at 21:21









            abarnert

            241k21327430




            241k21327430







            • 1




              Any reason why you used object.__setattr__ instead of super().__setattr__?
              – Aran-Fey
              Aug 12 at 21:23










            • @Aran-Fey Probably just habit left over from Guido's original Python 2.2 examples or something, and I can't see any good reason not to use super, so… edited.
              – abarnert
              Aug 12 at 21:25













            • 1




              Any reason why you used object.__setattr__ instead of super().__setattr__?
              – Aran-Fey
              Aug 12 at 21:23










            • @Aran-Fey Probably just habit left over from Guido's original Python 2.2 examples or something, and I can't see any good reason not to use super, so… edited.
              – abarnert
              Aug 12 at 21:25








            1




            1




            Any reason why you used object.__setattr__ instead of super().__setattr__?
            – Aran-Fey
            Aug 12 at 21:23




            Any reason why you used object.__setattr__ instead of super().__setattr__?
            – Aran-Fey
            Aug 12 at 21:23












            @Aran-Fey Probably just habit left over from Guido's original Python 2.2 examples or something, and I can't see any good reason not to use super, so… edited.
            – abarnert
            Aug 12 at 21:25





            @Aran-Fey Probably just habit left over from Guido's original Python 2.2 examples or something, and I can't see any good reason not to use super, so… edited.
            – abarnert
            Aug 12 at 21:25


















             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51812872%2fextending-a-class-by-parameter-in-python%23new-answer', 'question_page');

            );

            Post as a guest













































































            Comments

            Popular posts from this blog

            What does second last employer means? [closed]

            List of Gilmore Girls characters

            One-line joke