What does the obj=lists[0] do in the following code?
lists = []
infile = open(path, 'rb')
while True:
try:
lists.append(pickle.load(infile))
except EOFError:
break
obj=lists[0]
while len(lists) > 3:
lists.pop(0)
print(lists)
infile.close()
I have tried to understand it but I cannot seem to see any reason for it.
Nothing.
obj is never referred to after its initial assignment, so it has no effect on anything.
The only possible way I could see that line doing anything, is if lists was some strange class whose __getitem__ call has a side effect. For example,
class StrangeList(list):
def __getitem__(self, idx):
self[idx] = 23
return 23
def a():
x = StrangeList([1,2,3])
print x
def b():
x = StrangeList([1,2,3])
obj = x[0]
print x
print "Calling a"
a()
print "Calling b"
b()
Result
Calling a
[1, 2, 3]
Calling b
[23, 2, 3]
Here, doing obj = x[0] does do something, even though obj is never used. But this is a contrived example; for your current code and for 99.9% of the classes you're likely to use in the future, __getitem__ won't behave this way.
Assuming this is all the code there is, there is no use for it and, as #Daniel Roseman mentioned, it must be a left over from some refactoring.
If there is more code in your program, I would suggest that the variable obj is being used to preserve the first value of the list. The loop below it consumes all elements in the list (except the last three), so if you are going to need the original first object in the list, you need to preserve it - hence, the obj attribution.
Related
This question already has answers here:
What is the purpose of the return statement? How is it different from printing?
(15 answers)
Closed 8 months ago.
In my previous question, Andrew Jaffe writes:
In addition to all of the other hints and tips, I think you're missing something crucial: your functions actually need to return something.
When you create autoparts() or splittext(), the idea is that this will be a function that you can call, and it can (and should) give something back.
Once you figure out the output that you want your function to have, you need to put it in a return statement.
def autoparts():
parts_dict = {}
list_of_parts = open('list_of_parts.txt', 'r')
for line in list_of_parts:
k, v = line.split()
parts_dict[k] = v
print(parts_dict)
>>> autoparts()
{'part A': 1, 'part B': 2, ...}
This function creates a dictionary, but it does not return something. However, since I added the print, the output of the function is shown when I run the function. What is the difference between returning something and printing it?
print simply prints out the structure to your output device (normally the console). Nothing more. To return it from your function, you would do:
def autoparts():
parts_dict = {}
list_of_parts = open('list_of_parts.txt', 'r')
for line in list_of_parts:
k, v = line.split()
parts_dict[k] = v
return parts_dict
Why return? Well if you don't, that dictionary dies (gets garbage collected) and is no longer accessible as soon as this function call ends. If you return the value, you can do other stuff with it. Such as:
my_auto_parts = autoparts()
print(my_auto_parts['engine'])
See what happened? autoparts() was called and it returned the parts_dict and we stored it into the my_auto_parts variable. Now we can use this variable to access the dictionary object and it continues to live even though the function call is over. We then printed out the object in the dictionary with the key 'engine'.
For a good tutorial, check out dive into python. It's free and very easy to follow.
The print statement will output an object to the user. A return statement will allow assigning the dictionary to a variable once the function is finished.
>>> def foo():
... print "Hello, world!"
...
>>> a = foo()
Hello, world!
>>> a
>>> def foo():
... return "Hello, world!"
...
>>> a = foo()
>>> a
'Hello, world!'
Or in the context of returning a dictionary:
>>> def foo():
... print {'a' : 1, 'b' : 2}
...
>>> a = foo()
{'a': 1, 'b': 2}
>>> a
>>> def foo():
... return {'a' : 1, 'b' : 2}
...
>>> a = foo()
>>> a
{'a': 1, 'b': 2}
(The statements where nothing is printed out after a line is executed means the last statement returned None)
I think you're confused because you're running from the REPL, which automatically prints out the value returned when you call a function. In that case, you do get identical output whether you have a function that creates a value, prints it, and throws it away, or you have a function that creates a value and returns it, letting the REPL print it.
However, these are very much not the same thing, as you will realize when you call autoparts with another function that wants to do something with the value that autoparts creates.
you just add a return statement...
def autoparts():
parts_dict={}
list_of_parts = open('list_of_parts.txt', 'r')
for line in list_of_parts:
k, v = line.split()
parts_dict[k] = v
return parts_dict
printing out only prints out to the standard output (screen) of the application. You can also return multiple things by separating them with commas:
return parts_dict, list_of_parts
to use it:
test_dict = {}
test_dict = autoparts()
Major difference:
Calling print will immediately make your program write out text for you to see. Use print when you want to show a value to a human.
return is a keyword. When a return statement is reached, Python will stop the execution of the current function, sending a value out to where the function was called. Use return when you want to send a value from one point in your code to another.
Using return changes the flow of the program. Using print does not.
A function is, at a basic level, a block of code that can executed, not when written, but when called. So let's say I have the following piece of code, which is a simple multiplication function:
def multiply(x,y):
return x * y
So if I called the function with multiply(2,3), it would return the value 6. If I modified the function so it looks like this:
def multiply(x,y):
print(x*y)
return x*y
...then the output is as you would expect, the number 6 printed. However, the difference between these two statements is that print merely shows something on the console, but return "gives something back" to whatever called it, which is often a variable. The variable is then assigned the value of the return statement in the function that it called. Here is an example in the python shell:
>>> def multiply(x,y):
return x*y
>>> multiply(2,3) #no variable assignment
6
>>> answer = multiply(2,3) #answer = whatever the function returns
>>> answer
6
So now the function has returned the result of calling the function to the place where it was called from, which is a variable called 'answer' in this case.
This does much more than simply printing the result, because you can then access it again. Here is an example of the function using return statements:
>>> x = int(input("Enter a number: "))
Enter a number: 5
>>> y = int(input("Enter another number: "))
Enter another number: 6
>>> answer = multiply(x,y)
>>> print("Your answer is {}".format(answer)
Your answer is 30
So it basically stores the result of calling a function in a variable.
def add(x, y):
return x+y
That way it can then become a variable.
sum = add(3, 5)
print(sum)
But if the 'add' function print the output 'sum' would then be None as action would have already taken place after it being assigned.
Unfortunately, there is a character limit so this will be in many parts. First thing to note is that return and print are statements, not functions, but that is just semantics.
I’ll start with a basic explanation. print just shows the human user a string representing what is going on inside the computer. The computer cannot make use of that printing. return is how a function gives back a value. This value is often unseen by the human user, but it can be used by the computer in further functions.
On a more expansive note, print will not in any way affect a function. It is simply there for the human user’s benefit. It is very useful for understanding how a program works and can be used in debugging to check various values in a program without interrupting the program.
return is the main way that a function returns a value. All functions will return a value, and if there is no return statement (or yield but don’t worry about that yet), it will return None. The value that is returned by a function can then be further used as an argument passed to another function, stored as a variable, or just printed for the benefit of the human user.
Consider these two programs:
def function_that_prints():
print "I printed"
def function_that_returns():
return "I returned"
f1 = function_that_prints()
f2 = function_that_returns()
print "Now let us see what the values of f1 and f2 are"
print f1 --->None
print f2---->"I returned"
When function_that_prints ran, it automatically printed to the console "I printed". However, the value stored in f1 is None because that function had no return statement.
When function_that_returns ran, it did not print anything to the console. However, it did return a value, and that value was stored in f2. When we printed f2 at the end of the code, we saw "I returned"
The below examples might help understand:
def add_nums1(x,y):
print(x+y)
def add_nums2(x,y):
return x+y
#----Function output is usable for further processing
add_nums2(10,20)/2
15.0
#----Function output can't be used further (gives TypeError)
add_nums1(10,20)/2
30
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-124-e11302d7195e> in <module>
----> 1 add_nums1(10,20)/2
TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'
I want to make a function that takes makes a list and adds an item to that list when I run it, so basically I would be passing this function two arguments, the first is the name I want the list to have, the second is an item I want to add to the list.
I want to do this as a learning excercise and I've built a function that almost does what I want it to do.
def addlst(l, item):
"""add an item to a list"""
l = list()#this line essentially does nothing.
if type(item) == str:
l.append(item.capitalize())
return l
print(l)
else:
l.append(item)
return l
print(l)
if I pass this something like:
addlst(people, 'kev')
I get the error:
NameError: name 'people' is not defined
but obviously, if I define people as an empty list it works fine.
Is what I'm doing actually possible? I know that as it stands the line
l = list()
would just empty the list first and so the append function would be useless (I'd have to add another clause to check if the list exists already) but my question is really about initialising a blank list within a function and then returning it to the global scope.
Putting aside the discussion regarding whether it is a good practice, (which can make sens if your main goal is about improving your understanding), you could simply use the global keyword to do what you describe. Say
def f(el):
global l
l.append(el)
Then
>>> l = []
>>> f(2)
>>> l
[2]
>>> f(3)
>>> l
[2, 3]
As it reads above, l has to be declared before using f.
Dealing with your peculiarities, something you could do is:
def addlst(item):
"""add an item to a list"""
global l#
if isinstance(item, str): # type(item) == str is not recommanded
item = item.capitalize()
l.append(item)
But actually, note that doing so will "bind" your function to deal exclusively with the list named l in the global scope. And it looks like this is not what you want, since it appears that you want to be able to pass multiple list objects to your function. The best approach here is
def addlst(list_, item):
"""add an item to a list"""
if isinstance(item, str):
item = item.capitalize()
list_.append(item)
return list_
First off: a function should never inject a new name into the calling scope.
If the function works with a global variable, that needs to be documented and the caller has to ensure the global exists before calling it.
If the function takes an argument, there are two options. One, you can mutate it and have your function return None, or you can create a new value based on the argument and return that, leaving the argument unchanged. Very rarely, if ever, should your function modify an argument and return a value.
If you have your function return a new list, you can optionally take a list to modify, or create a brand new list inside your function.
Unrelated, but you shouldn't care what the type of item is, only that it is something that has a capitalize method that you can call. Just try it; if it doesn't, it will raise an AttributeError that you can catch, in which case you can simply use item as is.
Putting all this together, I recommend the third approach. add_to_list will take an item as the first argument, and an optional list as the second argument. If no list is given, the function will create a new list. In either case, you'll append the appropriately modified item to the list and return it.
def add_to_list(item, l=None):
# Note: this doesn't change the item you pass; it just rebinds
# the local name item to a *new* string if it succeeds.
try:
item = item.capitalize()
except AttributeError:
pass
if l is None:
l = []
return l + [item]
Then you can use
people = add_to_list('kev') # people == ['Kev']
people = add_to_list('bob') # people == ['Bob'], Kev is gone!
people = add_to_list('kev', people) # people == ['Bob', 'Kev'], Kev is back.
The more efficient version mentioned in the second approach modifies l in place; in this case, though, you have to provide a list; you can't create a new list.
def add_to_list(item, l):
try:
item = item.capitalize()
except AttributeError:
pass
l.append(item)
people = [] # Create the list in the *calling* scope, not in add_to_list
add_to_list('kev') # TypeError, missing an argument
add_to_list('kev', people) # people == ['Kev']
add_to_list('bob', people) # people == ['Kev', 'Bob']
The first approach is pretty poor; it restricts your function to working with a specific list whose name is hard-coded in the function, but I'll mention it here for completeness. Since the list is hard-coded, we'll change the name of the function to reflect that.
def add_to_people(item):
global people
try:
item = item.capitalize()
except AttributeError:
pass
people.append(item)
Now add_to_list can work with the global list people, but no other list.
people = []
add_to_people('kev')
add_to_people('bob')
And finally, in the interest of full disclosure, yes, add_to_people can create the list if it hasn't already:
def add_to_people(item):
global people
try:
people # Simply try to evaluate the name
except NameError:
people = []
# ...
However, if using a global name in the first place is bad, autovivifying it like this is worse. Avoid this style of programming wherever possible.
When you write addlst(people, 'kev'), you're telling your code that you want to execute the addlst function with a variable named people as first parameter.
Problem is: you never set this variable!
There are many ways to this; You could either initialize an empty list before calling the function:
people = []
addlst(people, 'kev')
Or make the parameter optional with a default value:
def addlst(item, l = None):
"""add an item to a list"""
if l is None:
l = []
if type(item) == str:
l.append(item.capitalize())
return l
else:
l.append(item)
return l
But that could be tricky, since lists are mutable objects.
NB: In your function, print will never be called because it stands after the return statement.
A last way
Eventually, you could also shorten your code by doing something like that:
mylist = []
item = "test"
mylist.append(item.capitalize() if type(item) == str else item)
This question already has answers here:
How do I get a result (output) from a function? How can I use the result later?
(4 answers)
Python difference between mutating and re-assigning a list ( _list = and _list[:] = )
(3 answers)
Closed 6 months ago.
I created a function and I want to append a number to the list:
def num(f):
list1.append(i)
return list1
list1 = []
i = 1
print "Now list1 is %s and i is %d" % (list1, i)
num(list1)
i += 1
print "Now list1 is %s and i is %d" % (list1, i)
num(list1)
i += 1
print "Now list1 is %s and i is %d" % (list1, i)
print list1
print i
Why do I have to return a function? It works with and without the return.
I was told that the function returns None if no return-statement was reached. But the function, mentioned above, works even if I don't type this return-statement.
I see you don't understand how functions work, so I added comments to your code to explain a little, but I suggest you to read Python tutorial about functions and wiki article further to gain understanding.
Also, I omitted many details not to overload the explanation. Important thing is there're immutable (i.e. integer, i in your example) and mutable (i.e. list, list1 in your example) types in Python and depending on this the behavior will be different.
def num(f):
#Here the argument you pass to the function is named 'f'
#and you don't use it
#The next line uses 'list1', that is defined in global scope
#since you didn't redefined this name inside the function
#Variable 'i' is also the one in global scope for same reasons
list1.append(i)
#Here you return 'list1', though you don't use this value
#further in your program. Indeed, you would not write a return
#statement the function would return 'None' as the return value
return list1
#Here you define 'list1' in global scope, and it will be used
#inside 'num' function, even without providing it as the argument
list1 = []
#Here you define 'i' in global scope, and it will be used
#inside 'num' function
i = 1
#Here you print 'i' and 'list' from global scope
print "Now list1 is %s and i is %d" % (list1, i)
#Here you call 'num' function and 'list1' provided as argument
#is assigned to 'f' inside the function, but you didn't used it and
#and instead used names from global scope - that's why it works in
#this way (however it is wrong use of function)
#With 'list1.append(i)' the 'list1' is modified in place so it
#doesn't matter if it is returned or not
num(list1)
#As to 'num' return value, it will be the same value as 'list1', but
#you don't use it here, to use it it needs to be assigned with '=' to
#some variable, i.e. 'list2=num(list1)', though in fact 'list1' and 'list2'
#will be the same all the time due to Python internals, but let's skip the
#details of this.
#You can see that the value returned is not 'None' - add the
#following line here:
print(num(list1))
#and run your program, the output will show you that it's a list returned.
#then remove the 'return' line in your function and run program again
#the output here will show, that is's 'None' that was returned.
So to fix the obvious mistake in the function:
def num(f):
f.append(i)
return f
but i is still used from global scope and not passed as argument, so even better:
def num(f_var,i_var):
f_var.append(i_var)
return f_var
Though the list will be modified inplace and you don't really have to return it
in you particular example, so:
def num(f_var,i_var):
f_var.append(i_var)
list1=[]
i=1
num(list1,i)
will work too.
In the provided example, returning a value is unnecessary because the append list method, and by extension your function as well, operates by side effect. Functions called only for side effects are not functions in the mathematical sense (mappings of domain values to codomain values), they serve to change state of mutable objects, in this case by appending an item to a list. While such functions can return a value, Python has a convention that functions invoked purely for side effect, such as list.append, only return None, denoting no useful return value.
If your function were side-effect-free, you would need to have a return statement for it to be useful at all. As an example, compare:
def add(a, b):
return a + b
...with the syntactically just as legal, but pretty useless:
def add(a, b):
a + b
# without a return statement, None is returned,
# and the calculated sum discarded
You don't use the return value, so it makes no difference, what you return. You also don't use the argument. You probably wanted to write
def append_num(f, i):
f.append(i)
and use two arguments:
append_num(list1, i)
I'm looking over someone else's code trying to learn from them and I have a question on something they've done.
This is line 16 from the link
self.sentence = sentence or ""
What does or in the assignment operator do?
I've tried running this myself and if sentence is defined then the it's assigned to self.sentence, otherwise if it's not assigned I get a NameError exception.
https://github.com/xavier/exercism-assignments/blob/master/python/bob/bob.py
or is a lazy operator, and returns first value, which is 'trueish' (bool(value) is True). This idiom is used, to assign a value, or if it is empty, something else.
In this case, probably it guards against assigning None, which evaluates to False, but author wanted to be sure, that be always a string will be assigned - and empty string in this case.
In the sample code, this would make more sense if __init__() had a default argument:
class Fake:
def __init__(self, sentence=None):
self.sentence = sentence or '<empty>'
def print_me(self):
print(self.sentence)
a = Fake('A real sentence')
b = Fake()
a.print_me()
b.print_me()
outputs:
paul#local:~/src/sandbox$ ./def.py
A real sentence
<empty>
paul#local:~/src/sandbox$
In this particular case, def __init__(self, sentence='<empty>'): followed by self.sentence = sentence would have done equally well, but this could be more useful when dealing with mutable objects such as lists, since def __init__(self, sentence=[]): will evaluate only once, and all the classes would refer to the same default list. Specifying None as the default value instead, and creating a separate empty list in __init__() would avoid this behavior.
For instance:
#!/usr/bin/env python
class Weird:
def __init__(self, the_list=[]): # <--- Don't do this
self.the_list = the_list
def append(self, value):
self.the_list.append(value)
def print_me(self):
print(self.the_list)
class Normal:
def __init__(self, the_list=None):
self.the_list = the_list or []
def append(self, value):
self.the_list.append(value)
def print_me(self):
print(self.the_list)
print("Weird output:")
a = Weird()
b = Weird()
a.append(1)
a.append(2)
a.print_me()
b.print_me()
print("Normal output:")
c = Normal()
d = Normal()
c.append(1)
c.append(2)
c.print_me()
d.print_me()
outputs:
paul#local:~/src/sandbox$ ./def2.py
Weird output:
[1, 2]
[1, 2]
Normal output:
[1, 2]
[]
paul#local:~/src/sandbox$
In the first case, you might expect each object to get its own empty list, but you can see when you append things to a, they get appended to b also, because a and b are sharing the same list. This is not happening in the second case, because we specified the default as None rather than [], and then used the idiom in your question. When the_list is None, the_list or [] will evaluate to []. When it's not, it'll just evaluate to the_list. It's equivalent to:
if sentence:
self.sentence = sentence
else:
self.sentence = ""
I want to find the name of the function as it was called ... i.e. the name of the variable that called the function. Using the basic recipes i.e. with __name__, func_name, or inspecting the basic stack does not work for me. For example
def somefunc():
print "My name is: %s" % inspect.stack()[1][3]
a = somefunc
a()
# would output: out: "My name is: somefunc"
# whereas I want it to output: "My name is: a"
My gut says I can do this, but I can't figure it out. Any python guru's out there?
It's probably impossible to do this 100% correctly, but you could give the following a try:
import inspect
import parser
# this flatten function is by mike c fletcher
def flatten(l, ltypes=(list, tuple)):
ltype = type(l)
l = list(l)
i = 0
while i < len(l):
while isinstance(l[i], ltypes):
if not l[i]:
l.pop(i)
i -= 1
break
else:
l[i:i + 1] = l[i]
i += 1
return ltype(l)
# function we're interested in
def a():
current_func = eval(inspect.stack()[0][3])
last_frame = inspect.stack()[1]
calling_code = last_frame[4][0]
syntax_tree = parser.expr(calling_code)
syntax_tree_tuple = parser.st2tuple(syntax_tree)
flat_syntax_tree_tuple = flatten(syntax_tree_tuple)
list_of_strings = filter(lambda s: type(s)==str,flat_syntax_tree_tuple)
list_of_valid_strings = []
for string in list_of_strings:
try:
st = parser.expr(string)
list_of_valid_strings.append(string)
except:
pass
list_of_candidates = filter(lambda s: eval(s)==current_func, list_of_valid_strings)
print list_of_candidates
# other function
def c():
pass
a()
b=a
a(),b(),c()
a(),c()
c(),b()
This will print:
['a']
['a', 'b']
['a', 'b']
['a']
['b']
It's pretty ugly and complicated, but might work for what you need. It works by finding all variables used in the line that called this function and comparing them to the current function.
The problem here is indirection. You could probably do something complicated like inspect the stack, get the code for the module that called the function, parse the line number from the stack to find the label used to call the function in the local context, and then use that, but that won't necessarily give you what you want anyway. Consider:
def func(x):
print get_label_function_called_with()
def func_wrapper(func_in_func_wrapper):
return func_in_func_wrapper
func_label = func
func_from_func_wrapper = func_wrapper(func_label)
func_from_func_wrapper()
Should this print func, func_in_func_wrapper, func_label, or func_from_func_wrapper? It might seem like an obvious answer at first, but given that you never really know what sort of indirection is going on inside code you are calling, you really can't know for sure.