Say I have a Python function that returns multiple values in a tuple:
def func():
return 1, 2
Is there a nice way to ignore one of the results rather than just assigning to a temporary variable? Say if I was only interested in the first value, is there a better way than this:
x, temp = func()
You can use x = func()[0] to return the first value, x = func()[1] to return the second, and so on.
If you want to get multiple values at a time, use something like x, y = func()[2:4].
One common convention is to use a "_" as a variable name for the elements of the tuple you wish to ignore. For instance:
def f():
return 1, 2, 3
_, _, x = f()
If you're using Python 3, you can you use the star before a variable (on the left side of an assignment) to have it be a list in unpacking.
# Example 1: a is 1 and b is [2, 3]
a, *b = [1, 2, 3]
# Example 2: a is 1, b is [2, 3], and c is 4
a, *b, c = [1, 2, 3, 4]
# Example 3: b is [1, 2] and c is 3
*b, c = [1, 2, 3]
# Example 4: a is 1 and b is []
a, *b = [1]
The common practice is to use the dummy variable _ (single underscore), as many have indicated here before.
However, to avoid collisions with other uses of that variable name (see this response) it might be a better practice to use __ (double underscore) instead as a throwaway variable, as pointed by ncoghlan. E.g.:
x, __ = func()
Remember, when you return more than one item, you're really returning a tuple. So you can do things like this:
def func():
return 1, 2
print func()[0] # prints 1
print func()[1] # prints 2
The best solution probably is to name things instead of returning meaningless tuples (unless there is some logic behind the order of the returned items). You can for example use a dictionary:
def func():
return {'lat': 1, 'lng': 2}
latitude = func()['lat']
You could even use namedtuple if you want to add extra information about what you are returning (it's not just a dictionary, it's a pair of coordinates):
from collections import namedtuple
Coordinates = namedtuple('Coordinates', ['lat', 'lng'])
def func():
return Coordinates(lat=1, lng=2)
latitude = func().lat
If the objects within your dictionary/tuple are strongly tied together then it may be a good idea to even define a class for it. That way you'll also be able to define more complex operations. A natural question that follows is: When should I be using classes in Python?
Most recent versions of python (≥ 3.7) have dataclasses which you can use to define classes with very few lines of code:
from dataclasses import dataclass
#dataclass
class Coordinates:
lat: float = 0
lng: float = 0
def func():
return Coordinates(lat=1, lng=2)
latitude = func().lat
The primary advantage of dataclasses over namedtuple is that its easier to extend, but there are other differences. Note that by default, dataclasses are mutable, but you can use #dataclass(frozen=True) instead of #dataclass to force them being immutable.
Here is a video that might help you pick the right data class for your use case.
Three simple choices.
Obvious
x, _ = func()
x, junk = func()
Hideous
x = func()[0]
And there are ways to do this with a decorator.
def val0( aFunc ):
def pick0( *args, **kw ):
return aFunc(*args,**kw)[0]
return pick0
func0= val0(func)
This seems like the best choice to me:
val1, val2, ignored1, ignored2 = some_function()
It's not cryptic or ugly (like the func()[index] method), and clearly states your purpose.
If this is a function that you use all the time but always discard the second argument, I would argue that it is less messy to create an alias for the function without the second return value using lambda.
def func():
return 1, 2
func_ = lambda: func()[0]
func_() # Prints 1
This is not a direct answer to the question. Rather it answers this question: "How do I choose a specific function output from many possible options?".
If you are able to write the function (ie, it is not in a library you cannot modify), then add an input argument that indicates what you want out of the function. Make it a named argument with a default value so in the "common case" you don't even have to specify it.
def fancy_function( arg1, arg2, return_type=1 ):
ret_val = None
if( 1 == return_type ):
ret_val = arg1 + arg2
elif( 2 == return_type ):
ret_val = [ arg1, arg2, arg1 * arg2 ]
else:
ret_val = ( arg1, arg2, arg1 + arg2, arg1 * arg2 )
return( ret_val )
This method gives the function "advanced warning" regarding the desired output. Consequently it can skip unneeded processing and only do the work necessary to get your desired output. Also because Python does dynamic typing, the return type can change. Notice how the example returns a scalar, a list or a tuple... whatever you like!
When you have many output from a function and you don't want to call it multiple times, I think the clearest way for selecting the results would be :
results = fct()
a,b = [results[i] for i in list_of_index]
As a minimum working example, also demonstrating that the function is called only once :
def fct(a):
b=a*2
c=a+2
d=a+b
e=b*2
f=a*a
print("fct called")
return[a,b,c,d,e,f]
results=fct(3)
> fct called
x,y = [results[i] for i in [1,4]]
And the values are as expected :
results
> [3,6,5,9,12,9]
x
> 6
y
> 12
For convenience, Python list indexes can also be used :
x,y = [results[i] for i in [0,-2]]
Returns : a = 3 and b = 12
It is possible to ignore every variable except the first with less syntax if you like. If we take your example,
# The function you are calling.
def func():
return 1, 2
# You seem to only be interested in the first output.
x, temp = func()
I have found the following to works,
x, *_ = func()
This approach "unpacks" with * all other variables into a "throwaway" variable _. This has the benefit of assigning the one variable you want and ignoring all variables behind it.
However, in many cases you may want an output that is not the first output of the function. In these cases, it is probably best to indicate this by using the func()[i] where i is the index location of the output you desire. In your case,
# i == 0 because of zero-index.
x = func()[0]
As a side note, if you want to get fancy in Python 3, you could do something like this,
# This works the other way around.
*_, y = func()
Your function only outputs two potential variables, so this does not look too powerful until you have a case like this,
def func():
return 1, 2, 3, 4
# I only want the first and last.
x, *_, d = func()
Related
I am trying to create a set of functions in python that will all do a similar operation on a set of inputs. All of the functions have one input parameter fixed and half of them also need a second parameter. For the sake of simplicity, below is a toy example with only two functions.
Now, I want, in my script, to run the appropriate function, depending on what the user input as a number. Here, the user is the random function (so the minimum example works). What I want to do is something like this:
def function_1(*args):
return args[0]
def function_2(*args):
return args[0] * args[1]
x = 10
y = 20
i = random.randint(1,2)
f = function_1 if i==1 else function_2
return_value = f(x,y)
And it works, but it seems messy to me. I would rather have function_1 defined as
def function_1(x):
return x
Another way would be to define
def function_1(x,y):
return x
But that leaves me with a dangling y parameter.
but that will not work as easily. Is my way the "proper" way of solving my problem or does there exist a better way?
There are couple of approaches here, all of them adding more boiler-plate code.
There is also this PEP which may be interesting to you.
But 'pythonic' way of doing it is not as elegant as usual function overloading due to the fact that functions are just class attributes.
So you can either go with function like that:
def foo(*args):
and then count how many args you've got which will be very broad but very flexible as well.
another approach is the default arguments:
def foo(first, second=None, third=None)
less flexible but easier to predict, and then lastly you can also use:
def foo(anything)
and detect the type of anything in your function acting accordingly.
Your monkey-patching example can work too, but it becomes more complex if you use it with class methods, and does make introspection tricky.
EDIT: Also, for your case you may want to keep the functions separate and write single 'dispatcher' function that will call appropriate function for you depending on the arguments, which is probably best solution considering above.
EDIT2: base on your comments I believe that following approach may work for you
def weigh_dispatcher(*args, **kwargs):
#decide which function to call base on args
if 'somethingspecial' in kwargs:
return weight2(*args, **kwargs)
def weight_prep(arg):
#common part here
def weight1(arg1, arg2):
weitht_prep(arg1)
#rest of the func
def weight2(arg1, arg2, arg3):
weitht_prep(arg1)
#rest of the func
alternatively you can move the common part into the dispatcher
You may also have a function with optional second argument:
def function_1(x, y = None):
if y != None:
return x + y
else:
return x
Here's the sample run:
>>> function_1(3)
3
>>> function_1(3, 4)
7
Or even optional multiple arguments! Check this out:
def function_2(x, *args):
return x + sum(args)
And the sample run:
>>> function_2(3)
3
>>> function_2(3, 4)
7
>>> function_2(3, 4, 5, 6, 7)
25
You may here refer to args as to list:
def function_3(x, *args):
if len(args) < 1:
return x
else:
return x + sum(args)
And the sample run:
>>> function_3(1,2,3,4,5)
15
This is my first time asking a question in SO, so if I'm somehow not doing it properly don't hesitate to edit it or ask me to modify it.
I think my question is kind of general, so I'm quite surprised for not having found any previous one related to this topic. If I missed it and this question is duplicated, I'll be very grateful if you could provide a link to where it was already answered.
Imagine I need to implement a function with (at least) three parameters: an array a, a start index and an end index. If not provided, the start parameter should refer to the first position of the array (start = 0), while the end parameter should be set to the last position (end = len(a) - 1). Obviously, the definition:
def function(a, start = 0, end = (len(a) - 1)):
#do_something
pass
does not work, leading to an exception (NameError: name 'a' is not defined). There are some workarounds, such as using end = -1 or end = None, and conditionally assign it to len(a) - 1 if needed inside the body of the function:
def function(a, start = 0, end = -1):
end = end if end != -1 else (len(a) -1)
#do_something
but I have the feeling that there should be a more "pythonic" way of dealing with such situations, not only with the length of an array but with any parameter whose default value is a function of another (non optional) parameter. How would you deal with a situation like that? Is the conditional assignment the best option?
Thanks!
Using a sentinel value such as None is typical:
def func(a, start=0, end=None):
if end is None:
end = # whatever
# do stuff
However, for your actual use case, there's already a builtin way to do this that fits in with the way Python does start/stop/step - which makes your function provide a consistent interface as to the way builtins/other libraries work:
def func(a, *args):
slc = slice(*args)
for el in a[slc]:
print(el)
See https://docs.python.org/2/library/functions.html#slice
If you only want to support start/end in that order, then (note that None effectively means until len(a) when used as end or 0 when used as start):
def func(a, start=0, end=None):
return a[start:end]
This isn't possible, functions can't be executed in the parameter list, you can pass along functions through the parameters but not their output.
def function(a, start = 0):
end = len(a)
Based on the answer provided by #NPE in Function with dependent preset arguments, an alternative to using -1 or (better) None as sentinel values is using an object (a named object?) which can be used even if None is a valid value of the function. For example:
default = object()
def function(a, start = 0, end = default):
if end is default: end = (len(a) - 1)
return start, end
allows a call like: function([1,2,3,4]) which returns (0, 3)
I personally find this solution quite convenient, at least for my own purpose
Edit: Maybe the code is even more readable if we use last instead of default:
last = object()
def function(a, start = 0, end = last):
if end is last: end = (len(a) - 1)
return start, end
I am unsure of your definition of an array or the premise of your problem, but to my understanding you are trying get end to be assigned to the length of a. If so, just declare end out side the arguments. Like so:
def function(a, start=0):
end=len(a)
Or do the conditional like you said:
def function(a, start=0, end=False):
if not end:
end = len(a)
Or simply declare the end variable before calling the function and pass it in the arguments!
Not sure if that answered your question, but hope it helped lol!
This has to be the hackiest code I've ever written. I think it comes close to what you were asking for (another alternative I came up with was using a lambda inside the function definition, but it takes a bit too much room to be pretty IMO):
import inspect
from functools import wraps
class defaultArguments(object):
def __init__(self):
self.lazyArgs = []
def initialize(self, func):
lazyArgs, self.lazyArgs = self.lazyArgs, []
#wraps(func)
def functionWrapper(*args, **kw):
if lazyArgs:
argNames, defaults = inspect.getargspec(func)[::3]
argValues = list(args) + [
kw[y] if y in kw else defaults[x]
for x,y in enumerate(argNames[len(args):])
]
oldGlobals = {}
for n,v in zip(argNames, argValues):
try:
oldGlobals[n] = globals()[n]
except:
oldGlobals[n] = None
if v not in lazyArgs:
globals()[n] = v
else:
globals()[n] = kw[n] = eval(v)
for o,v in oldGlobals.items(): globals()[o] = v
return func(*args, **kw)
return functionWrapper
def __call__(self, x):
self.lazyArgs.append(x)
return x
Using it:
d = defaultArguments()
#d.initialize
def function1(a, start=d('a[-1]'), end=d('len(a)-1')):
print a, start, end
function1([1,2,8])
>>> [1, 2, 8] 8 2
function1([1,2,8,10], end=1)
>>> [1, 2, 8, 10] 10 1
#d.initialize
def function2(a, b, c, start=d('a*b*c'), end=d('a+b+c+start')):
print a, start, end
function2(2,4,6)
>>> 2 48 60
# Notice that `end` does take the calculated value of `start` into
# account. The logic here is based on what you'd expect to happen
# with normal assignment if the names were each assigned a value
# sequentially: a is evaluated, then b, then c, etc...
I do feel guilty for doing this, especially with the way I resorted to using globals and other cheats. However, I think it works as you requested.
Unfortunately, you do have to write extra stuff (using a decorator and having to wrap keyword values in d('') ), but that was inevitable as Python doesn't support this natively.
Edit:
I worked on the sugary part of the syntax a bit. Shortened it down to a simple decorator function.
def initArgs(func):
#wraps(func)
def functionWrapper(*args, **kw):
argNames, defaults = inspect.getargspec(func)[::3]
for k in kw:
for i in argNames:
if k != i and ('_' + k) == i:
kw['_' + k] = kw[k]
del kw[k]
argValues = list(args) + [
kw[y] if y in kw else defaults[x]
for x,y in enumerate(argNames[len(args):])
]
oldGlobals = {}
for n,v in zip(argNames, argValues):
try:
oldGlobals[n] = globals()[n]
except:
oldGlobals[n] = None
if not n.startswith('_') or n in kw:
globals()[n] = v
else:
globals()[n] = kw[n] = eval(v)
for o,v in oldGlobals.items(): globals()[o] = v
return func(*args, **kw)
return functionWrapper
To use it:
# When using initArgs, the strings associated with the keyword arguments will
# get eval'd only if the name is preceded with an underscore(`_`). It's a
# bit strange and unpythonic for part of a name to have side effects, but then
# again name mangling works with double underscores (`__`) before methods.
# Example:
#initArgs
def function1(a, _start='a[-1]', _end='len(a)-1'):
print a, _start, _end
function1([1,2,8,10])
>>> [1, 2, 8, 10] 10 3
# Removing underscore (`_`) from start
#initArgs
def function2(a, start='a[-1]', _end='len(a)-1'):
print a, start, _end
function1([1,2,8,10])
>>> [1, 2, 8, 10] 'a[-1]' 3
# Outputs a string normally.
In the caller's frame, the arguments start and end can used with or without their underscores, so changing their names in the function definition at a later point wouldn't affect the caller. The only exception is within the function itself, where removing an underscore(_) would require doing the same everywhere else inside.
I am aware that Python reduce only accepts a function with two arguments. However, is there a way to make more than two arguments available to the function? I don't want to make it a global variable because that would be visible for all other imports. The following snippet might help describing the problem (Please read the comments in the snippets):
# The reduce function
def apply_something(something, config):
# Consrtuct a class object based on the truth value of some other variable.
# some_var can be changed and is being accessed in different threads so its
# not safe to make it global. The reduce function is being called from
# inside some other function so It would be better to make
# some_var only accessible in the function context.
if some_var:
obj = Klass(some_var)
else:
obj = Klass()
def callee():
# This is how I apply the reduce operation.
reduce(apply_something, [1, 2, 3], something_initializer)
# I want something like this:
some_var = True # So this can be accessed in apply_something
Please provide some insight into this kind of problem.
I think what you're looking for is partial function application, which you can do using functools.
def apply_something(something, config, some_var):
pass # ...
import functools
functools.reduce(functools.partial(apply_something, some_var=True),
[1, 2, 3], something_initializer)
Example:
>>> def foo(a, b, c):
... return a + b if c else a * b
>>> functools.reduce(functools.partial(foo, c=True), [1,2,3,4,5], 0)
15
>>> functools.reduce(functools.partial(foo, c=False), [1,2,3,4,5], 1)
120
Strictly speaking, the function passed to reduce will always be called with two arguments. However, these types of functions will often access variables in an outer scope. Since I'm unclear on your exact problem, let's implement join in terms of reduce:
def join(joining_string, strings_to_join):
# i.e., join('-', ['a', 'b', 'c']) -> 'a-b-c'
# Here, we need an extra piece of data in our reduce function:
# joining_string.
def do_reduce(a, b):
# Joining string comes from the outer scope:
return a + joining_string + b
return reduce(do_reduce, strings_to_join)
Also, Chris Martin's solution involving partial is perfectly correct as well. Applying it to the above would look like this:
# This didn't *need* to move out of join, but it can. Before, it needed
# to be in join to be able to "capture" the local variable joining_string.
def do_reduce(a, b, joiner):
# Joining string comes from the outer scope:
return a + joiner + b
def join(joining_string, strings_to_join):
# i.e., join('-', ['a', 'b', 'c']) -> 'a-b-c'
# Here, we need an extra piece of data in our reduce function:
# joining_string.
return reduce(
functools.partial(do_reduce, joiner=joining_string),
strings_to_join)
You could as well just use a lambda:
def foo(total, cur, some_var=False):
pass # ...
reduce(lambda total, cur: foo(total, cur, some_var=True), [1, 2, 3], init)
Imagine I've got a Python module with some function in it:
def sumvars(x, y, z):
s = x
s += y
s += z
return s
But sometimes I want to get results of some intermediate calculations (for example, I could have a function which reverses a matrix and would like to know the determinant which has been calculated as an intermediate step as well). Obviously, I wouldn't want to redo those calculations again if they were already done within that function.
My first idea is to return a dict:
def sumvars(x, y, z):
d = {}
s = x
d['first_step'] = s
s += y
d['second_step'] = s
s += z
d['final'] = s
return d
But I don't recall any functions in numpy or scipy which return dicts and so it seems like this might be not a good idea. (Why?) Also routinely I'll always have to type sumvars(x,y,z)['final'] for a default return value...
Another option I see is creating global variables but seems wrong having a bunch of them in my module, I would need to remember their names and in addition not being attached to the function itself looks like a bad design choice.
What would be the proper function design for such situation?
Generally when you have two different ways you want to return data, go ahead and make two different functions. "Flat is better than nested", after all. Just have one call the other so that you Don't Repeat Yourself.
For example, in the standard library, urllib.parse has parse_qs (which returns a dict) and parse_qsl (which returns a list). parse_qs just then calls the other:
def parse_qs(...):
parsed_result = {}
pairs = parse_qsl(qs, keep_blank_values, strict_parsing,
encoding=encoding, errors=errors)
for name, value in pairs:
if name in parsed_result:
parsed_result[name].append(value)
else:
parsed_result[name] = [value]
return parsed_result
Pretty straightforward. So in your example it seems fine to have
def sumvars(x, y, z):
return sumvars_with_intermediates(x, y, z).final
def sumvars_with_intermediates(x, y, z):
...
return my_namedtuple(final, first_step, second_step)
(I favor returning namedtuples instead of dicts from my APIs, it's just prettier)
Another obvious example is in re: re.findall is its own function, not some configuration flag to search.
Now, the standard library is a sprawling thing made by many authors, so you'll find counterexamples to every example. You'll far more often see the above pattern rather than one omnibus function that accepts some configuration flags, though, and I find it far more readable.
Put the common calculation into its own function as Jayanth Koushik recommended if that calculation can be named appropriately. If you want to return many values (an intermediate result and a final result) from a single function then a dict may be an overkill depending on what is your goal but in python it is much more natural to simply return a tuple if your function has many values to return:
def myfunc():
intermediate = 5
result = 6
return intermediate, result
# using the function:
intermediate, result = myfunc()
Not sure if function attributes is a good idea:
In [569]: def sumvars(x, y, z):
...: s = x
...: sumvars.first_step = s
...: s += y
...: sumvars.second_step = s
...: s += z
...: return s
In [570]: res=sumvars(1,2,3)
...: print res, sumvars.first_step, sumvars.second_step
...:
6 1 3
Note: as #BrenBarn mentioned, this idea is just like global variables, your previously calculated "intermediate results" could not be stored when you want to reuse them.
Just came up with this idea which could be a better solution:
def sumvars(x, y, z, mode = 'default'):
d = {}
s = x
d['first_step'] = s
s += y
d['second_step'] = s
s += z
d['final'] = s
if mode == 'default':
return s
else:
return d
I belive the proper solution is to use a class, to have a better grasp of what you are modeling. For example in the case of the Matrix, you could simply store the determinant in the "determinant" attribute.
Here is an example using your matrix example.
class Matrix:
determinant = 0
def calculate_determinant(self):
#calculations
return determinant
def some_method(self, args):
# some calculations here
self.determinant = self.calculate_determinant()
# other calculations
matrix = Matrix()
matrix.some_method(x, y, z)
print matrix.determinant
This also allows you to separate your method into simpler methods, like one for calculating the determinant of your matrix.
Another variation:
def sumvars(x, y, z, d=None):
s = x
if not d is None:
d['first_step'] = s
s += y
if not d is None:
d['second_step'] = s
s += z
return s
The function always returns the desired value without packing it into a tuple or dictionary. The intermediate results are still available, but only if requested. The call
sumvars(1, 2, 3)
just returns 6 without storing intermediate values. But the call
d = {}
sumvars(1, 2, 3, d)
returns the same answer 6 and inserts the intermediate calculations into the supplied dictionary.
Option 1. Make two separate functions.
Option 2. Use a generator:
>>> def my_func():
... yield 1
... yield 2
...
>>> result_gen = my_func()
>>> result_gen
<generator object my_func at 0x7f62a8449370>
>>> next(result_gen)
1
>>> next(result_gen)
2
>>> next(result_gen)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
Inspired by #zhangxaochen solution, here's my take on your problem using class attributes:
class MyClass():
def __init__(self):
self.i = 4
def f(self):
s = self.i
MyClass.first_step = s
print(MyClass.first_step)
s += self.i
MyClass.second_step = s
print(MyClass.second_step)
s += self.i
return s
def main():
x = MyClass()
print(x.f()) # print final s
print(x.first_step)
print(x.second_step)
print(MyClass.second_step)
Note: I included several prints to make it more explicit how attribute values can be retrieved.
Result:
4
8
12
4
8
8
This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 9 years ago.
i need help-i try to send value to method like in c++ by ref/by ptr
how can i do it?
to exmple:
def test(x):
x=3
x=2
test(x)
print(x)
In this case x a local variable in test method and will not change the "original" X
so how can i change the "original" X?
thanks
In some ways, all calls in Python are called with references. In fact, all variables are references in a sense. But some types, like int from your example, cannot be changed.
In the case of, say, a list, the functionality you're looking for is trivial:
def change_it(some_list):
some_list.append("world")
foo = ["hello"]
change_it(foo)
print(foo) # prints ['hello', 'world']
Note, however, that reassigning the parameter variable some_list does not change the value in the calling context.
If you're asking this question, though, you're probably looking to do something like set two or three variables using one function. In that case, you're looking for something like this:
def foo_bar(x, y, z):
return 2*x, 3*y, 4*z
x = 3
y = 4
z = 5
x, y, z = foo_bar(x, y, z)
print(y) # prints 12
Of course, you can do anything in Python, but that doesn't mean you should. In the fashion of the TV show Mythbusters, here's something that does what you're looking for
import inspect
def foo(bar):
frame = inspect.currentframe()
outer = inspect.getouterframes(frame)[1][0]
outer.f_locals[bar] = 2 * outer.f_locals[bar]
a = 15
foo("a")
print(a) # prints 30
or even worse:
import inspect
import re
def foo(bar):
# get the current call stack
my_stack = inspect.stack()
# get the outer frame object off of the stack
outer = my_stack[1][0]
# get the calling line of code; see the inspect module documentation
# only works if the call is not split across multiple lines of code
calling_line = my_stack[1][4][0]
# get this function's name
my_name = my_stack[0][3]
# do a regular expression search for the function call in traditional form
# and extract the name of the first parameter
m = re.search(my_name + "\s*\(\s*(\w+)\s*\)", calling_line)
if m:
# finally, set the variable in the outer context
outer.f_locals[m.group(1)] = 2 * outer.f_locals[m.group(1)]
else:
raise TypeError("Non-traditional function call. Why don't you just"
" give up on pass-by-reference already?")
# now this works like you would expect
a = 15
foo(a)
print(a)
# but then this doesn't work:
baz = foo_bar
baz(a) # raises TypeError
# and this *really*, disastrously doesn't work
a, b = 15, 20
foo_bar, baz = str, foo_bar
baz(b) and foo_bar(a)
print(a, b) # prints 30, 20
Please, please, please, don't do this. I only put it in here to inspire the reader to look into some of the more obscure parts of Python.
As far as I am aware, this doesn't exist in Python (although a similar thing occurs if you pass mutable objects to a function). You would do either
def test():
global x
x = 3
test()
or
def test(x):
return 3
x = test(x)
The second of these is much preferred.