Basic use of functions in python - python

I'm trying to learn Python 3. This is an example I am trying to learn from. So here I define a function to read text. Open a file, read the contents, print it, then close.
So this code runs well. The thing I don't understand, however, is why we write:
print(contents_of_file), but not read(quotes). How come it's quotes.read()? As far I can understand both print() and read() are functions and I expected both to be used the same way. What am I missing here - please help?
Is there a rule when to put stuff inside brackets and when not to?
def read_text():
quotes = open("/Users/me/text.txt", encoding = "utf-8")
contents_of_file = quotes.read()
print(contents_of_file)
quotes.close()
read_text()

print() is a function. read() is a method of the object bound to quotes. As such, read must be referred to by accessing quotes. Only then can we add parens to invoke it.

You've stumbled across the often argued definitions of functions and methods.
read() is a method that belongs to quotes (which is an instance of a class, I don't actually know the name of which). Technically, Methods belong to Objects, Functions are normally defined in a style that isn't strictly Object Orientated, or in global scope (like all C functions).
It might be worth reading up on the OOP aspects of Python, this will likely help you understand it more.

quotes is a file object. I understand you don't yet know what is an object. But try printing quotes.
print type(quotes)
This object has a function read() whose purpose is to read contents from the file.
To call a function of an object, you have to write:
object.funcName()
As this is exactly what we want, we are just calling that function. So we are writing:
quotes.read()
print doesn't belongs to any of these type of objects. So, we can call it without any object reference.

Related

How can I avoid retyping long variable names in calling functions

How can I avoid lines like:
this_long_variable_name = this_long_variable_name.replace('a', 'b')
I thought I could avoid it by making a function, repl,
def repl(myfind, myreplace, s):
s = s.replace(myfind, myreplace)
print(s) # for testing purposes
return s
but because of stuff about the local vs. global namespaces that I don't understand, I can't get the function to return a changed value for this_long_variable_name. Here's what I've tried:
this_long_variable_name = 'abbbc'
repl('b', 'x', this_long_variable_name)
print('after call to repl, this_long_variable_name =', this_long_variable_name)
The internal print statement shows the expected: axxxc
The print statement after the call to repl show the unchanged: abbbbc
Of course, it works if I give up and accept the redundant typing:
this_long_variable_name = repl('b', 'x', this_long_variable_name)
BTW, it's not just about the length of what has to be retyped, even if the variable's name were 'a,' I would not like retyping a = a.replace(...)
Since in the function s is a parameter, I can't do:
global s
I even tried:
this_long_variable_name.repl('b', 'x')
which shows you both how little I understand and how desperate I am.
The issue you're running into is that Python strings are immutable. str.replace() returns an entirely new string, so in s = s.replace(myfind, myreplace), the name s no longer refers to the original string, which is why you don't see any change on the outside of the function's namespace.
There probably isn't a great solution to your problem. I recommend using a modern IDE or Python REPL with autocompletion to alleviate it. Trying to abuse the standard way of writing things like this may feel good to you, but it will confuse anyone else looking at your code.
Harry it does not work because inside your repl function you actually have a local copy of the content of your this_long_variable_name. This is called "pass by copy" which means python hands over a copy to the function. Unfortunately this is how python does it. Check also here:
Python: How do I pass a string by reference?
Also strings are immutable in python so if you wanna change them you always create a new modified version. Check here:
Aren't Python strings immutable?
Question would be why should you need long variable names in the first place?

CSV Parsing, trying to understand some code

Here's the code
import csv
def csv_dict_reader(file_obj):
"""
read a CSV file using csv.DictReader
"""
reader = csv.DictReader(file_obj, delimiter=',')
for line in reader:
print(line['first_name']),
print(line['last_name']),
if __name__== "__main__":
with open("dummy.csv") as f_obj:
csv_dict_reader(f_obj)
I wanted to try and do a quick breakdown, to see if I understand how exactly this works. Here we go:
1) import csv brings in the csv method
2) We define a function, which takes 'file_obj' as its argument
3) the reader variable makes a call to a function within csv called "DictReadre", which subsequently takes arguments from 'file_obj' and specifies a 'delimiter'
4) I get confused with this for loop, why is that we don't have to define line beforehand? Is it that line is already defined as part of 'reader'?
5) I'm really confused when it comes to 'name' and 'main', are these somehow related to how we specify a 'file_obj'? I'm equally confused with how we end up specifying the 'file_obj' in the end; I've been assuming 'f_obj' somehow manages to fill this role.
--edit--
Awesome, this is starting to make a whole lot more sense to me. So, when I make a 'class' call to DictReader(), I'm creating an instance of it in the variable 'reader'?
Maybe I'm going too far off the beaten path, but what in the DictReader() class allows for it to determine the structure of fields like 'last_name' or 'first_name'? I'm assuming it has something to do with how CSV files are structures, but I'm not entirely certain.
1) import csv brings in the csv method
Well, not quite; it brings in the csv module.*
* … which includes the csv.DictReader class, which has a csv.DictReader.__next__ method that you call implicitly, but that's not important here.
2) We define a function, which takes 'file_obj' as its argument
Exactly.*
* Technically, there's a distinction between arguments and parameters, or between actual vs. formal arguments/parameters. You probably don't want to learn that yet. But if you do, formal parameters go in function definitions; actual arguments go in function calls.
3) the reader variable makes a call to a function within csv called "DictReadre", which subsequently takes arguments from 'file_obj' and specifies a 'delimiter'
Again, not quite; it makes a call to the class DictReader. Calling a class constructs an instance of that class. Arguments are passed the same way as in a function call.* You can see the parameters that DictReader takes by looking it up in the help.
* In fact, constructing a class actually calls the class's __new__ method, and then (usually) its __init__ method. But that's only important when you're writing new classes; when you're just using classes, you don't care about __new__ or __init__. That's why the documentation shows, e.g., class csv.DictReader(csvfile, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds).
4) I get confused with this for loop, why is that we don't have to define line beforehand? Is it that line is already defined as part of 'reader'?
No, that's exactly what for statements do: each time through the loop, line gets assigned to the next value in reader. The tutorial explains in more detail.
A simpler example may help:
for a in [1, 2, 3]:
print(a)
This assigns 1 to a, prints out that 1, then assigns 2 to a, prints out that 2, then assigns 3 to a, prints out that 3, then it's done.
Also, you may be confused by other languages, which need variables to be declared before they can be used. Python doesn't do that; you can assign to any name you want anywhere you want, and if there wasn't a variable with that name, there is now.
5) I'm really confused when it comes to 'name' and 'main'
This is a special case where you have to learn something reasonably advanced a little early.
The same source code file can be used as a script, to run on the command line, and also as a module, to be imported by other code. The way you distinguish between the two is by checking __name__. If you're being run as a script, it will be '__main__'. If you're being used as a module by some other script, it will be whatever the name of your module is.
So, idiomatically, you define all your public classes and functions and constants that might be useful to someone else, then you do if __name__ == '__main__': and put all the "top-level script" code there that you want to execute if someone runs you as a script.
Again, the tutorial explains in more detail.

How to add arguments next to 'self' in a python function?

I'm trying to fix up a little program, but looks like I'm in a bit over my head. The whole code is too long to copy here, so I'm just gonna paste the problematic part.
def kontroll(self):
count=IntVar()
sisend=sisendivaartus.get()
print(count)
if count==1:
kast.delete(0.0,END)
sisend.delete(0.0,END)
count=0
else:
kast.delete(0.0,END)
if sisend=="õige" or sisend=="ÕIGE" or sisend=="Õige":
if oige==sonake:
if tahendus==" ":
kast.insert(END,"Tubli, õige!"+"\n"+str(oige)+"\n"+str(tahendus))
count=1
else:
kast.insert(END,"Tubli, õige!"+"\n"+str(oige)+"\n:"+str(tahendus))
count=1
#skoor+=1
#skoor=skoor+1
else:
if tahendus==" ":
kast.insert(END,"Kahjuks eksid. Õige on "+str(oige)+"\n"+str(tahendus))
count=1
else:
kast.insert(END,"Kahjuks eksid. Õige on "+str(oige)+":\n"+str(tahendus))
count=1
#vale=vale+1
#skoor=skoor-1
else:
if sisend==oige:
if tahendus==" ":
kast.insert(END,"Tubli, õige!\n"+str(oige)+"\n"+str(tahendus))
count=1
else:
kast.insert(END,"Tubli, õige!\n"+str(oige)+":\n"+str(tahendus))
count=1
#skoor=skoor+1
else:
if tahendus==" ":
kast.insert(END,"Kahjuks eksid. Õige on "+str(oige)+"\n"+str(tahendus))
count=1
else:
kast.insert(END,"Kahjuks eksid. Õige on "+str(oige)+":\n"+str(tahendus))
count=1
#vale=vale+1
#skoor=skoor-1
#if skoor<0:
# skoor=0
Now the problem is that I have to add arguments to kontroll() but I don't know how to do that with 'self' being there. To be honest, I don't even understand why I need that 'self' there, 'cause I'm not using classes which usually use the 'self' argument... So anyway, I googled the error I recieved without having 'self' there and after adding 'self' it started working, but I can't add 'skoor' and 'vale' in brackets...
Right now I just start kontroll with nothing in brackets, like this: kontroll().
So how should I start the function and how should I add the arguments to it? I can't use global variables either, 'cause this 'skoor=skoor+1' messes everything up (can't have global variable on the left side of equals sign).
Thanks.
EDIT:
GUI part of my program looks like this:
raam=Tk()
raam.title("MÄNG")
raam.geometry("430x450")
valik=IntVar()
valik2=IntVar()
C2=Checkbutton(raam,text="f",variable=valik2,command=lambda:ok.config(state=ACTIVE)).place(x=5,y=10)
ok=Button(raam,text="Alusta!",command=alusta,state=DISABLED)
ok.place(x=230,y=20,width=80)
C1=Checkbutton(raam,text="š",variable=valik,command=lambda:ok.config(state=ACTIVE)).place(x=5,y=30)
sisendivaartus=StringVar()
sisend=Entry(raam,textvariable=sisendivaartus)
sisend.place(x=10,y=250,width=200)
sisend.bind("<Return>",kontroll(skoor,vale))
credit=Label(raam,text="2013",font=("Verdana","7"))
credit.place(x=0,y=430)
score=Label(raam,text="Skoor:",font=("Verdana","7"))
score.place(x=380,y=430)
nupp=Button(raam,text="Seaded",command=seaded)
nupp.config()
nupp.place(x=330,y=20,width=80)
kast=Text(raam,wrap=WORD,font=("Verdana",10))
kast.config()
app=App(raam)
kast.place(x=10,y=60,width=400,height=180)
raam.mainloop()
For Henry's suggestion (how to use the function when not in class), I start getting different errors that have no basis, for example "NameError: global name 'oige' is not defined". Despite what the error says, global name 'oige' is defined and works fine without arguments. If I replace 'skoor' and 'vale' in the functions definition with just 'self' and recall it without any arguments, everything works just fine. I guess this is kind of hard to understand without seeing the whole piece, so I uploaded it here, if anyone has a minute.
PS. what I said earlier about having 0 classes in my code - that has changed since I constantly keep working on this. Also please keep in mind that this is a beta version of a beta, so many things are not supposed to work yet.
(For trivia: it tests and trains person's capabilities in Estonian orthography)
Writing Your Function
It's very easy to add more arguments to a function; simply change your function definition to
def kontroll(self, skoor, vale):
# Your code here.
Then skoor and vale become variable names local to the kontroll function and you can use them like any other variable.
As to why you need self in the function definition, that's because (presumably) this method is actually an instance method of some class you've defined. Instance methods always receive the object they're bound to as their first argument. This argument is called self, which is why you have to have an argument reserved for it. See this question for a more complete explanation.
If this is not actually an instance method of some class, mind you, then you don't actually need self. And generally speaking, if the method doesn't need a reference to a specific object instance, then there's no reason to make it an instance method!
Calling Your Function
Calling your function is just as simple, but it depends on the answer to the other question: is this actually an instance method? If it's defined inside a class (which it sounds like it is) then you need to do something like the following:
class C(object):
def kontroll(self, skoor, vale):
pass # Your code goes here.
c = C() # Create an instance of the class!
c.kontroll(skoor, vale) # The instance (c) is automatically passed to the method.
If, on the other hand, your function is not defined inside a class, your code should look like this:
def kontroll(skoor, vale):
pass # Your code goes here.
kontroll(skoor, vale)
You need self because this is almost certainly a method of a class, and you need to pass the object to the method when it is called. Self is just a convention, technically you can use some other name for this just as easily. That being said, it seems like you need to do some reading about classes in python and really try to understand the way an object instance works. I recommend starting with the docs:
http://docs.python.org/2/tutorial/classes.html
There appear to be a lot of globals in your code snippet that should probably be class variables, and you really need to understand how things like the __init__ method work before going to deep into this.

Why can't I "string".print()?

My understanding of the print() in both Python and Ruby (and other languages) is that it is a method on a string (or other types). Because it is so commonly used the syntax:
print "hi"
works.
So why doesn't "hi".print() in Python or "hi".print in Ruby work?
When you do something like "hi".print(), you are implying that the string object "hi" has a method print. This is not the case. Instead, print is a function that takes a string (or other types) as input.
Ruby does have a method Object#display (doc here), which sends a representation of the object to the current output stream, or one specified as an argument.
(I find that it's hard to work with in irb if I use ; at the end of a line to suppress the printing of the return value; if I do that, display's output isn't shown, even if I flush the stream.)
It's not a method on a string. Prior to Python 3, it was a statement (just like break or import), and you could use both print "hi" and print("hi"). From Python 3, it was replaced by a function, thus you can no longer use print "hi":
Print Is A Function
The print statement has been replaced with a
print() function, with keyword arguments to replace most of the
special syntax of the old print statement (PEP 3105).
Why should it work? String classes rarely have void print methods - and you would never need them, because the standard static print function can print those strings anyway. It is important to note: method(someObject) is not necessarily the same as someObject.method().
What do you propose str.print should do?
print to stdout? how about stderr? or a file? or a serial port?
Printing to stdout is really a special case but it's so ubiquitous that sometimes it can be overlooked.
Then we'd have to specify where str should print to every time we create a string?
At the very least we'd have to say
"foo".print(sys.stdout)
Hopefully that looks awful to you too. It's a confusion of responsibilities
print isn't a method on a string in Python (or in Ruby, I believe). It's a statement (in Python 3 it's a global function). Why? For one, not everything you can print is a string. How about print 2?
In case you are more happy to use a method rather than a statement in Ruby you can use the method display ("test".display) to achieve this or define a new method easily like
class String
def print
puts self
end
end
and use it like this
"test".print

Why the syntax for open() and .read() is different?

This is a newbie question, but I looked around and I'm having trouble finding anything specific to this question (perhaps because it's too simple/obvious to others).
So, I am working through Zed Shaw's "Learn Python the Hard Way" and I am on exercise 15. This isn't my first exposure to python, but this time I'm really trying to understand it at a more fundamental level so I can really do something with a programming language for once. I should also warn that I don't have a good background in object oriented programming or fully internalized what objects, classes, etc. etc. are.
Anyway, here is the exercise. The ideas is to understand basic file opening and reading:
from sys import argv
script, filename = argv
txt = open(filename)
print "Here's your file %r:" % filename
print txt.read()
print "I'll also ask you to type it again:"
file_again = raw_input("> ")
txt_again = open(file_again)
print txt_again.read()
txt.close()
txt_again.close()
My question is, why are the open and read functions used differntly?
For example, to read the example file, why don't/can't I type print read(txt) on line 8?
Why do I put a period in front of the variable and the function after it?
Alternatively, why isn't line 5 written txt = filename.open()?
This is so confusing to me. Is it simply that some functions have one syntax and others another syntax? Or am I not understanding something with respect to how one passes variables to functions.
Syntax
Specifically to the syntactical differences: open() is a function, read() is an object method.
When you call the open() function, it returns an object (first txt, then txt_again).
txt is an object of class file. Objects of class file are defined with the method read(). So, in your code above:
txt = open(filename)
Calls the open() function and assigns an object of class file into txt.
Afterwards, the code:
txt.read()
calls the method read() that is associated with the object txt.
Objects
In this scenario, it's important to understand that objects are defined not only as data entities, but also with built-in actions against those entities.
e.g. A hypothetical object of class car might be defined with methods like start_engine(), stop_engine(), open_doors(), etc.
So as a parallel to your file example above, code for creating and using a car might be:
my_car = create_car(type_of_car)
my_car.start_engine()
(Wikipedia entry on OOP.)
To answer this you should have some understanding of object oriented programming.
open() is a normal function, and the first parameter is a string, with the path to the file. The return value of this function is an object.
The further work is done by using this object. An object also has functions, but they are called methods. These methods are called in the context of this object, and the point connects the object with the method. So txt.read() means that you are calling the read-method from the txt-object.
But if you really want to understand this, you should have a look at OOP.
You're coming up against methods vs functions.
open is a global function, and it takes as its parameters simply the things that go between the brackets.
read is a method of file objects. The expression txt.read() calls the read method of the txt object. Under the hood, the txt object is passed as the first parameter of its read method. The read method will be defined something like this:
class File(object):
def read(self):
# do whatever here
# self is whatever object appears to the left of the dot in foo.read
It follows from the above definition that you can only use a method like read on an object which has a read method defined for it.

Categories