I am trying really hard to understand specifically parameters. Particularly, when I define a function I.e. def function(parameter): print(parameter) And then call it function("a simple string") Is the parameter always going to be parameter? It's receiving a value, right? So... Maybe I'm like mentally deficit... or overthinking this, but what if I do..
def function(parameter0, parameter1, parameter3)
print(parameter0, parameter1, parameter3)And then call the function
function("Does this cause an error?", "Must have exact values", "for each parameter?")Am I over thinking this? I'm just following lessons from a PDF. Python for the absolute beginner
I'm must confused and I'm not even sure how or why I'm confused.
-
Edit: formatting and typos
-
Update: Thanks everyone for your help. I think I am understanding it. I believe I'm overthinking it, and over reacting. Sorry for being difficult.
Videos
The other answers have done a good job at explaining duck typing and the simple answer by tzot:
Python does not have variables, like other languages where variables have a type and a value; it has names pointing to objects, which know their type.
However, one interesting thing has changed since 2010 (when the question was first asked), namely the implementation of PEP 3107 (implemented in Python 3). You can now actually specify the type of a parameter and the type of the return type of a function like this:
def pick(l: list, index: int) -> int:
return l[index]
Here we can see that pick takes 2 parameters, a list l and an integer index. It should also return an integer.
So here it is implied that l is a list of integers which we can see without much effort, but for more complex functions it can be a bit confusing as to what the list should contain. We also want the default value of index to be 0. To solve this you may choose to write pick like this instead:
def pick(l: "list of ints", index: int = 0) -> int:
return l[index]
Note that we now put in a string as the type of l, which is syntactically allowed, but it is not good for parsing programmatically (which we'll come back to later).
It is important to note that Python won't raise a TypeError if you pass a float into index, the reason for this is one of the main points in Python's design philosophy: "We're all consenting adults here", which means you are expected to be aware of what you can pass to a function and what you can't. If you really want to write code that throws TypeErrors you can use the isinstance function to check that the passed argument is of the proper type or a subclass of it like this:
def pick(l: list, index: int = 0) -> int:
if not isinstance(l, list):
raise TypeError
return l[index]
More on why you should rarely do this and what you should do instead is talked about in the next section and in the comments.
PEP 3107 does not only improve code readability but also has several fitting use cases which you can read about here.
Type annotation got a lot more attention in Python 3.5 with the introduction of PEP 484 which introduces a standard module typing for type hints.
These type hints came from the type checker mypy (GitHub), which is now PEP 484 compliant.
The typing module comes with a pretty comprehensive collection of type hints, including:
List,Tuple,Set,Dict- forlist,tuple,setanddictrespectively.Iterable- useful for generators.Any- when it could be anything.Union- when it could be anything within a specified set of types, as opposed toAny.Optional- when it might be None. Shorthand forUnion[T, None].TypeVar- used with generics.Callable- used primarily for functions, but could be used for other callables.
These are the most common type hints. A complete listing can be found in the documentation for the typing module.
Here is the old example using the annotation methods introduced in the typing module:
from typing import List
def pick(l: List[int], index: int) -> int:
return l[index]
One powerful feature is the Callable which allows you to type annotate methods that take a function as an argument. For example:
from typing import Callable, Any, Iterable
def imap(f: Callable[[Any], Any], l: Iterable[Any]) -> List[Any]:
"""An immediate version of map, don't pass it any infinite iterables!"""
return list(map(f, l))
The above example could become more precise with the usage of TypeVar instead of Any, but this has been left as an exercise to the reader since I believe I've already filled my answer with too much information about the wonderful new features enabled by type hinting.
Previously when one documented Python code with for example Sphinx some of the above functionality could be obtained by writing docstrings formatted like this:
def pick(l, index):
"""
:param l: list of integers
:type l: list
:param index: index at which to pick an integer from *l*
:type index: int
:returns: integer at *index* in *l*
:rtype: int
"""
return l[index]
As you can see, this takes a number of extra lines (the exact number depends on how explicit you want to be and how you format your docstring). But it should now be clear to you how PEP 3107 provides an alternative that is in many (all?) ways superior. This is especially true in combination with PEP 484 which, as we have seen, provides a standard module that defines a syntax for these type hints/annotations that can be used in such a way that it is unambiguous and precise yet flexible, making for a powerful combination.
In my personal opinion, this is one of the greatest features in Python ever. I can't wait for people to start harnessing the power of it. Sorry for the long answer, but this is what happens when I get excited.
An example of Python code which heavily uses type hinting can be found here.
Python is strongly typed because every object has a type, every object knows its type, it's impossible to accidentally or deliberately use an object of a type "as if" it was an object of a different type, and all elementary operations on the object are delegated to its type.
This has nothing to do with names. A name in Python doesn't "have a type": if and when a name's defined, the name refers to an object, and the object does have a type (but that doesn't in fact force a type on the name: a name is a name).
A name in Python can perfectly well refer to different objects at different times (as in most programming languages, though not all) -- and there is no constraint on the name such that, if it has once referred to an object of type X, it's then forevermore constrained to refer only to other objects of type X. Constraints on names are not part of the concept of "strong typing", though some enthusiasts of static typing (where names do get constrained, and in a static, AKA compile-time, fashion, too) do misuse the term this way.
In a few words, they're data that gets "passed into" the function to tell it what to do. Wikipedia has details.
http://en.wikipedia.org/wiki/Function_argument
For instance, your hi() function might need to know who to say hello to:
def hi(person):
print "Hi there " + person + ", how are you?"
Or a mathematical function might need a value to operate on:
def square(x):
return x * x
This is not a Python question, but rather a generic programming question. A very basic one.
Before answering the question about arguments, and in view of the other questions you asked, it is useful to discuss the concept of variables.
A variable is a named piece of memory where information of interest to the underlying program can be stored and retrieved. In other words, it is a symbolic name, chosen by the programmer, that is associated to its contents. Using various language constructs generally known as assignments, the programmer can read or write the contents of a variable.
It is important to note that the value (i.e. the content) of a variable needn't be defined when the program is written. It is only necessary at run-time. This allows the program to describe actions to be performed on symbolic elements without knowing exactly the value these elements have. Consider this snippet, part of a bigger program:
# ... some logic above
ball_volume = 4.0 / 3 * math.pi * ball_radius
if ball_volume > 200:
print ("Man, that's a big ball")
# ... more logic below
At the time the program is written one doesn't need to know the actual value of ball_radius; yet, with the assumption that this variable will contain the numeric value of some hypothetical ball, the snippet is capable of describing how to compute the ball's volume. In this fashion, when the program is running, and somehow (more on this later) the ball_radius variable has been initialized with some appropriate value, the variable ball_volume can too be initialized and used, here in the conditional statement (if), and possibly below. (At some point the variable may go out-of-scope, but this concept which controls when particular variables are accessible to the program is well beyond this primer).
In some languages the type of data that may be associated with a particular variable needs to be explicitly defined and cannot change. For example some variables could hold only integer values, other variables string values (text) etc. In Python there is no such restriction, a variable can be assigned and re-assigned to any type of data, but of course, the programmer needs to keep track of this for example to avoid passing some text data to a mathematical function.
The data stored inside variable may come from very different sources. Many of the examples provided in tutorials and introductory documentation have this data coming from keyboard input (as when using raw_input as mentioned in some of your questions). That is because it allows interactive tests by the people trying out these tutorial snippets. But the usefulness of programs would be rather limited if variables only get their data from interactive user input. There are many other sources and this is what makes programming so powerful: variables can be initialized with data from:
- databases
- text files or files various text-base formats (XML, JSON, CSV..)
- binary files with various formats
- internet connections
- physical devices: cameras, temperature sensors...
In a nutshell, Arguments, also called Parameters, are variables passed to the function which [typically] are used to provide different output and behavior from the function. For example:
>>> def say_hello(my_name):
... print("Hello,", my_name, "!")
>>> say_hello("Sam")
Hello, Sam !
>>> customer_name = "Mr Peter Clark" #imagine this info came from a database
>>> # ...
>>> say_hello(customer_name)
Hello, Mr Peter Clark !
>>>
In the example above, my_name is just like any local variable of the say_hello function; this allows the function to define what it will do with the underlying value when the function is called, at run-time.
At run-time, the function can be called with an immediate value (a value that is "hard-coded" in the logic, such as "Sam" in the example), or with [the value of] another variable (such as customer_name). In both cases the value of the function's my_name variable gets assigned some value, "Sam" and "Mr Peter Clark" respectively. In the latter case, this value is whatever the customer_name variable contains. Note that the names of the variables used inside the function (my_name) and when the function is called (customer_name) do not need to be the same. (these are called the "formal parameter(s)" and the "actual parameters" respectively)
Note that while typically most arguments as passed as input to a function, in some conditions, they can be used as output, i.e. to provide new/modified values at the level of the logic which called the function. Doing so requires using, implicitly or explicitly, the proper calling convention specification (See Argument passing conventions below)
Now... beyond this very basic understanding of the purpose of parameters, things get a little more complicated than that (but not much). I'll discuss these additional concepts in general and illustrate them as they apply to Python.
Default values for arguments (aka "optional" arguments)
When the function is declared it may specify the default value for some parameters. These values are used for the parameters which are not specified when the function is called. For obvious reasons these optional parameters are found at the end of the parameter list (otherwise the language compiler/interpreter may have difficulty figuring out which parameter is which...)
>>> def say_hello(dude = "Sir"):
... print("Hello,", dude, "!")
...
>>> say_hello()
Hello, Sir !
>>> say_hello("William Gates")
Hello, Bill ! #just kidding ;-)
Hello, William Gates ! # but indeed. works as the original function when param
# is specified
Variable number of parameters
In some cases it may be handy to define a function so that it may accept a variable number of parameters. While such lists of parameter values ultimately get passed in some kind of container (list, array, collection...) various languages offers convenient ways of accessing such parameter values.
>>> def add_many(operand1, *operands):
... Sum = operand1
... for op in operands:
... Sum += op
... return Sum
...
>>> add_many(1, 3, 5, 7, 20)
36
>>> add_many(1, 3)
4
Named Arguments (Keyword Arguments)
With Python and a few other languages, it is possible to explicitly name the arguments when calling the function. Whereby argument passing is by default based a positional basis ("1st argument, 2nd argument etc.), Python will let you name the arguments and pass them in any order. This is mostly a syntactic nicety, but can be useful, in combination with default arguments for functions that accept very many arguments. It is also a nice self-documenting feature.
>>> def do_greetings(greeting, person):
... print (greeting, "dear", person, "!")
...
>>> do_greetings(person="Jack", greeting="Good evening")
Good evening dear Jack !
In Python, you can even pass a dictionary in lieu of several named arguments for example, with do_greetingsas-is, imagine you have a dictionary like:
>>> my_param_dict = {"greeting":"Aloha", "person":"Alan"}
>>> do_greetings(**my_param_dict)
Aloha dear Alan !
In closing, and while the fancy ways of passing arguments, and the capability for methods to handle variable number of arguments are useful features of various languages, two key concepts need to be mentioned:
Argument passing convention : by value or by reference
So far all the functions we used didn't alter the value of the parameters passed to them. We can imagine however many instances when functions may want to do this, either to perform some conversion or computation on the said values, for its own internal use, or to effectively change the value of the variable so that the changes are reflected at the level of logic which called the function. That's where argument passing conventions come handy...
arguments which are passed by value may be altered by the function for its own internal computations but are not changed at the level of the calling method.
arguments which are passed by reference will reflect changes made to them, at the level of the calling method.
Each language specifies the ways that arguments are passed. A typical convention is to pass integers, numberic values and other basic types by value and to pass objects by reference. Most language also offer keyword that allow altering their default convention.
In python all arguments are passed by reference. However a few variables types are immutable (numbers, strings, tuples...) and they can therefore not be altered by the function.
Implicit "self" or "this" argument of class methods
In object oriented languages, methods (i.e. functions within a class) receive an extra argument that is the value of underlying object (the instance of the class), allowing the method to use various properties members of the class in its computation and/or to alter the value of some of these properties.
in Python, this argument is declared at the level of the method definition, but is passed implicitly. Being declared, it may be named most anything one wishes, although by convention this is typically called self.
>>> class Accumulator:
... def __init__(self, initialValue = 0):
... self.CurValue = initialValue
... def Add(self, x):
... self.CurValue += x
... return self.CurValue
...
>>> my_accu = Accumulator(10)
>>> my_accu.Add(5)
15
>>> my_accu.Add(3)
18