class Test:
def c(self, args):
print args
def b(self, args):
args.append('d')
def a(self):
args = ['a', 'b', 'c']
self.b(args)
self.c(args)
Test().a()
Why doesn't this print ['a', 'b', 'c']?
When you pass a list to a function, you're really passing it a pointer to the list and not a copy of the list. So b is appending a value to the original args, not its own local copy of it.
The parameter you pass to methods b and c is a reference to the list args, not a copy of it. In method b, you append to the same list you created in method a.
See this answer for a more detailed explanation on parameter passing in Python.
Related
I'm trying to call a function defined outside of class scope in Python, and it modifies the passed value, without any references to the passed variable, but somehow the original variable in class scope gets modified.
I have used python extensively for scriting but haven't really done much with Classes. I looked at this post, which explains a lot but doesn't really talk about it. This variable is surely out of scope, how's it getting mutated?
def doSomethingOutOfScope(arr):
spv = arr[0]
arr[0] = 'S'
class Solution:
def doSomethingInScope(self, passed_arr):
print(passed_arr) # prints [0, 1, 2]
doSomethingOutOfScope(passed_arr) # passed_arr shouldn't get modified
print(passed_arr) # prints ['S', 1, 2] - Why ?
s = Solution()
s.doSomethingInScope([0, 1, 2])
In Python, everything is an object and every object is passed in reference. Therefore basically any changes you directly made on the passed object besides reassigning is always reflected on the object itself in real time. The key thing to note is the mutability of the object, i.e. whether the object is mutable pass its initial assignment.
For example, str and int objects are immutable. Note there are never any methods under str and int that changes the object directly:
s = 'foo' # str type
s.upper() # FOO
print(s)
# foo
Note how str.upper() method doesn't change s itself. in order to make s into "FOO", you need to reassign s:
s = s.upper()
print(s)
# FOO
However by reassigning the object (obj = ...) it changes the object reference, where id(s) will now be different. So if a str was passed like this:
def func(string):
string = string.upper()
func(s)
s will remain unchanged because at the point of reassignment string = ..., string will no longer have the same object reference of s.
However, with mutable objects, as long as you don't reassign, the object itself will take the changes:
l = list('abcde')
def func(lst, value):
lst.append(value)
# no reassignment
func(l, 'f')
print(l)
# ['a', 'b', 'c', 'd', 'e', 'f']
That is because the object reference (id(l)) remains the same within the function.
All that said, in your case, if you wanted to do something with the object but not mutate it, you want to either pass a copy of the object (which will have a different id), or create a copy of the passed object in the local scope:
# pass a copy of the object:
def func(lst):
lst.append('x')
return lst
func(lst[:])
# OR, create a local object
def out_of_scope(lst):
temp_lst = lst[:]
temp_lst.append('x')
return temp_lst
In this particular case, [:] returns a full slice of the list as a different object.
For a bit more information, here's a relevant read.
Pythons list are actually mutable and are passed by reference
I am a student who is new to python. I am trying to define an array class below which uses a dictionary as its only member variable. I am assuming that Python implements dictionaries as the only structured type (i.e., there is no array, list, tuple, etc.).
I am facing difficulty in coding such a program.
This is my code:
class array(object):
def __init__(self):
self.dic={}
def __init__(self,diction):
self.dic = {}
for x in diction:
self.dic.append(x)
def __setitem__(self,key,value):
self.dic[key]=value
def __getitem__(self,key):
if key not in self.dic.keys():
raise KeyError
return self.dic[key]
I want the program to work this way:
a = array('a','b','c') #------output------
print(a) # ['a', 'b', 'c']
print(a[1]) # b
a[1] = 'bee'
print(a) # ['a', 'bee', 'c']
a[3] = 'day'
print(a) # ['a', 'bee', 'c', 'day']
print(a[6]) # IndexError exception
Any suggestions, advice. :)
There are quite a few issues with your class definition:
array is already a data structure: better to rename using the proper Python class-naming conventions (MyClass).
You cannot overload function definitions: better to use an unpacking operator (*) to extract all (if any) arguments.
You cannot append to a dictionary: you need to assign to a key.
Your call to print will display a generic class name, since you don't specify a __str__ magic method. Since a dict is unordered, I did some funny business here to make it display as sorted, though I'm sure there's a better way.
No need to raise a KeyError in __getitem__, since this will be raised anyway.
Finally, I corrected your spacing.
Note that I've only implemented the methods necessary to make your test cases work.
class MyArray(object):
def __init__(self, *diction):
self.dic = {}
for i, x in enumerate(diction):
self.dic[i] = x
def __setitem__(self, key, value):
self.dic[key] = value
def __getitem__(self, key):
return self.dic[key]
def __str__(self):
return str([self.dic[i] for i in sorted(self.dic.keys())])
Let's say there's a function in a Python library (let's call it mymodule):
def some_func(a,b='myDefaultValue'):
return some_computation
and then there's another function in another module that calls it,
import mymodule
def wrapper(a,b):
return some_transform(mymodule.some_func(a,b))
How do I make it such that wrapper inherits some_func's default value for the b parameter? I could do something like:
def wrapper(a,b=None):
if b:
return some_transform(some_func(a,b))
else:
return some_transform(some_func(a))
but that seems needlessly cumbersome, leads to a combinatorial explosion of possibilities with multiple optional arguments, and makes it so I can't explicitly pass in None to wrapper.
Is there a way of getting the default args for a function, or is common practice to simply pull that value out into a shared constant that both function declarations can make use of?
You can use func_defaults:
https://docs.python.org/2/library/inspect.html?highlight=func_defaults#types-and-members
func_defaults tuple of any default values for arguments
def some_func(a,b='myDefaultValue'):
print a, b
def wrapper(a,b):
b = some_func.func_defaults[0] if b is None else b
some_func(a,b)
print "b is 'there'"
a = "hello"
b = "there"
wrapper(a,b)
print "b is 'None'"
b = None
wrapper(a,b)
output:
b is 'there'
hello there
b is 'None'
hello myDefaultValue
EDIT: To answer your question from the comments, there isn't anything built-in to look up the arguments of the function with default values by name. However, you know that the arguments with default values have to come after the non-optional arguments. So if you know the total number of arguments you have, and how many of them have default values, you can subtract the 2 to get the starting point of the arguments with default values. Then you can zip the list of arguments (starting at the previously calculated argument index) together with the list of default argument values and create a dictionary from the list. Use the inspect module to get all of the information you need:
Like so:
>>> import inspect
>>> def some_func(a,b,c,d="dee",e="ee"):
... print a,b,c,d,e
...
>>> some_func("aaa","bbb","ccc",e="EEE")
aaa bbb ccc dee EEE
>>> some_funcspec = inspect.getargspec(some_func)
>>> some_funcspec
ArgSpec(args=['a', 'b', 'c', 'd', 'e'], varargs=None, keywords=None, defaults=('dee', 'ee'))
>>> defargsstartindex = len(some_funcspec.args) - len(some_funcspec.defaults)
>>> defargsstartindex
3
>>> namedargsdict = dict(zip([key for key in some_funcspec.args[defargsstartindex:]], list(some_funcspec.defaults)))
>>> namedargsdict
{'e': 'ee', 'd': 'dee'}
In the example above, namedargsdict is your list of arguments with default values for some_func.
Further reading:
https://docs.python.org/2/library/inspect.html#inspect.getargspec
inspect.getargspec(func) Get the names and default values of a Python
function’s arguments. A tuple of four things is returned: (args,
varargs, keywords, defaults). args is a list of the argument names (it
may contain nested lists). varargs and keywords are the names of the *
and ** arguments or None. defaults is a tuple of default argument
values or None if there are no default arguments; if this tuple has n
elements, they correspond to the last n elements listed in args.
Changed in version 2.6: Returns a named tuple ArgSpec(args, varargs,
keywords, defaults).
You can use argument unpacking to accomplish this:
In [1]: def some_func(a,b='myDefaultValue'):
...: print a, b
...:
In [2]: def wrapper(a, *args, **kwargs):
...: some_func(a, *args, **kwargs)
...:
In [3]: some_func('foo', 'bar')
foo bar
In [4]: some_func('baz')
baz myDefaultValue
In [5]: wrapper('foo', 'bar')
foo bar
In [6]: wrapper('baz')
baz myDefaultValue
If you plan to wrap multiple functions in this way, you might consider making wrapper a decorator:
In [1]: from functools import wraps
In [2]: def wrapper(func):
...: #wraps(func)
...: def decorated(a, *args, **kwargs):
...: print 'wrapper invoked with a = {}'.format(a)
...: return func(a, *args, **kwargs)
...: return decorated
...:
In [3]: #wrapper
...: def some_func(a, b='myDefaultValue'):
...: print a, b
...:
In [4]: some_func('foo', 'bar')
wrapper invoked with a = foo
foo bar
In [5]: some_func('baz')
wrapper invoked with a = baz
baz myDefaultValue
Your question is not clear enough. But as far as I understand from your question, you should use class so that you can easily share values among multiple functions inside the class
class SomeClass:
def __init__(self, b='defaultvalue'):
self.b = b
def some_func(self, a, b):
pass
def wrapper(self, a):
self.some_func(a, self.b)
I am trying to make my function return items in a list one by one each time the function is called. I have this code:
def abc():
ls = ['a', 'b', 'c']
for i in ls:
ls.append(i)
yield i
I can type something like this on the terminal and keep pressing next() to get the next item in the list.
>>>ab = abc()
>>>next(ab)
'a'
>>>next(ab)
'b'
>>>next(ab)
'c'
>>>next(ab)
'a'
>>>next(ab)
'b'
And it should go on forever every time next is called. Instead of repeatedly typing next(ab) in the terminal, I want to make my function do all that (return the next item in the list) every time the function abc() is called.
Basically you're looking for a closure function:
def func():
seq = ['a', 'b', 'c']
ind = [-1]
def inner():
ind[0] += 1
return seq[ind[0]%len(seq)]
return inner
>>> f = func() # One call is still required after that the
# returned inner function can maintain the state.
>>> f()
'a'
>>> f()
'b'
>>> f()
'c'
>>> f()
'a'
In Python 3 instead of defining ind as a list we can use nonlocal keyword.
Or using itertools.cycle:
from itertools import cycle
def func(seq):
return cycle(seq).next
...
>>> f = func('abc')
>>> f()
'a'
>>> f()
'b'
>>> f()
'c'
>>> f()
'a'
>>> f()
'b'
You need a queue.
Every time a function call happens
x=[1,2,3]
k= x.pop(0)
x.append(k)
return k
This will get you the desired behavior.
EDIT:
ls = ['a', 'b', 'c']
def abc():
k= ls.pop(0)
ls.append(k)
return k
print abc()
print abc()
print abc()
print abc()
print abc()
The function you have uses increasing amounts of memory because it appends to the list for each iteration. An improvement is to maintain an index:
def abc():
ls = ['a', 'b', 'c']
i = 0;
while True:
yield ls[i]
i = (i+1) % len(ls)
What you have is exactly what you need. It is a generator. Normally you would not call next() directly. Normally you would use a loop to process the values produced by your generator:
for thing in abc():
print(thing)
Since your generator never throws a StopIteration exception, the for loop will never end.
This calls for creating a higher order function that will use closure to create a secondary function to do what you want.
def create_wrapper(func):
iter = func()
def wrapper():
return next(iter)
return wrapper
ab = create_wrapper(abc)
ab()
>>> 'a'
ab()
>>> 'b'
And so on.
Here is a quick intro to higher order functions and closures in the context of the above code -
In the above code, func is actually a function reference, note how we call create_wrapper(abc) without the parens after abc, so it is not actually executing abc(). Then we create an iter object and create a child function called wrapper. We refer to the iter object in the child function even though it is defined in the parent function. This usage is called closure. When we return the function reference to wrapper, create_wrapper goes out of scope and so should any variables used inside it - including iter. But because it is being referenced in the child function, which lives on beyond its parent, iter is preserved.
BTW - the way you create an infinite iterator by appending to the list is pretty clever :-) but it obviously runs the danger of a memory overflow. There are other ways to create infinite iterators. Check out https://docs.python.org/3/library/itertools.html.
class test:
def __init__(self, val):
self.val = val
self.val.lower()
Why doesn't lower() operate on the contents of val in this code?
You probably mean:
self.val = self.val.lower()
Or, more concisely:
class test:
def __init__(self, val):
self.val = val.lower()
To elaborate, lower() doesn't modify the string in place (it can't, since strings are immutable). Instead, it returns a copy of the string, appropriately modified.
The documentation states it pretty clearly:
Return a copy of the string with all the cased characters [4] converted to lowercase.
It is because strings are immutable. You cannot change them in-place.
Thus, you must overwrite the value of the variable like that:
self.val = self.val.lower()
Note: Unless, of course, your self.val is not a string, but rather some mutable object that is changed in-place after calling lower() method. But this is not the case (you can make it the case if you have created the class of self.val, though).
Example of mutable object with lower() method changing it in-place:
>>> class LowerableList(list):
def lower(self):
for i, item in enumerate(self):
self[i] = item.lower()
>>> a = LowerableList(['A', 'a', 'X', 'D'])
>>> a
['A', 'a', 'X', 'D']
>>> a.lower()
>>> a
['a', 'a', 'x', 'd']
Does it help?
In Python there are 2 types of function that leads to this kind of confusion. For example to sort a list you could do:
>>> a.sort()
or
>>> a = sorted(a)
first one sorts in "a", but second sorts "a" and returns new sorted list.