1

I have this kind of a function call in Python:

foo(["A", "B", "X", "Y", "Z"], SomeClass("m", ["A", "B", "X", "Y", "Z"]), SomeClass("n",["A", "B", "X", "Y", "Z"]))

In general, foo can have arbitrary number of arguments, so there can be many SomeClass objects passed, but when calling the constructor, you always have to pass the same thing that you pass as the first argument to foo, What I'd like to have is this:

foo(["A", "B", "X", "Y", "Z"], SomeClass("m", arg1), SomeClass("n", arg1))

So the code is shorter and more readable. What should I put instead of arg1 in order to "reference" the first argument passed to foo?

Lilly
  • 33
  • 3
  • 1
    You could change the prototype of `foo`, so that it could be used like `foo(["A", "B", "X", "Y", "Z"], "m", "n")`, and internally `foo` would instantiate the different objects. Also, another solution would be to create variable `arg1`, and delete it after function call. – Spirine Aug 10 '16 at 12:48
  • Sprine, you should add that as an answer. Your first solution is better than the ones answered so far. – Oscar Smith Aug 10 '16 at 13:04

2 Answers2

4

Why not to use variable:

arg1 = ["A", "B", "X", "Y", "Z"]
foo(arg1, SomeClass("m", arg1), SomeClass("n", arg1))

NOTE: lists passed by reference so if you modify it within foo or while initializing SomeClass you could get unpredictable result to avoid such case you have to pass copy of list, see more on that How to clone or copy a list? question.

To fix reference problem you have to make copy of list prior passing it to SomeClass or foo, it can be done with copy.copy(), copy.deepcopy() or list slicing:

from copy import copy, deepcopy


foo(copy(arg1), SomeClass("m", copy(arg1)), SomeClass("n", copy(arg1)))

foo(arg1[:], SomeClass("m", arg1[:]), SomeClass("n", arg1[:]))
foo(deepcopy(arg1), SomeClass("m", deepcopy(arg1)), SomeClass("n", deepcopy(arg1)))

Important moment is that list slicing ([:]) and copy.copy() return shallow copy of the list meanwhile copy.deepcopy() returns deep copy. See more on What exactly is the difference between shallow copy, deepcopy and normal assignment operation?

Community
  • 1
  • 1
Andriy Ivaneyko
  • 20,639
  • 6
  • 60
  • 82
2

No, there are no such references; you passed in a list literal object, there are no other references to it other than the internal interpreter stack.

Simply create your own reference; store that first list in a variable first, then reference that:

arg1 = ["A", "B", "X", "Y", "Z"]
foo(arg1, SomeClass("m", arg1), SomeClass("n", arg1))

If foo() is always going to need a number of SomeClass() instances based on arg1, you could also make foo() responsible for creating those instances. Pass in only that one other argument to SomeClass():

foo(["A", "B", "X", "Y", "Z"], "m", "n")

and in foo:

def foo(arg1, *arg2_values):
    instances = [SomeClass(arg1, arg2) for arg2 in arg2_values]

Now the caller only has to pass in that list once.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343