Parameter naming convention in Python - python

For functions with closely related formal parameters, such as
def add_two_numbers(n1, n2):
return n1 + n2
def multiply_two_numbers(n1, n2):
return n1 * n2
Is it a good idea to give the same names to the parameters in both functions, as shown above?
The alternative is to rename the parameters in one of the functions. For example:
def add_two_numbers(num1, num2):
return num1 + num2
Keeping them the same in both functions looks more consistent since the parameters each one takes are analogous, but is that more confusing?
Similarly, which would be better for the example below?
def count(steps1, steps2):
a = 0
b = 0
for i in range(steps1):
a += 1
for j in range(steps2):
b += 1
return a, b
def do_a_count(steps1, steps2):
print "Counting first and second steps..."
print count(steps1, steps2)
Otherwise, changing the arguments in the second function gives:
def do_a_count(s1, s2):
print "Counting first and second steps..."
print count(s1, s2)
Again, I'm a little unsure of which way is best. Keeping the same parameter names makes the relation between the two functions clearer, while the second means there is no possibility of confusing parameters in the two functions.
I have done a bit of searching around (including skimming through PEP-8), but couldn't find a definitive answer. (Similar questions on SO I found included:
Naming practice for optional argument in python function
and
In Python, what's the best way to avoid using the same name for a __init__ argument and an instance variable?)

I would keep the names the same unless you have a good reason to use different names ... Remember that even positional arguments can be called by keywords, e.g.:
>>> def foo(a,b):
... print a
... print b
...
>>> foo(b=2,a=1)
Keeping the "keywords" the same helps in that rare, but legal corner case ...

In general, you should give your function's parameters names that make sense, and not even consider anything to do with other functions when you choose those names. The names of two functions' parameters simply don't have anything to do with each other, even if the functions do similar things.
Although... if the functions do do similar things, maybe that's a sign that you've missed a refactoring? :)

The important guideline here is that you should give them reasonable names—ideally the first names that you'd guess the parameters to have when you come back to your code a year later.
Every programmer has a set of conventions. Some people like to call integer arguments to binary functions n1 and n2; others like n, m; or lhs, rhs; or something else. As long as you pick one and stick to it (as long as it's reasonable), anyone else can read your code, and understand it, after a few seconds learning your style. If you use different names all over the place, they'll have to do a lot more guessing.
As mgilson points out, this allows you to use keyword parameters if you want. It also means an IDE with auto-complete is more useful—when you see the (…n1…, …n2…) pop up you know you want to pass two integers. But mainly it's for readability.
Of course if there are different meanings, give them different names. In some contexts it might be reasonable to have add_two_numbers(augend, addend) and multiply_two_numbers(factor, multiplicand).

Related

When to type-check a function's arguments?

I'm asking about situations where if a wrong type of argument is passed to the function, it could:
Blow up the whole thing.
Return unexpected results
Return nothing
For instance, the function below expects the argument name to be a string. It would throw an exception for all other types that doesn't have a startswith method.
def fruits(name):
if name.startswith('O'):
print('Is it Orange?')
There are other cases where a function could halt or cause damage to the system if execution proceeds without type-checking. Whenever there are a lot of functions or functions with a lot of arguments, type checking is tedious and makes the code unreadable. So, is there a standard for doing this? As to 'how to type check' - there are plenty of examples here on stackexchange, but I couldn't find any about where it would be appropriate to do so.
Another example would be:
def fruits(names):
with open('important_file.txt', 'r+') as fil:
for name in names:
if name in fil:
# Edit the file
Here if the name is a string each character in it will influence the editing of the file. If it is any other iterable, each element provided by it would influence the editing. Both of these could produce different results.
So, when should we type-check an argument and should we not?
The answer off the top of my head would be: it depends where the input comes from.
If the functions are class methods that get invokes internally or things like that, you can assume the inputs are valid, because you wrote it!
For example
def add(x,y):
return x + y
def multiply(a,b):
product = 0
for i in range(a):
product = add(product, b)
return product
In my add function, I could check that there is a + operator for the parameters x and y. But since I wrote the multiply function, and that is the only function that uses add, it is safe to assume the inputs will be int because that's how I wrote it. Now that argument stands on shaky ground for large code bases where you (hopefully) have shared code, so you can't be sure people don't misuse your functions. But that's why you comment them well to describe the correct use of said function.
If it has to read from a file, get user input, etc, then you may want to do some validation first.
I almost never do type checking in Python. In accordance with Pythonic philosophy I assume that me and other programmers are adult people capable of reading the code (or at least the documentation) and using it properly. I assume that we test our code before we let it destroy something important. After all in most cases if you do something wrong, you'll just see an error and Python's error messages are quite informative most of the time.
The only occasion when I sometimes check types is when I want my function to behave differently depending on the argument's type. But although I sometimes feel compelled to do this, I don't consider it a good practice.
Most often it happens when my function iterates over a list of strings and I fear (or want) I could get a single string passed into it by accident - this won't throw an error at once because unfortunately string is an iterable too.

How declare for in function with parameter

I new in Python. I don't know how work this.
I have this code:
def main():
a=input("Type number")
e=int(a)
function2(e);
def function2(e):
for h in range(e):
print("X")
main();
write me this error:
Traceback (most recent call last)
for h in range(e):
NameError: name 'e' is not defined
Thats because of an indentation error, and you forgot to put a : after your for loop:
def main():
a = input("Type number")
e = int(a)
function2(e)
def function2(e):
for h in range(e):
print("X")
main()
Also, no semicolons are required in python.
Your problem seems to be a series of misunderstandings in general. Your errors in your code are simple, but let's see if I can't walk you through some concepts so that when I show you the fixed code, you understand it completely. Keep in mind that I expect you already know a lot of it, but I'm writing this answer not just for you, but for any other beginners who stumble upon this page. :)
It seems we can cover the following topics (each concept is simple in itself, but you need to get them completely in order to get the next one):
Variables in programming
Variables in python
Whitespace in python
Functions: Parameters vs Arguments
Solution: fixing your code
Variables in programming
Variables, as you probably know, are simply the labels we give to data. In most languages, you have to declare the variable first so that you can have the appropriate type assigned to it (that is, so the computer knows whether it's an integer, a string, a boolean, etc). Thus, you need the following code:
int myVariable1 = 3;
string myVariable2 = "hello";
bool myVariable3 = true;
(In some languages, you need to declare variables and then assign a value to them.)
Variables in python
Python, apart from many starter languages, is dynamically typed. This means that the variables (the labels on the data) have no type, but the values do.
That means that your code can look like this
myVariable1 = 3
myVariable2 = "hello"
myVariable3 = True
And python can figure out what types to use, based on the data assigned to the variables.
(Note: in python, you don't need ; to end a line, and boolean values are capitalized (True, `False))
Whitespace in python
Python was designed to be easy to read. Computers use hints inside the language ((), [], {}, :, ;, etc) to know what's going on. In Python, whitespace (      ) is part of the hinting, or syntax. In most languages, whitespace is ignored but because Python does not ignore it, it can be used to format your languages in a visually pleasing way. In C++,
function myFunction() {string myString = "wow such learn good job, many doge wow";}
and
function myFunction() {
string myString = "wow such learn good job, many doge wow";
}
are the same. You can see how this could confuse a new programmer, as it doesn't even look the same. But in Python, the code has to look like:
def myFunction():
myString = "wow such learn good job, many doge wow"
And it is this uniformity that makes Python so much easier to work with, for a lot of people.
Functions: Parameters vs Arguments
In every decent language, the use of functions is vital, and understanding them completely is even more vital.
Functions can easily be related to basic concepts of Algebra. Functions already exist in Algebra, this being why the comparison is so easiy.
In Algebra, a function is an equation with variables in it. Inside the function, work is ready to be done with the equation that is set up, and it's just waiting for you to fill in the missing pieces. That is to say,
f(x) = 3 + 2x + x^2
is a function that is ready to go, but it needs to you put in x.
This is the same thing in programming. When I write
def myFunction(x):
3+2x+x**2
I am writing the exact same thing as f(x); A working equation that depends on the information it is given.
A note: Not all programming functions do math exactly, some operate on strings, but they all alter data and that is my point. Some functions don't even need input, because they operate on data independent of what you're doing. Here, the comparison falls apart somewhat, but I hope you're still onboard.
So, what are arguments and what are parameters?
When defining the function and then calling the function:
def myFunction(x): #defining the function f(x)
3+2x+x**2
print myFunction(3) #calling the function f(x) where x=3
The parameter is x in the first line. Parameters are the variables that you put into the definition of a function.
The argument is the 3 that you put in place of the x when you called the function. Arguments are the values you use to fill in the variables in a function.
As such, you are now giving the function the value 3 and it solves the following:
3+2*(3)+(3)^2
3+6+9
9+9
18
The resulting output will of course print:
18.
Solution: fixing your code
Now that we've gone over all of the base concepts that lead to your code getting errors. Here is your original code:
def main():
a=input("Type number")
e=int(a)
function2(e);
def function2(e):
for h in range(e):
print("X")
main();
There are a multitude of errors here:
Your def main(): is written mostly correct, but the indentation may not be sufficient. Python standard, the one that may confuse less sophisticated interpreters for it, requires about 4 spaces as its whitespace and indentation.
Your def main(): also uses a ; at the end, which, as a difference between Python and lots of other languages, is a syntax problem. Python doesn't need ;, and just removing it fixes that error.
Your def function2(e): appears to have no errors aside from the whitespace problem that we saw in def main():
Your def function2(e): makes use of print(), which, while this is no error, is a syntax difference that is significant between Python 2.7 and Python 3.3; For this reason, I'll be adding the tag Python 3.3 for future-proofing reasons.
When you call main();, the ending ; is unneccessary, and can be removed.
Here is a revised version of your code that works.
def main():
a = input("Type number")
e = int(a)
function2(e)
def function2(e):
for h in range(e):
print("X")
main()
Do you understand how it works completely now? Sorry for all the reading, hopefully you are much more comfortable now, having gone through the entire thing!
For any questions, don't hesitate to ask in a comment below.
Happy Coding!
PS - I see that you already picked the best answer. But maybe after reading this one, you'll change your mind ;)
You're missing a colon : inside of your function2, so if you change that bit to:
def function2(e):
for h in range(e):
print("X")
You should be good to go.
None Any mistake or synatx erorr in Your Code It is Working Fine .
And You can indent the code by (tab) or by one space or any thing else .as long as you are saved the Blocks

Flexible Arguments in Python

This has probably been asked before, but I don't know how to look up the answer, because I'm not sure what's a good way to phrase the question.
The topic is function arguments that can semantically be expressed in many different ways. For example, to give a file to a function, you could either give the file directly, or you could give a string, which is the path to the file. To specify a number, you might allow an integer as an argument, or maybe you might allow a string (the numeral), or you might even allow a string such as "one". Another example might be a function that takes a list (of numbers, say), but as a convenience, it will convert a number into a list containing one element: that number.
Is there a more or less standard approach in Python to allowing this sort of flexibility? It certainly complicates the code for a program if you're not certain what types the arguments are, so my guess would be to try factor out the convenience functions into just one place, instead of scattered everywhere, but I don't really know how best to do that kind of factoring.
No, there is not more or less a "standard" approach to this.
Don't do that! ;)
But if you still want to, I'd suggest that you have an intermediate class or function handling this for you:
Pseudocode:
def printTheNumber(num):
print num
def intermediatePrintTheNumber(input):
num_int_dict = {'one':1, "two":2 ....
if input.isstring():
printTheNumber(num_int_dict[input])
elif input.isint():
printTheNumber(input)
else:
print "Sorry Dave, I don't understand you"
If this is pythonic I don't know, but that's how I'd solve it if I had to, of course with some more checking of the input to deem it valid.
When it comes to your comment you mention semantic similarity i.e "one" and 1 might mean the same thing.
Where should this kind of conversion be made you ask.
Well that depends on the design of your system, but I can tell you that it should not be done in the same function that I call printTheNumber for one very simple reason, and that is that that would give that function way to much responsibility.
Depending on the complexity of the input it could be the integer 1 or the string "1" or, in the worse case, "one" or maybe even worse "uno"|"one"|"yxi"|"ett" .. and so on. This should be handled by a function that has only that responsibility maybe with a database handling the mapping.
I would split it up so that I have one function handling the the strings "one", "two" ... etc, and one handling integers and have a third function that checks the input to see if it can be converted to an integer or not.
As I see it, there is a warning for a fundamental flaw in the design if you have to take measures for this kind of complexity, but you seem to be aware of that so I won't go on about it.
A good way to factor out code common to several functions is through decorators. For example,
from functools import wraps
def takes_list(func):
#wraps(func)
def wrapper(arg):
if not isinstance(arg, list):
arg = [arg]
return func(arg)
return wrapper
#takes_list
def my_func(x):
"Does something with list x."
I should note that for cases such as files, you don't want to get in the way of Python's duck typing: doing a check isinstance(arg, file) has the problem that it won't allow file-like things such as io.StringIO. Instead, check against str (or basestring) or even let open do the checking for you, with try-except.
However, it's generally better practice just to let the caller pass what they like into the function, and fail if it isn't valid.
Since you can not add methods at runtime to builtin classes such as int or str you would make a switch case statement like structure as mentioned by Daniel Figueroa.
Another way would be to just convert:
def func(i):
if not isinstance(i, int):
i = int(i) # objects can overwrite __int__ if needed.
If you have own classes that you can add methods to, you may use double dispatch to do the same thing for you. Smalltalk uses this for the Integer-Float-... conversion.
Another way would be to use subject oriented programming for which I have not found an implementation yet but I tried: https://gist.github.com/niccokunzmann/4971938

explicitly passing functions in python

Out of curiosity is more desirable to explicitly pass functions to other functions, or let the function call functions from within. is this a case of Explicit is better than implicit?
for example (the following is only to illustrate what i mean)
def foo(x,y):
return 1 if x > y else 0
partialfun = functools.partial(foo, 1)
def bar(xs,ys):
return partialfun(sum(map(operator.mul,xs,ys)))
>>> bar([1,2,3], [4,5,6])
--or--
def foo(x,y):
return 1 if x > y else 0
partialfun = functools.partial(foo, 1)
def bar(fn,xs,ys):
return fn(sum(map(operator.mul,xs,ys)))
>>> bar(partialfun, [1,2,3], [4,5,6])
There's not really any difference between functions and anything else in this situation. You pass something as an argument if it's a parameter that might vary over different invocations of the function. If the function you are calling (bar in your example) is always calling the same other function, there's no reason to pass that as an argument. If you need to parameterize it so that you can use many different functions (i.e., bar might need to call many functions besides partialfun, and needs to know which one to call), then you need to pass it as an argument.
Generally, yes, but as always, it depends. What you are illustrating here is known as dependency injection. Generally, it is a good idea, as it allows separation of variability from the logic of a given function. This means, for example, that it will be extremely easy for you to test such code.
# To test the process performed in bar(), we can "inject" a function
# which simply returns its argument
def dummy(x):
return x
def bar(fn,xs,ys):
return fn(sum(map(operator.mul,xs,ys)))
>>> assert bar(dummy, [1,2,3], [4,5,6]) == 32
It depends very much on the context.
Basically, if the function is an argument to bar, then it's the responsibility of the caller to know how to implement that function. bar doesn't have to care. But consequently, bar's documentation has to describe what kind of function it needs.
Often this is very appropriate. The obvious example is the map builtin function. map implements the logic of applying a function to each item in a list, and giving back a list of results. map itself neither knows nor cares about what the items are, or what the function is doing to them. map's documentation has to describe that it needs a function of one argument, and each caller of map has to know how to implement or find a suitable function. But this arrangement is great; it allows you to pass a list of your custom objects, and a function which operates specifically on those objects, and map can go away and do its generic thing.
But often this arrangement is inappropriate. A function gives a name to a high level operation and hides the internal implementation details, so you can think of the operation as a unit. Allowing part of its operation to be passed in from outside as a function parameter exposes that it works in a way that uses that function's interface.
A more concrete (though somewhat contrived) example may help. Lets say I've implemented data types representing Person and Job, and I'm writing a function name_and_title for formatting someone's full name and job title into a string, for client code to insert into email signatures or on letterhead or whatever. It's obviously going to take a Person and Job. It could potentially take a function parameter to let the caller decide how to format the person's name: something like lambda firstname, lastname: lastname + ', ' + firstname. But to do this is to expose that I'm representing people's names with a separate first name and last name. If I want to change to supporting a middle name, then either name_and_title won't be able to include the middle name, or I have to change the type of the function it accepts. When I realise that some people have 4 or more names and decide to change to storing a list of names, then I definitely have to change the type of function name_and_title accepts.
So for your bar example, we can't say which is better, because it's an abstract example with no meaning. It depends on whether the call to partialfun is an implementation detail of whatever bar is supposed to be doing, or whether the call to partialfun is something that the caller knows about (and might want to do something else). If it's "part of" bar, then it shouldn't be a parameter. If it's "part of" the caller, then it should be a parameter.
It's worth noting that bar could have a huge number of function parameters. You call sum, map, and operator.mul, which could all be parameterised to make bar more flexible:
def bar(fn, xs,ys, g, h, i):
return fn(g(h(i,xs,ys))
And the way in which g is called on the output of h could be abstracted too:
def bar(fn, xs, ys, g, h, i, j):
return fn(j(g, h(i, xs, ys)))
And we can keep going on and on, until bar doesn't do anything at all, and everything is controlled by the functions passed in, and the caller might as well have just directly done what they want done rather than writing 100 functions to do it and passing those to bar to execute the functions.
So there really isn't a definite answer one way or the other that applies all the time. It depends on the particular code you're writing.

Parameter names in Python functions that take single object or iterable

I have some functions in my code that accept either an object or an iterable of objects as input. I was taught to use meaningful names for everything, but I am not sure how to comply here. What should I call a parameter that can a sinlge object or an iterable of objects? I have come up with two ideas, but I don't like either of them:
FooOrManyFoos - This expresses what goes on, but I could imagine that someone not used to it could have trouble understanding what it means right away
param - Some generic name. This makes clear that it can be several things, but does explain nothing about what the parameter is used for.
Normally I call iterables of objects just the plural of what I would call a single object. I know this might seem a little bit compulsive, but Python is supposed to be (among others) about readability.
I have some functions in my code that accept either an object or an iterable of objects as input.
This is a very exceptional and often very bad thing to do. It's trivially avoidable.
i.e., pass [foo] instead of foo when calling this function.
The only time you can justify doing this is when (1) you have an installed base of software that expects one form (iterable or singleton) and (2) you have to expand it to support the other use case. So. You only do this when expanding an existing function that has an existing code base.
If this is new development, Do Not Do This.
I have come up with two ideas, but I don't like either of them:
[Only two?]
FooOrManyFoos - This expresses what goes on, but I could imagine that someone not used to it could have trouble understanding what it means right away
What? Are you saying you provide NO other documentation, and no other training? No support? No advice? Who is the "someone not used to it"? Talk to them. Don't assume or imagine things about them.
Also, don't use Leading Upper Case Names.
param - Some generic name. This makes clear that it can be several things, but does explain nothing about what the parameter is used for.
Terrible. Never. Do. This.
I looked in the Python library for examples. Most of the functions that do this have simple descriptions.
http://docs.python.org/library/functions.html#isinstance
isinstance(object, classinfo)
They call it "classinfo" and it can be a class or a tuple of classes.
You could do that, too.
You must consider the common use case and the exceptions. Follow the 80/20 rule.
80% of the time, you can replace this with an iterable and not have this problem.
In the remaining 20% of the cases, you have an installed base of software built around an assumption (either iterable or single item) and you need to add the other case. Don't change the name, just change the documentation. If it used to say "foo" it still says "foo" but you make it accept an iterable of "foo's" without making any change to the parameters. If it used to say "foo_list" or "foo_iter", then it still says "foo_list" or "foo_iter" but it will quietly tolerate a singleton without breaking.
80% of the code is the legacy ("foo" or "foo_list")
20% of the code is the new feature ("foo" can be an iterable or "foo_list" can be a single object.)
I guess I'm a little late to the party, but I'm suprised that nobody suggested a decorator.
def withmany(f):
def many(many_foos):
for foo in many_foos:
yield f(foo)
f.many = many
return f
#withmany
def process_foo(foo):
return foo + 1
processed_foo = process_foo(foo)
for processed_foo in process_foo.many(foos):
print processed_foo
I saw a similar pattern in one of Alex Martelli's posts but I don't remember the link off hand.
It sounds like you're agonizing over the ugliness of code like:
def ProcessWidget(widget_thing):
# Infer if we have a singleton instance and make it a
# length 1 list for consistency
if isinstance(widget_thing, WidgetType):
widget_thing = [widget_thing]
for widget in widget_thing:
#...
My suggestion is to avoid overloading your interface to handle two distinct cases. I tend to write code that favors re-use and clear naming of methods over clever dynamic use of parameters:
def ProcessOneWidget(widget):
#...
def ProcessManyWidgets(widgets):
for widget in widgets:
ProcessOneWidget(widget)
Often, I start with this simple pattern, but then have the opportunity to optimize the "Many" case when there are efficiencies to gain that offset the additional code complexity and partial duplication of functionality. If this convention seems overly verbose, one can opt for names like "ProcessWidget" and "ProcessWidgets", though the difference between the two is a single easily missed character.
You can use *args magic (varargs) to make your params always be iterable.
Pass a single item or multiple known items as normal function args like func(arg1, arg2, ...) and pass iterable arguments with an asterisk before, like func(*args)
Example:
# magic *args function
def foo(*args):
print args
# many ways to call it
foo(1)
foo(1, 2, 3)
args1 = (1, 2, 3)
args2 = [1, 2, 3]
args3 = iter((1, 2, 3))
foo(*args1)
foo(*args2)
foo(*args3)
Can you name your parameter in a very high-level way? people who read the code are more interested in knowing what the parameter represents ("clients") than what their type is ("list_of_tuples"); the type can be defined in the function documentation string, which is a good thing since it might change, in the future (the type is sometimes an implementation detail).
I would do 1 thing,
def myFunc(manyFoos):
if not type(manyFoos) in (list,tuple):
manyFoos = [manyFoos]
#do stuff here
so then you don't need to worry anymore about its name.
in a function you should try to achieve to have 1 action, accept the same parameter type and return the same type.
Instead of filling the functions with ifs you could have 2 functions.
Since you don't care exactly what kind of iterable you get, you could try to get an iterator for the parameter using iter(). If iter() raises a TypeError exception, the parameter is not iterable, so you then create a list or tuple of the one item, which is iterable and Bob's your uncle.
def doIt(foos):
try:
iter(foos)
except TypeError:
foos = [foos]
for foo in foos:
pass # do something here
The only problem with this approach is if foo is a string. A string is iterable, so passing in a single string rather than a list of strings will result in iterating over the characters in a string. If this is a concern, you could add an if test for it. At this point it's getting wordy for boilerplate code, so I'd break it out into its own function.
def iterfy(iterable):
if isinstance(iterable, basestring):
iterable = [iterable]
try:
iter(iterable)
except TypeError:
iterable = [iterable]
return iterable
def doIt(foos):
for foo in iterfy(foos):
pass # do something
Unlike some of those answering, I like doing this, since it eliminates one thing the caller could get wrong when using your API. "Be conservative in what you generate but liberal in what you accept."
To answer your original question, i.e. what you should name the parameter, I would still go with "foos" even though you will accept a single item, since your intent is to accept a list. If it's not iterable, that is technically a mistake, albeit one you will correct for the caller since processing just the one item is probably what they want. Also, if the caller thinks they must pass in an iterable even of one item, well, that will of course work fine and requires very little syntax, so why worry about correcting their misapprehension?
I would go with a name explaining that the parameter can be an instance or a list of instances. Say one_or_more_Foo_objects. I find it better than the bland param.
I'm working on a fairly big project now and we're passing maps around and just calling our parameter map. The map contents vary depending on the function that's being called. This probably isn't the best situation, but we reuse a lot of the same code on the maps, so copying and pasting is easier.
I would say instead of naming it what it is, you should name it what it's used for. Also, just be careful that you can't call use in on a not iterable.

Categories

Resources