I'm confused about choosing names for my functions in Python. Sometimes Python built-in functions are imperative such as: print
function and string method find
. Sometimes they aren't such as: len
its name isn't imperative such as calculate_len
, for instance, and type
isn't find_type
.
I can understand that print
returns a value that we don't use (i.e None
) and does something (i.e it shows a string on the screen), so its name is imperative.
But len
returns a value that we use and does something (i.e. calculating how many items there are in a sequence or a mapping.) and its name isn't imperative. On the other hand, find
string method (as len
) returns a value that we use and does something, and its name is imperative.
What made ask this question is that I put a script that encrypt and decrypt string using Caesar cipher to being reviewed. The reviewer said that:
Just a gut feeling: functions do stuff. So a good name for a function is an imperative: I'd use
rotate_letter
instead ofrotated_letter
.
rotated_letter
returns a single-letter string representing a letter rotated by a number. I don't know what is better, I used rotated_letter
as it returns a value, like randint
function in random module, it isn't generate_randint
.
So, in this case, how should I name a function that returns a value to be used? Should I make the name imperative or just a noun. In other cases it's obvious how to do it, such as boolean functions, such as is_even
and is_palindrome
we just make it like a yes/no question, and also functions that just do and return non-used values (i.e None
), such as print
and list method sort
.
2 Answers 2
Use verbs where reasonable, nouns if they are shorter and unambiguous
Most of the time, functions should be (imperative) verbs and classes, variables, and parameters should be nouns. Attributes should also be nouns, including those created using @property
. This is especially the case for functions which have side effects.[1] If a function does return something, you should evaluate whether the verb adds something or is just "noise":
make_list(foo)
vs.list(foo)
: The noun is easier to read than the verb. Also,list
is actually a class, and classes should be nouns.open(foo)
vs.file(foo)
: The verb is easier to read than the noun, and it makes more sense to give "options" to a verb than to a noun, so the noun was removed in Python 3.open()
remains the only "standard"[2] way to create file objects in Python 3.foo.get_bar()
vs.foo.bar()
vs.foo.bar
(assumefoo
andbar
are both nouns): The first option is right out, because the "get" doesn't add anything that we didn't already know. The second is appropriate if getting abar
out of afoo
is a potentially expensive operation and/or carries side effects (you might also considerBar(foo)
ifBar
is a class). The third is appropriate if this is a cheap operation with no side effects, and alternative implementations are unlikely to make it expensive.xs.sort()
vs.sorted(xs)
ifxs
is a list: The first is imperative: Sort the list. It modifies the list in-place and returns nothing. The second is declarative: A list that is sorted, which is precisely what it returns. Both are verbs.
[1]: Usually returning a value and having side effects are mutually exclusive unless you have some compelling design reason to combine them. So a function that has side effects should probably not return anything and hence making it a noun would make very little sense.
[2]: There are some moderately lower-level operations in the io
module which can be used to add or remove file buffering, automatic text en/decoding, etc., and these are mostly nouns because they are object-oriented classes. Most users do not need to play with these things directly; instead, open()
chooses an appropriate class and instantiates it automatically.
-
Thank you! In "
foo.get_bar()
vs.` foo.bar()` vs.foo.bar
" what is the difference between the second and the third?Mahmood Muhammad Nageeb– Mahmood Muhammad Nageeb10/21/2016 15:22:22Commented Oct 21, 2016 at 15:22 -
The third is either a property or a bare attribute. The second is a method.Kevin– Kevin10/21/2016 15:22:33Commented Oct 21, 2016 at 15:22
-
So, if I understand, it's appropriate not to make
rotated_letter
imperative and keep it declarative, right?Mahmood Muhammad Nageeb– Mahmood Muhammad Nageeb10/21/2016 15:29:03Commented Oct 21, 2016 at 15:29 -
In this case I'm not sure whether
letter
is implied by context.Kevin– Kevin10/21/2016 15:33:03Commented Oct 21, 2016 at 15:33 -
1+1 for mentioning
list
is a classDušan Maďar– Dušan Maďar07/18/2019 12:45:14Commented Jul 18, 2019 at 12:45
rotated_letter
doesn't look like a method. It looks like a property. Which means that the first idea is to do:
var letter = caesar.rotated_letter
expecting letter
to contain a value of type string, not a function. From there, either you chose a different name, such as:
def rotate_letter(self):
pass
or you use a property instead:
@property
def rotated_letter(self):
return self.whatever
len
and type
are named like that because any other name would be long to type. They are used a lot, and they have a special status of core Python functions that every Python programmer will learn anyway, making their names much more irrelevant than the names of third-party libraries.
len
, especially, is a good example of what you shouldn't do in your code: you're expected to use full names such as length
(unless the short form is very popular, such as max
), and use a verb, such as compute_length
. Or it could be a property: len([1, 5, 6])
becomes [1, 5, 6].length
. For instance, in C#, the later form is used: new [] { ... }.Length
.
Note that there may be historical reasons as well for len
: other languages, such as C#, preferred Count
, which is usually a method (although the behavior is unfortunately inconsistent through .NET Framework). Count
is a verb, so intuitively, you're inclined to invoke it as a method.
Returning values or performing an action
A function is always expected to perform an action. If it just returns a value, it should be a property. You have a hint that the function should be transformed into a property when:
The function just contains a
return ...
statement,The function's name which comes naturally into your mind is
get_something
, as inproduct.get_price()
.
Now, if you have a function, it can be one of four types:
It can be pure, that is return a value without affecting the environment. Example:
road.measure_distance()
.It can affect the environment without returning anything. Example:
product_database.remove_record(1234)
.It can affect the environment and return a value. Example:
value.increment()
used such asvalue++
.It can do nothing and return nothing. Example:
time.sleep(1)
.
There are few cases where the name could give a strong hint about the type of the function, but in many cases, you won't be able to know the type just from its name.
-
I assume the answer is "yes", but I must ask: are you answering entirely from the perspective of Python? Because in other languages your separation of function vs property is not always true; it's also not true that a function "must perform an action". Is this the convention in Python? (I write Python but haven't read all the PEPs and I'm definitely NOT an expert. I didn't downvote, BTW).Andres F.– Andres F.10/20/2016 14:29:19Commented Oct 20, 2016 at 14:29
-
@AndresF.: I'm answering from the perspective of Python. In languages such as Java where properties don't exist,
getSomething
andsetSomething
are the usual names used instead of properties.Arseni Mourzenko– Arseni Mourzenko10/20/2016 19:23:19Commented Oct 20, 2016 at 19:23
Explore related questions
See similar questions with these tags.
len
, for example, is better thought of as "length of" - you're getting a meta-level description of its argument.