Wrapping homogeneous Python objects2019 Community Moderator ElectionPython Object WrapperCalling an external command in PythonWhat are metaclasses in Python?Is there a way to run Python on Android?Finding the index of an item given a list containing it in PythonDifference between append vs. extend list methods in PythonHow can I safely create a nested directory in Python?Does Python have a ternary conditional operator?How to get the current time in PythonHow can I make a time delay in Python?Does Python have a string 'contains' substring method?

Turning a hard to access nut?

Can you move over difficult terrain with only 5 feet of movement?

What is the relationship between relativity and the Doppler effect?

Usage and meaning of "up" in "...worth at least a thousand pounds up in London"

How can an organ that provides biological immortality be unable to regenerate?

Why is there so much iron?

What are substitutions for coconut in curry?

Optimising a list searching algorithm

Print last inputted byte

Variable completely messes up echoed string

Dual Irish/Britsh citizens

gerund and noun applications

What favor did Moody owe Dumbledore?

Wrapping homogeneous Python objects

How are passwords stolen from companies if they only store hashes?

Could Sinn Fein swing any Brexit vote in Parliament?

Calculate the frequency of characters in a string

I got the following comment from a reputed math journal. What does it mean?

Geography in 3D perspective

In what cases must I use 了 and in what cases not?

What should I install to correct "ld: cannot find -lgbm and -linput" so that I can compile a Rust program?

Hausdorff dimension of the boundary of fibres of Lipschitz maps

How does one measure the Fourier components of a signal?

Comment Box for Substitution Method of Integrals



Wrapping homogeneous Python objects



2019 Community Moderator ElectionPython Object WrapperCalling an external command in PythonWhat are metaclasses in Python?Is there a way to run Python on Android?Finding the index of an item given a list containing it in PythonDifference between append vs. extend list methods in PythonHow can I safely create a nested directory in Python?Does Python have a ternary conditional operator?How to get the current time in PythonHow can I make a time delay in Python?Does Python have a string 'contains' substring method?










7















I'm looking for a way to have a collection of homogeneous objects, wrap them in another object, but have the wrapper object have the same API as the original and forward the corresponding API call to its object members.



class OriginalApi:
def __init__(self):
self.a = 1
self.b = "bee"

def do_something(self, new_a, new_b, put_them_together=None):
self.a = new_a or self.a
self.b = new_b or self.b

if put_them_together is not None:
self.b = "".format(self.a, self.b)

# etc.

class WrappedApi:
def __init__(self):
self.example_1 = OriginalApi()
self.example_2 = OriginalApi()


Some possible solutions that have been considered, but are inadequate:




  • Rewriting the whole API Why not? Not adequate because the API is fairly large and expanding. Having to maintain the API in multiple spots is not realistic.



    Code example:



    class WrappedApi:
    def __init__(self):
    self.example_1 = OriginalApi()
    self.example_2 = OriginalApi()

    def do_something(self, new_a, new_b, put_them_together=None):
    self.example_1.do_something(new_a, new_b, put_them_together)
    self.example_2.do_something(new_a, new_b, put_them_together)



  • Using a list and a for-loop This changes the API on the object. That said, this is the backup solution in the event I can't find something more elegant. In this case, the WrappedApi class would not exist.



    Code example:



    wrapped_apis = [OriginalApi(), OriginalApi()]
    for wrapped_api in wrapped_apis:
    wrapped_api.do_something(1, 2, True)


  • I tried using
    Python Object Wrapper, but I could not see how to have it call multiple sub-objects with the same arguments.


And for anyone curious about the use case, it's actually a collection of several matplotlib axes objects. I don't want to reimplement to entire axes API (it's big), and I don't want to change all the code that makes calls on axes (like plot, step, etc.)










share|improve this question



















  • 2





    How do you want to handle the sequence protocol? Should indexing into the wrapper give you one of the wrapped items, or the result of indexing into all of the wrapped items? This is going to be complex in the generic case.

    – jonrsharpe
    4 hours ago












  • is this referring to def __getitem__(self, i):? If so, I hadn't thought about that, but I think either method would be valid for my situation

    – TinyTheBrontosaurus
    4 hours ago















7















I'm looking for a way to have a collection of homogeneous objects, wrap them in another object, but have the wrapper object have the same API as the original and forward the corresponding API call to its object members.



class OriginalApi:
def __init__(self):
self.a = 1
self.b = "bee"

def do_something(self, new_a, new_b, put_them_together=None):
self.a = new_a or self.a
self.b = new_b or self.b

if put_them_together is not None:
self.b = "".format(self.a, self.b)

# etc.

class WrappedApi:
def __init__(self):
self.example_1 = OriginalApi()
self.example_2 = OriginalApi()


Some possible solutions that have been considered, but are inadequate:




  • Rewriting the whole API Why not? Not adequate because the API is fairly large and expanding. Having to maintain the API in multiple spots is not realistic.



    Code example:



    class WrappedApi:
    def __init__(self):
    self.example_1 = OriginalApi()
    self.example_2 = OriginalApi()

    def do_something(self, new_a, new_b, put_them_together=None):
    self.example_1.do_something(new_a, new_b, put_them_together)
    self.example_2.do_something(new_a, new_b, put_them_together)



  • Using a list and a for-loop This changes the API on the object. That said, this is the backup solution in the event I can't find something more elegant. In this case, the WrappedApi class would not exist.



    Code example:



    wrapped_apis = [OriginalApi(), OriginalApi()]
    for wrapped_api in wrapped_apis:
    wrapped_api.do_something(1, 2, True)


  • I tried using
    Python Object Wrapper, but I could not see how to have it call multiple sub-objects with the same arguments.


And for anyone curious about the use case, it's actually a collection of several matplotlib axes objects. I don't want to reimplement to entire axes API (it's big), and I don't want to change all the code that makes calls on axes (like plot, step, etc.)










share|improve this question



















  • 2





    How do you want to handle the sequence protocol? Should indexing into the wrapper give you one of the wrapped items, or the result of indexing into all of the wrapped items? This is going to be complex in the generic case.

    – jonrsharpe
    4 hours ago












  • is this referring to def __getitem__(self, i):? If so, I hadn't thought about that, but I think either method would be valid for my situation

    – TinyTheBrontosaurus
    4 hours ago













7












7








7


2






I'm looking for a way to have a collection of homogeneous objects, wrap them in another object, but have the wrapper object have the same API as the original and forward the corresponding API call to its object members.



class OriginalApi:
def __init__(self):
self.a = 1
self.b = "bee"

def do_something(self, new_a, new_b, put_them_together=None):
self.a = new_a or self.a
self.b = new_b or self.b

if put_them_together is not None:
self.b = "".format(self.a, self.b)

# etc.

class WrappedApi:
def __init__(self):
self.example_1 = OriginalApi()
self.example_2 = OriginalApi()


Some possible solutions that have been considered, but are inadequate:




  • Rewriting the whole API Why not? Not adequate because the API is fairly large and expanding. Having to maintain the API in multiple spots is not realistic.



    Code example:



    class WrappedApi:
    def __init__(self):
    self.example_1 = OriginalApi()
    self.example_2 = OriginalApi()

    def do_something(self, new_a, new_b, put_them_together=None):
    self.example_1.do_something(new_a, new_b, put_them_together)
    self.example_2.do_something(new_a, new_b, put_them_together)



  • Using a list and a for-loop This changes the API on the object. That said, this is the backup solution in the event I can't find something more elegant. In this case, the WrappedApi class would not exist.



    Code example:



    wrapped_apis = [OriginalApi(), OriginalApi()]
    for wrapped_api in wrapped_apis:
    wrapped_api.do_something(1, 2, True)


  • I tried using
    Python Object Wrapper, but I could not see how to have it call multiple sub-objects with the same arguments.


And for anyone curious about the use case, it's actually a collection of several matplotlib axes objects. I don't want to reimplement to entire axes API (it's big), and I don't want to change all the code that makes calls on axes (like plot, step, etc.)










share|improve this question
















I'm looking for a way to have a collection of homogeneous objects, wrap them in another object, but have the wrapper object have the same API as the original and forward the corresponding API call to its object members.



class OriginalApi:
def __init__(self):
self.a = 1
self.b = "bee"

def do_something(self, new_a, new_b, put_them_together=None):
self.a = new_a or self.a
self.b = new_b or self.b

if put_them_together is not None:
self.b = "".format(self.a, self.b)

# etc.

class WrappedApi:
def __init__(self):
self.example_1 = OriginalApi()
self.example_2 = OriginalApi()


Some possible solutions that have been considered, but are inadequate:




  • Rewriting the whole API Why not? Not adequate because the API is fairly large and expanding. Having to maintain the API in multiple spots is not realistic.



    Code example:



    class WrappedApi:
    def __init__(self):
    self.example_1 = OriginalApi()
    self.example_2 = OriginalApi()

    def do_something(self, new_a, new_b, put_them_together=None):
    self.example_1.do_something(new_a, new_b, put_them_together)
    self.example_2.do_something(new_a, new_b, put_them_together)



  • Using a list and a for-loop This changes the API on the object. That said, this is the backup solution in the event I can't find something more elegant. In this case, the WrappedApi class would not exist.



    Code example:



    wrapped_apis = [OriginalApi(), OriginalApi()]
    for wrapped_api in wrapped_apis:
    wrapped_api.do_something(1, 2, True)


  • I tried using
    Python Object Wrapper, but I could not see how to have it call multiple sub-objects with the same arguments.


And for anyone curious about the use case, it's actually a collection of several matplotlib axes objects. I don't want to reimplement to entire axes API (it's big), and I don't want to change all the code that makes calls on axes (like plot, step, etc.)







python






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 29 mins ago









Peter Mortensen

13.8k1987113




13.8k1987113










asked 4 hours ago









TinyTheBrontosaurusTinyTheBrontosaurus

1,33011025




1,33011025







  • 2





    How do you want to handle the sequence protocol? Should indexing into the wrapper give you one of the wrapped items, or the result of indexing into all of the wrapped items? This is going to be complex in the generic case.

    – jonrsharpe
    4 hours ago












  • is this referring to def __getitem__(self, i):? If so, I hadn't thought about that, but I think either method would be valid for my situation

    – TinyTheBrontosaurus
    4 hours ago












  • 2





    How do you want to handle the sequence protocol? Should indexing into the wrapper give you one of the wrapped items, or the result of indexing into all of the wrapped items? This is going to be complex in the generic case.

    – jonrsharpe
    4 hours ago












  • is this referring to def __getitem__(self, i):? If so, I hadn't thought about that, but I think either method would be valid for my situation

    – TinyTheBrontosaurus
    4 hours ago







2




2





How do you want to handle the sequence protocol? Should indexing into the wrapper give you one of the wrapped items, or the result of indexing into all of the wrapped items? This is going to be complex in the generic case.

– jonrsharpe
4 hours ago






How do you want to handle the sequence protocol? Should indexing into the wrapper give you one of the wrapped items, or the result of indexing into all of the wrapped items? This is going to be complex in the generic case.

– jonrsharpe
4 hours ago














is this referring to def __getitem__(self, i):? If so, I hadn't thought about that, but I think either method would be valid for my situation

– TinyTheBrontosaurus
4 hours ago





is this referring to def __getitem__(self, i):? If so, I hadn't thought about that, but I think either method would be valid for my situation

– TinyTheBrontosaurus
4 hours ago












2 Answers
2






active

oldest

votes


















5














If you're only implementing methods then a generic __getattr__ can do the trick



class Wrapper: 
def __init__(self, x):
self.x = x
def __getattr__(self, name):
def f(*args, **kwargs):
for y in self.x:
getattr(y, name)(*args, **kwargs)
return f


For example with x = Wrapper([[], [], []]) after calling x.append(12) all the three list objects will have 12 as last element.



Note that the return value will always be None... an option could be collecting return values and returning them as a list but this of course would "break the API".






share|improve this answer

























  • This only works for methods and other callable attributes, though. Gathering the results into a list would be straightforward, but it'd be hard to distinguish between the cases where you have a list of Nones and should return the list, or a list of Nones and should return None.

    – jonrsharpe
    3 hours ago












  • @jonrsharpe: yes of course, but it's hard to multiplex a protocol that requires reading without changing the API. What should len(x) return if the contained objects don't answer the same?

    – 6502
    3 hours ago











  • Well, quite! As I said above, in the generic case this gets very complex.

    – jonrsharpe
    3 hours ago











  • good point on the return values. i'm hoping my usage of matplotlib gets away with ignoring most return values. And if it doesn't? Then... well... this get a lot harder. I'll ask a new question if that's the case.

    – TinyTheBrontosaurus
    1 hour ago


















1














I think you have the right idea here



wrapped_apis = [OriginalApi(), OriginalApi()]
for wrapped_api in wrapped_apis:
wrapped_api.do_something(1, 2, True)


You can define your wrapper class by inheriting from list and then handle the API calls to its items once it is created.



class WrapperClass(list):
def __init__(self, api_type):
self.api_type = api_type

for func in dir(api_type):
if callable(getattr(api_type, func)) and not func.startswith("__"):
setattr(self, func, lambda *args, **kwargs:
[getattr(o, func)(*args, **kwargs) for o in self])

w = WrapperClass(OriginalApi)
o1, o2 = [OriginalApi()]*2
w.append(o1)
w.append(o2)
print(w.do_something(1, 2, True))
# [None, None]
print(w[0].b)
# 12
print(w[1].b)
# 12
print(o1.b)
# 12


Here, I'm iterating every method in your API class and creating a method in the wrapper class that applies its arguments to all its list items. It then returns a list comprehension consisting of the results.



Needless to say, you should probably validate the type of a new object being appended to this WrapperClass like so,



def append(self, item):
if not isinstance(item, self.api_type):
raise TypeError('Wrong API type. Expected %s'.format(self.api_type))
super(WrapperClass, self).append(item)





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%2f55211193%2fwrapping-homogeneous-python-objects%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    5














    If you're only implementing methods then a generic __getattr__ can do the trick



    class Wrapper: 
    def __init__(self, x):
    self.x = x
    def __getattr__(self, name):
    def f(*args, **kwargs):
    for y in self.x:
    getattr(y, name)(*args, **kwargs)
    return f


    For example with x = Wrapper([[], [], []]) after calling x.append(12) all the three list objects will have 12 as last element.



    Note that the return value will always be None... an option could be collecting return values and returning them as a list but this of course would "break the API".






    share|improve this answer

























    • This only works for methods and other callable attributes, though. Gathering the results into a list would be straightforward, but it'd be hard to distinguish between the cases where you have a list of Nones and should return the list, or a list of Nones and should return None.

      – jonrsharpe
      3 hours ago












    • @jonrsharpe: yes of course, but it's hard to multiplex a protocol that requires reading without changing the API. What should len(x) return if the contained objects don't answer the same?

      – 6502
      3 hours ago











    • Well, quite! As I said above, in the generic case this gets very complex.

      – jonrsharpe
      3 hours ago











    • good point on the return values. i'm hoping my usage of matplotlib gets away with ignoring most return values. And if it doesn't? Then... well... this get a lot harder. I'll ask a new question if that's the case.

      – TinyTheBrontosaurus
      1 hour ago















    5














    If you're only implementing methods then a generic __getattr__ can do the trick



    class Wrapper: 
    def __init__(self, x):
    self.x = x
    def __getattr__(self, name):
    def f(*args, **kwargs):
    for y in self.x:
    getattr(y, name)(*args, **kwargs)
    return f


    For example with x = Wrapper([[], [], []]) after calling x.append(12) all the three list objects will have 12 as last element.



    Note that the return value will always be None... an option could be collecting return values and returning them as a list but this of course would "break the API".






    share|improve this answer

























    • This only works for methods and other callable attributes, though. Gathering the results into a list would be straightforward, but it'd be hard to distinguish between the cases where you have a list of Nones and should return the list, or a list of Nones and should return None.

      – jonrsharpe
      3 hours ago












    • @jonrsharpe: yes of course, but it's hard to multiplex a protocol that requires reading without changing the API. What should len(x) return if the contained objects don't answer the same?

      – 6502
      3 hours ago











    • Well, quite! As I said above, in the generic case this gets very complex.

      – jonrsharpe
      3 hours ago











    • good point on the return values. i'm hoping my usage of matplotlib gets away with ignoring most return values. And if it doesn't? Then... well... this get a lot harder. I'll ask a new question if that's the case.

      – TinyTheBrontosaurus
      1 hour ago













    5












    5








    5







    If you're only implementing methods then a generic __getattr__ can do the trick



    class Wrapper: 
    def __init__(self, x):
    self.x = x
    def __getattr__(self, name):
    def f(*args, **kwargs):
    for y in self.x:
    getattr(y, name)(*args, **kwargs)
    return f


    For example with x = Wrapper([[], [], []]) after calling x.append(12) all the three list objects will have 12 as last element.



    Note that the return value will always be None... an option could be collecting return values and returning them as a list but this of course would "break the API".






    share|improve this answer















    If you're only implementing methods then a generic __getattr__ can do the trick



    class Wrapper: 
    def __init__(self, x):
    self.x = x
    def __getattr__(self, name):
    def f(*args, **kwargs):
    for y in self.x:
    getattr(y, name)(*args, **kwargs)
    return f


    For example with x = Wrapper([[], [], []]) after calling x.append(12) all the three list objects will have 12 as last element.



    Note that the return value will always be None... an option could be collecting return values and returning them as a list but this of course would "break the API".







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 3 hours ago

























    answered 3 hours ago









    65026502

    87.3k13115217




    87.3k13115217












    • This only works for methods and other callable attributes, though. Gathering the results into a list would be straightforward, but it'd be hard to distinguish between the cases where you have a list of Nones and should return the list, or a list of Nones and should return None.

      – jonrsharpe
      3 hours ago












    • @jonrsharpe: yes of course, but it's hard to multiplex a protocol that requires reading without changing the API. What should len(x) return if the contained objects don't answer the same?

      – 6502
      3 hours ago











    • Well, quite! As I said above, in the generic case this gets very complex.

      – jonrsharpe
      3 hours ago











    • good point on the return values. i'm hoping my usage of matplotlib gets away with ignoring most return values. And if it doesn't? Then... well... this get a lot harder. I'll ask a new question if that's the case.

      – TinyTheBrontosaurus
      1 hour ago

















    • This only works for methods and other callable attributes, though. Gathering the results into a list would be straightforward, but it'd be hard to distinguish between the cases where you have a list of Nones and should return the list, or a list of Nones and should return None.

      – jonrsharpe
      3 hours ago












    • @jonrsharpe: yes of course, but it's hard to multiplex a protocol that requires reading without changing the API. What should len(x) return if the contained objects don't answer the same?

      – 6502
      3 hours ago











    • Well, quite! As I said above, in the generic case this gets very complex.

      – jonrsharpe
      3 hours ago











    • good point on the return values. i'm hoping my usage of matplotlib gets away with ignoring most return values. And if it doesn't? Then... well... this get a lot harder. I'll ask a new question if that's the case.

      – TinyTheBrontosaurus
      1 hour ago
















    This only works for methods and other callable attributes, though. Gathering the results into a list would be straightforward, but it'd be hard to distinguish between the cases where you have a list of Nones and should return the list, or a list of Nones and should return None.

    – jonrsharpe
    3 hours ago






    This only works for methods and other callable attributes, though. Gathering the results into a list would be straightforward, but it'd be hard to distinguish between the cases where you have a list of Nones and should return the list, or a list of Nones and should return None.

    – jonrsharpe
    3 hours ago














    @jonrsharpe: yes of course, but it's hard to multiplex a protocol that requires reading without changing the API. What should len(x) return if the contained objects don't answer the same?

    – 6502
    3 hours ago





    @jonrsharpe: yes of course, but it's hard to multiplex a protocol that requires reading without changing the API. What should len(x) return if the contained objects don't answer the same?

    – 6502
    3 hours ago













    Well, quite! As I said above, in the generic case this gets very complex.

    – jonrsharpe
    3 hours ago





    Well, quite! As I said above, in the generic case this gets very complex.

    – jonrsharpe
    3 hours ago













    good point on the return values. i'm hoping my usage of matplotlib gets away with ignoring most return values. And if it doesn't? Then... well... this get a lot harder. I'll ask a new question if that's the case.

    – TinyTheBrontosaurus
    1 hour ago





    good point on the return values. i'm hoping my usage of matplotlib gets away with ignoring most return values. And if it doesn't? Then... well... this get a lot harder. I'll ask a new question if that's the case.

    – TinyTheBrontosaurus
    1 hour ago













    1














    I think you have the right idea here



    wrapped_apis = [OriginalApi(), OriginalApi()]
    for wrapped_api in wrapped_apis:
    wrapped_api.do_something(1, 2, True)


    You can define your wrapper class by inheriting from list and then handle the API calls to its items once it is created.



    class WrapperClass(list):
    def __init__(self, api_type):
    self.api_type = api_type

    for func in dir(api_type):
    if callable(getattr(api_type, func)) and not func.startswith("__"):
    setattr(self, func, lambda *args, **kwargs:
    [getattr(o, func)(*args, **kwargs) for o in self])

    w = WrapperClass(OriginalApi)
    o1, o2 = [OriginalApi()]*2
    w.append(o1)
    w.append(o2)
    print(w.do_something(1, 2, True))
    # [None, None]
    print(w[0].b)
    # 12
    print(w[1].b)
    # 12
    print(o1.b)
    # 12


    Here, I'm iterating every method in your API class and creating a method in the wrapper class that applies its arguments to all its list items. It then returns a list comprehension consisting of the results.



    Needless to say, you should probably validate the type of a new object being appended to this WrapperClass like so,



    def append(self, item):
    if not isinstance(item, self.api_type):
    raise TypeError('Wrong API type. Expected %s'.format(self.api_type))
    super(WrapperClass, self).append(item)





    share|improve this answer





























      1














      I think you have the right idea here



      wrapped_apis = [OriginalApi(), OriginalApi()]
      for wrapped_api in wrapped_apis:
      wrapped_api.do_something(1, 2, True)


      You can define your wrapper class by inheriting from list and then handle the API calls to its items once it is created.



      class WrapperClass(list):
      def __init__(self, api_type):
      self.api_type = api_type

      for func in dir(api_type):
      if callable(getattr(api_type, func)) and not func.startswith("__"):
      setattr(self, func, lambda *args, **kwargs:
      [getattr(o, func)(*args, **kwargs) for o in self])

      w = WrapperClass(OriginalApi)
      o1, o2 = [OriginalApi()]*2
      w.append(o1)
      w.append(o2)
      print(w.do_something(1, 2, True))
      # [None, None]
      print(w[0].b)
      # 12
      print(w[1].b)
      # 12
      print(o1.b)
      # 12


      Here, I'm iterating every method in your API class and creating a method in the wrapper class that applies its arguments to all its list items. It then returns a list comprehension consisting of the results.



      Needless to say, you should probably validate the type of a new object being appended to this WrapperClass like so,



      def append(self, item):
      if not isinstance(item, self.api_type):
      raise TypeError('Wrong API type. Expected %s'.format(self.api_type))
      super(WrapperClass, self).append(item)





      share|improve this answer



























        1












        1








        1







        I think you have the right idea here



        wrapped_apis = [OriginalApi(), OriginalApi()]
        for wrapped_api in wrapped_apis:
        wrapped_api.do_something(1, 2, True)


        You can define your wrapper class by inheriting from list and then handle the API calls to its items once it is created.



        class WrapperClass(list):
        def __init__(self, api_type):
        self.api_type = api_type

        for func in dir(api_type):
        if callable(getattr(api_type, func)) and not func.startswith("__"):
        setattr(self, func, lambda *args, **kwargs:
        [getattr(o, func)(*args, **kwargs) for o in self])

        w = WrapperClass(OriginalApi)
        o1, o2 = [OriginalApi()]*2
        w.append(o1)
        w.append(o2)
        print(w.do_something(1, 2, True))
        # [None, None]
        print(w[0].b)
        # 12
        print(w[1].b)
        # 12
        print(o1.b)
        # 12


        Here, I'm iterating every method in your API class and creating a method in the wrapper class that applies its arguments to all its list items. It then returns a list comprehension consisting of the results.



        Needless to say, you should probably validate the type of a new object being appended to this WrapperClass like so,



        def append(self, item):
        if not isinstance(item, self.api_type):
        raise TypeError('Wrong API type. Expected %s'.format(self.api_type))
        super(WrapperClass, self).append(item)





        share|improve this answer















        I think you have the right idea here



        wrapped_apis = [OriginalApi(), OriginalApi()]
        for wrapped_api in wrapped_apis:
        wrapped_api.do_something(1, 2, True)


        You can define your wrapper class by inheriting from list and then handle the API calls to its items once it is created.



        class WrapperClass(list):
        def __init__(self, api_type):
        self.api_type = api_type

        for func in dir(api_type):
        if callable(getattr(api_type, func)) and not func.startswith("__"):
        setattr(self, func, lambda *args, **kwargs:
        [getattr(o, func)(*args, **kwargs) for o in self])

        w = WrapperClass(OriginalApi)
        o1, o2 = [OriginalApi()]*2
        w.append(o1)
        w.append(o2)
        print(w.do_something(1, 2, True))
        # [None, None]
        print(w[0].b)
        # 12
        print(w[1].b)
        # 12
        print(o1.b)
        # 12


        Here, I'm iterating every method in your API class and creating a method in the wrapper class that applies its arguments to all its list items. It then returns a list comprehension consisting of the results.



        Needless to say, you should probably validate the type of a new object being appended to this WrapperClass like so,



        def append(self, item):
        if not isinstance(item, self.api_type):
        raise TypeError('Wrong API type. Expected %s'.format(self.api_type))
        super(WrapperClass, self).append(item)






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 2 hours ago

























        answered 3 hours ago









        darkskydarksky

        1,4261224




        1,4261224



























            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.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55211193%2fwrapping-homogeneous-python-objects%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

            Era Viking Índice Início da Era Viquingue | Cotidiano | Sociedade | Língua | Religião | A arte | As primeiras cidades | As viagens dos viquingues | Viquingues do Oeste e Leste | Fim da Era Viquingue | Fontes históricas | Referências Bibliografia | Ligações externas | Menu de navegação«Sverige då!»«Handel I vikingetid»«O que é Nórdico Antigo»Mito, magia e religião na volsunga saga Um olhar sobre a trajetória mítica do herói sigurd«Bonden var den verklige vikingen»«Vikingatiden»«Vikingatiden»«Vinland»«Guerreiras de Óðinn: As Valkyrjor na Mitologia Viking»1519-9053«Esculpindo símbolos e seres: A arte viking em pedras rúnicas»1679-9313Historia - Tema: VikingarnaAventura e Magia no Mundo das Sagas IslandesasEra Vikinge

            What's the metal clinking sound at the end of credits in Avengers: Endgame?What makes Thanos so strong in Avengers: Endgame?Who is the character that appears at the end of Endgame?What happens to Mjolnir (Thor's hammer) at the end of Endgame?The People's Ages in Avengers: EndgameWhat did Nebula do in Avengers: Endgame?Messing with time in the Avengers: Endgame climaxAvengers: Endgame timelineWhat are the time-travel rules in Avengers Endgame?Why use this song in Avengers: Endgame Opening Logo Sequence?Peggy's age in Avengers Endgame

            Mortes em março de 2019 Referências Menu de navegação«Zhores Alferov, Nobel de Física bielorrusso, morre aos 88 anos - Ciência»«Fallece Rafael Torija, o bispo emérito de Ciudad Real»«Peter Hurford dies at 88»«Keith Flint, vocalista do The Prodigy, morre aos 49 anos»«Luke Perry, ator de 'Barrados no baile' e 'Riverdale', morre aos 52 anos»«Former Rangers and Scotland captain Eric Caldow dies, aged 84»«Morreu, aos 61 anos, a antiga lenda do wrestling King Kong Bundy»«Fallece el actor y director teatral Abraham Stavans»«In Memoriam Guillaume Faye»«Sidney Sheinberg, a Force Behind Universal and Spielberg, Is Dead at 84»«Carmine Persico, Colombo Crime Family Boss, Is Dead at 85»«Dirigent Michael Gielen gestorben»«Ciclista tricampeã mundial e prata na Rio 2016 é encontrada morta em casa aos 23 anos»«Pagan Community Notes: Raven Grimassi dies, Indianapolis pop-up event cancelled, Circle Sanctuary announces new podcast, and more!»«Hal Blaine, Wrecking Crew Drummer, Dies at 90»«Morre Coutinho, que editou dupla lendária com Pelé no Santos»«Cantor Demétrius, ídolo da Jovem Guarda, morre em SP»«Ex-presidente do Vasco, Eurico Miranda morre no Rio de Janeiro»«Bronze no Mundial de basquete de 1971, Laís Elena morre aos 76 anos»«Diretor de Corridas da F1, Charlie Whiting morre aos 66 anos às vésperas do GP da Austrália»«Morreu o cardeal Danneels, da Bélgica»«Morreu o cartoonista Augusto Cid»«Morreu a atriz Maria Isabel de Lizandra, de "Vale Tudo" e novelas da Tupi»«WS Merwin, prize-winning poet of nature, dies at 91»«Atriz Márcia Real morre em São Paulo aos 88 anos»«Mauritanie: décès de l'ancien président Mohamed Mahmoud ould Louly»«Morreu Dick Dale, o rei da surf guitar e de "Pulp Fiction"»«Falleció Víctor Genes»«João Carlos Marinho, autor de 'O Gênio do Crime', morre em SP»«Legendary Horror Director and SFX Artist John Carl Buechler Dies at 66»«Morre em Salvador a religiosa Makota Valdina»«مرگ بازیکن‌ سابق نساجی بر اثر سقوط سنگ در مازندران»«Domingos Oliveira morre no Rio»«Morre Airton Ravagniani, ex-São Paulo, Fla, Vasco, Grêmio e Sport - Notícias»«Morre o escritor Flavio Moreira da Costa»«Larry Cohen, Writer-Director of 'It's Alive' and 'Hell Up in Harlem,' Dies at 77»«Scott Walker, experimental singer-songwriter, dead at 76»«Joseph Pilato, Day of the Dead Star and Horror Favorite, Dies at 70»«Sheffield United set to pay tribute to legendary goalkeeper Ted Burgin who has died at 91»«Morre Rafael Henzel, sobrevivente de acidente aéreo da Chapecoense»«Morre Valery Bykovsky, um dos primeiros cosmonautas da União Soviética»«Agnès Varda, cineasta da Nouvelle Vague, morre aos 90 anos»«Agnès Varda, cineasta francesa, morre aos 90 anos»«Tania Mallet, James Bond Actress and Helen Mirren's Cousin, Dies at 77»e