-1

I apologize if this seems like an obvious question, but I cannot find the word to search for to describe this.

I am currently writing this:

foo.cat()
foo.dog()
foo.fish()
foo.moose()
foo.horse()
...

I'd rather write this:

many foo:
    dog()
    cat()
    fish()
    horse()
    ...

How can I do this in Python 3? Is there a keyword, or something?

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
  • 1
    No. The first way is the idiomatic way to do this in Python. And there isn't anything inelegant about it. – juanpa.arrivillaga Jul 14 '22 at 22:06
  • If foo is a user-defined class, you can add a method to it which calls all these methods, or you can create a function which accepts an object of foo as an argument. Then you just need to call that function/method. You normally only need to do this if you are going to be calling these methods a lot of times (to minimize repeated code) – Charchit Agarwal Jul 14 '22 at 22:09
  • As an aside, always use the generic [python] tag for all Python related questions. – juanpa.arrivillaga Jul 14 '22 at 22:10
  • You could consider implementing a [fluent interface](https://stackoverflow.com/q/37827808/4583620) so that you could call like: `foo.cat().dog().fish()...`. I don't think this is definitively better or more "elegant" but it is an option. – Michael Ruth Jul 14 '22 at 23:44
  • does "many foo" imply that you have a *list of foos*? you then say "call *on one object*", so what is it? – Christoph Rackwitz Jul 17 '22 at 10:14

3 Answers3

2
  1. You could use dog() - only one function with that specific name
  2. you could make new function that will call all of them
  3. use something like this
exec_methods = ["dog", "cat", "fish"]
for method in exec_methods:
    getattr(x, method)()
Michael Štekrt
  • 406
  • 3
  • 8
  • `for method in ("dog", "cat", "fish"): getattr(foo, method)()` — however neither idiomatic nor especially elegant. – martineau Jul 14 '22 at 23:12
0

If you want to shorten "foo", you can do

for f in [foo]:
    f.dog()
    f.cat()
    f.fish()
    f.horse()

    del f # deletes f to avoid leaving orphan variables
Colim
  • 1,283
  • 3
  • 11
  • This is it; I hadn't considered a trivial iterator. This simplifies things enough that my engineers will be able to debug the hardware initialization sequence without having to write entire blocks of LT8740_io.LT8740_iO_X[0].foo() everywhere. Thank you, this'll save my hardware guys a lot of typing during hardware debug. – Analog Moose Jul 15 '22 at 20:25
  • 1
    @AnalogMoose Do you not realize you can just do `f = foo` (and omit the indentation)? Even less typing... – Kelly Bundy Jul 15 '22 at 21:03
  • I do, but my engineers might lose track of which is which over months of dd – Analog Moose Jul 16 '22 at 07:21
  • I do, but my engineers might lose track over months of debug and development if x is the 8740 test command of core 0 subsystem whereas y is the g91 sense resistor array SPI core and then z is the x of core 1. I want them to have a title at the top of each block saying "Dude, we are initializing the g91 fault masks right now." To keep order in all of these operations, I'd need to keep undefining things after using them. For does it for me; 'i' just vanished, – Analog Moose Jul 16 '22 at 07:24
  • 1
    @AnalogMoose *"I'd need to keep undefining things after using them. For does it for me"* - Uh... that's not true, `for` *doesn't* undefine. – Kelly Bundy Jul 16 '22 at 14:02
  • So if I unindent the last line, the program will still recognize f.? – Analog Moose Jul 16 '22 at 19:52
  • 1
    @AnalogMoose Yes. Did you not try it? – Kelly Bundy Jul 16 '22 at 19:58
  • Odd. Well, it won't hurt me. The engineers will still be able to use it, and it'll cut down on the endless pages of codes. – Analog Moose Jul 18 '22 at 00:22
  • You can delete f at the end – Colim Jul 18 '22 at 07:24
0

You could define a methodscaller function that was somewhat of hybrid between what operator.itemgetter() and operator.methodcaller() do that created something callable that would call all the methods specified when it was called. The function itself would be generic in the sense that it can be used with any type of object and/or series of methods.

The following demonstrates what I mean:

class Foo:
    def dog(self): print('dog called')
    def cat(self): print('cat called')
    def fish(self): print('fish called')
    def moose(self): print('moose called')
    def horse(self): print('horse called')


def methodscaller(*methods):
    """Return callable object that calls the methods named in its operand."""
    if len(methods) == 1:
        def g(obj):
            return getattr(obj, methods[0])
    else:
        def g(obj):
            return tuple(getattr(obj, method)() for method in methods)
    return g


call_methods = methodscaller('dog', 'cat', 'fish', 'moose', 'horse')
call_methods(Foo())
martineau
  • 119,623
  • 25
  • 170
  • 301
  • Hmm, what's the relationship to itemgetter? – Kelly Bundy Jul 15 '22 at 01:16
  • @Kelly: It's similar in the sense of the way it handles one or more items (`methodcaller` doesn't accept multiple method names). [`attrgetter()`](https://docs.python.org/3/library/operator.html#operator.attrgetter) also does. – martineau Jul 15 '22 at 01:22