Should the names of function arguments reflect the context of the function in which they are used?
To give a concrete example in Python, (taken from this textbook):
def create_radio_button(rb_name, rb_value):
vs
def create_radio_button(name, value):
The Python style guide suggests using underscores to avoid keyword clashes, but doesn't mention the use of prefixes in arguments. In Clean Code, Bob Martin suggests choosing variable names that are pronounceable and to avoid encodings, which perhaps counts against an rb_ prefix. However, he follows this by stating that variable names should be searchable. My primary goal is to improve the clarity of my code, so I'm interested to hear what people have found easiest to work with.
It depends on context, and perhaps on personal preference to some extent.
def create_radio_button(name, value)
Recommend the above over the other option here, because I can see from the context that we are talking about a radio button so the "rb_" prefix is redundant information, it is already duplicated in the function name.
The comment about variable names being searchable I guess refers to the poor practice of using a variable name such as p, where you might want to search or highlight the variable name, resulting in the annoyance of finding any word containing a p. This issue doesn't apply so much here, "name" and "value" would be searchable enough*.
* This last point is somewhat moot for people using a decent editor, where we can refactor/rename a symbol and the IDE should be smart enough to know where the usages are in context/scope
This is a more general question than just python. The parameter name should describe its role as concisely as possible (so I would just use "name" and "value" in your example).
Of course, this doesn't replace actual documentation, for which I would recommend the somewhat standard tags
:param name: description
:param value: description
(you can also add the expected type of the parameter before its name in the above)
In general, the function should be relatively short, so it is fairly obvious that 'name' is a parameter to the function.
I think using the rb_ prefix would only make sense for global variables, which, in a python application, should be pretty rare (better use class variables).
Related
My question is quite general, but for clarity I'd like to give an example that is as concrete as possible: I was lately writing a class, which was derived from a matplotlib artist. A minimal working example would be the following:
from matplotlib import text
class TextChild(text.Text):
def __init__(self):
self._rotation = self.get_rotation()
The idea behind using an underscore self._rotation was to show the potential user not to access that attribute directly (i.e. to label it private). This turned out to be a bad idea, because text.Text also has an attribute called _rotation and I got very surprising results.
There are, of course, ways to deal with this.
One is to use a different attribute name, say, self._rotation2, but
the base class may be subject to change in the future, possibly
introducing new attributes and with a bit of bad luck names might
again match, which would break the derived class.
Another solution would be to use name mangling, i.e.
self.__rotation (the solution I chose). From what I understood,
however, name mangling should be used as sparsely as possible and if
I have many private attributes there will be a lot of double
underscores in the code.
So here is the question: Is there a preferred way of naming private class attributes when deriving from a class out of my own control that may change in the future?
Is there a preferred way of naming private class attributes when deriving from a class out of my own control that may change in the future?
It's really difficult to tell how you should choose the name of identifiers in your code, this is open to you. Generally speaking, it's your job as a programmer to avoid name collisions, some advanced IDEs can aide in this process.
For you question I believe using name mangling will definitely avoid name collisions somehow, this won't litter your code with underscores as you might think given that you use this feature wisely. If you're using a lot of redundant names, it's better to choose unique names instead. It's generally acceptable to use __name for attributes that you would like to ensure that they belong to their classes and please remember private in Python isn't really private, it's really pseudo-private. You'll still be able to access those attributes.
Here's one trick that you can use to avoid name collisions:
>>> "name" in dir(Foo)
True
So if name is already there in the namespace of class Foo, you would know from this single line and to get a list of all the attributes of class Foo just call dir with Foo as its argument: dir(Foo).
Mainly this is a design issue, but if I were in your position I'd opt to check with dir to ensure the uniqueness of my names to avoid overriding other names unintentionally. For example, if you read the codes of Python standard library, in many places the use of _name naming convention to denote this name should not be directly accessed from outside the class is pretty obvious.
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
without explicit (type) declaration I struggle to try to figure out how things work --- are there some good thumbs of rule/tips that you may have for reading python code better? Thanks!
In spite of the first impression that this question gives, I think it is indeed really intelligent because it reveals that you are subconscious of something that should interest any Python's developper but that I find very neglected in general and in explanations in particular, if not misunderstood.
I mean that IMO the base of Python is terrificly quaint and intelligent: it's the data model on which it has been conceived.
In this Python's data model, there are no variables in the sense of "chunks of memory whose contents can change", contrary to other languages, and in the sense that we don't manage this precise kind of variables in Python.
More precisely, all is object in Python, and every object is named and designed with an identifier, but neither the object nor the identifier are 'variables' in the said sense.
That doesn't mean that there are no little boxes, so called variables in other languages, temporarily hosting values that go in and out of them, in the depthes of the implementation.
.
Say an object is designed with the identifier XYA2.
Personally I use this appearance of letters to designate any identifier. An identifier is nothing else than a word written in a code. It is what appears in a code.
Note that this appearance of letters is the one used by this stackoverflow.com site to represent a code sample inside text, by clicking on the button {}. That's easy to remind.
Now, the object whose name is XYA2 is a real thing, a concrete set of bits lying in the memory of the computer to represent the desired conceptual value that it stands for.
This set is defined in C language in which Python is implemented.
Personnaly, I bold the letters when I want to designate an object.
Then the object of name XYA2 is, for me, refered to by XYA2
The identifier is XYA2
It is linked to an underlying and inaccessible pointer that points to the object.
This link is done by means of the symbol table. You will see very few references or allusions to symbol table in general, here on stackoverflow or elsewhere. However it's very important, I think.
The pointer linked to the identifier XYA2 points to the object XYA2
So, XYA2 is directly linked to the pointer and indirectly linked to the object.
Instead of saying "indirectly linked", we say "assigned". An object and its identifier are reciprocally assigned one to the other, but the medium of this link is the underlying pointer.
.
And now, something important.
Strictly speaking, a variable is a "chunk of memory whose content can change".
I personally do efforts to never use the word 'variable' in an other sense that this one.
The problem is that, because of the use of the word 'variable' in mathematics, this word is very often used indiscriminately and thrown in all the wind's directions by many developpers (not all) even when it isn't justified.
Thereby, it is commonly used by nearly everybody to designates the names, aka the identifiers in a code. But this practice is horribly confusing. It should be carefully avoided.
That said, an object in Python is not only an instance of some class, it is above all a concrete set of bits; set which IS NOT, as far as I know, a variable, in the sense of "chunk of memory whose content can change".
Hence my opinion that there aren't variables in Python, since the only entities we can access to and manipulate are identifiers and objects.
However, the processes under the hood in an executed Python program use quantities of pointers that are, as far as I know, real variables in the strict sense of this word.
So, in a sense, it could be said that my affirmation 'There are no variables in Python" is false.
It's a matter of point of view.
As a developer in Python, conceptually speaking, I don't manage variables. When I think to an algorithm, I don't think at the level of the pointers, even if I know they exist and that it's very important to know they exist. Being not at the level of the variables, but at the level of the Python's data model, I don't see why I should accept to believe that there are variables in a Python program. There are variables at the machine low-level, and Python is a very-high-level language.
.
Why did I write all this ?
1)
because the nature of the Python's data model has quantities of consequences that can't be understood if this data model isn't known. Among these consequences, some are interesting because they give incredible possibilities, others are traps (a well known example is: modifying an element in a copied list modifies also the element in the original list). That's why it's of first importance to learn about this data model.
For that, I recommend you to read these parts of the documentation:
3.1 of objects-values-and-types
4.1 of naming-and-binding
.
2)
To justify my answer to your perplexity: don't struggle about what happens under the hood:
there's a garbage colector, a reference counter, wagons of underlying dictionaries-like entities, a thunderous ballet of values in the secret of the underlying pointers, many verifications made by the interpreter... When something doesn't fit well , warning is given in the form of exception's messages.
Python has all the machinery under control
The only concern you must have is to think about the algorithm you want to achieve, and for that, knowing the data model is essential.
Welcome in the Python universe
Warning
I don't consider myself as a very skilled Python developper, I'm just an amateur who had a lot of problems before understanding some essential things about Python.
All the above description is my personal views about the data model of Python. If any point is incorrect in this description, I will be happy to learn more about it if the teaching is done with developped argumentation.
But I underline the fact that this vision of things allows me to understand and to answer to a lot of tough problems and to achieve some tricky mechanisms that Python is capable of. So, all can't be false in this above description.
You should take a look at PEP8 documentation This describes the Python formatting and style.
Read up on Duck Typing. One of the purposes of Duck Typing is that you shouldn't be thinking too much about the type of something anyway. What really concerns you is that the the variable can be used the way that you want it.
In Python, you don't need a type declaration because the name you assign is just a pointer to an object, and furthermore it can change at any time.
a = None
a = 1+5
a = my_function() # calls my function and assigns the return object to a
a = my_function # Assigns the function itself to a. You could actually pass it as a parameter
a = MyClass() # Runs the __init__() function of the class and assigns the return value to a
a = MyClass # Assigns the class itself to a.
This is all valid Python. You could run this sequentially, although changing up the type is frowned upon unless its totally clear as to why.
if you know the c++11 then it is similer to auto type.
The variable type is decided on the bases of its assignment.
I recently posted a question on stackoverflow and I got a resolution.
Some one suggested to me about the coding style and I haven't received further input. I have the following question with reference to the prior query.
How can we declare private variables inside a class in python? I thought that by using a double underscore (__) the variable is treated as private. Please correct me.
As per the suggestion received before, we don't have to use a getter or setter method. Shouldn't we use a getter or setter or both? Please let me know your suggestion on this one.
Everything is public in Python, the __ is a suggestion by convention that you shouldn't use that function as it is an implementation detail.
This is not enforced by the language or runtime in any way, these names are decorated in a semi-obfuscated way, but they are still public and still visible to all code that tries to use them.
Idiomatic Python doesn't use get/set accessors, it is duplication of effort since there is no private scope.
You only use accessors when you want indirect access to a member variable to have code around it, and then you mark the member variable with __ as the start of its name and provide a function with the actual name.
You could go to great lengths with writing reams of code to try and protect the user from themselves using Descriptors and meta programming, but in the end you will end up with more code that is more to test and more to maintain, and still no guarantee that bad things won't happen. Don't worry about it - Python has survived 20 years this way so far, so it can't be that big of a deal.
PEP 8 (http://www.python.org/dev/peps/pep-0008/) has a section "Designing for inheritance" that should address most of these concerns.
To quote:
"We don't use the term "private" here, since no attribute is really
private in Python (without a generally unnecessary amount of work)."
Also:
"If your class is intended to be subclassed, and you have attributes
that you do not want subclasses to use, consider naming them with
double leading underscores and no trailing underscores."
If you've not read the entire section, I would encourage you to do so.
Update:
To answer the question (now that the title has changed). The pythonic way to use private variables, is to not use private variables. Trying to hide something in python is seldom seen as pythonic.
You can use Python properties instead of getters and setters. Just use an instance attribute and when you need something more complex, make this attribute a property without changing too much code.
http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/
Private variables:
If you use the double underscore at the beginning of your class members they are considered to be private, though not REALLY enforced by python. They simply get some naming tacked on to the front to prevent them from being easily accessed. Single underscore could be treated as "protected".
Getter/Setter:
You can use these if you want to do more to wrap the process and 'protect' your 'private' attributes. But its, again, not required. You could also use Properties, which has getter/setter features.
1) http://docs.python.org/tutorial/classes.html#private-variables
“Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member). It should be considered an implementation detail and subject to change without notice.
(continue reading for more details about class-private variables and name mangling)
2) http://docs.python.org/library/functions.html#property
In generally I'm using the standard naming stated in PEP-8 for variables. Like:
delete_projects
connect_server
However sometimes I can't find any good name and the name just extend to a long one:
project_name_to_be_deleted
I could use pr_nm_del , but this makes the code unreadable. I'm really suffering finding good variable names for functions. Whenever I begin to write a new function I just spent time to find a good variable name.
Is there any standard for choosing certain abbreviations for well known variable names like, delete,project,configuration, etc. ? How do you choose short but good and readable variable names ?
This question might be not depend directly to Python, but as different programming languages uses different variable names formatting I thought I limit this question to Python only.
pr_nm_del? You might as well let a cat name it. I believe abbreviations should be avoided at all cost, except well-known/obvious ones (like del, as mentioned in the comments - that one's even a language keyword!) that save a whole lot of typing.
But that doesn't mean overly verbose identifiers. Just as context is important to understand statements in natural languages, identifiers can often be kept much shorter (and just as understandable) by referring to context. In your example, project_name is perfectly fine - the procedure is already called delete_project, so project_name obviously refers to the name of the project to be deleted. Even name alone might be fine. No need to state that again by appending _to_be_deleted.
In your example, you have a function called delete_project. Wondering what to call the variable that stores the project to be deleted? Just 'project'!
def delete_project(self, project):
del self.projects[project]
Simple.
Variable names don't have to be fully descriptive. Context can lend a lot to how we understand a particular name at a particular point in time. No need to say "this is the project to be deleted" when discussing a function that deletes project.
If you find function names are too long, they're probably doing too much. If you find variable names are becoming too long, think about their purpose in the current context, and see if part of the name can be implied.
This is a problem that kind of solves itself when you're doing OOP. The subject (project, configuration) is the class and the verb (delete, etc) is the method name ie:
class Workspace(object):
def delete_project(self, project):
log.info("Deleting", project.name)
...
I think long names are acceptable provided that they are descriptive. With a good editor/IDE, short names cannot save typing, while long but descriptive names can save the time of reading your code. So the length of the reading time of the name is much more important than the actual length of the name.
As for your example, project_name_to_be_deleted is fine. If you want to shorten it, I will suggest using project_name_to_del since del is a well-known abbreviation for delete (you can even find this in your keyboard). And the use conf as configuration is also popular. But don't go further. For example, proj2del is not a good idea.
Also, for internal/local things, it's fine to use short-not-so-descriptive names.
Very few names have "standard" abbreviations. What you think is "common" or "standard" is not the same for someone else.
The time spent setting a good name is well invested, as code is read much more often than it is written.
As an example, I've seen
"configuration"
abbreviated as
"config"
"cnfg"
"cfg"
"cnf"
...so the lesson is - don't abbreviate unless there is a very well known abbreviation of it!
My karate instructor is fond of saying, "a block is a lock is a throw is a blow." What he means is this: When we come to a technique in a form, although it might seem to look like a block, a little creativity and examination shows that it can also be seen as some kind of joint lock, or some kind of throw, or some kind of blow.
So it is with the way the django template syntax uses the dot (".") character. It perceives it first as a dictionary lookup, but it will also treat it as a class attribute, a method, or list index - in that order. The assumption seems to be that, one way or another, we are looking for a piece of knowledge. Whatever means may be employed to store that knowledge, we'll treat it in such a way as to get it into the template.
Why doesn't python do the same? If there's a case where I might have assigned a dictionary term spam['eggs'], but know for sure that spam has an attribute eggs, why not let me just write spam.eggs and sort it out the way django templates do?
Otherwise, I have to except an AttributeError and add three additional lines of code.
I'm particularly interested in the philosophy that drives this setup. Is it regarded as part of strong typing?
django templates and python are two, unrelated languages. They also have different target audiences.
In django templates, the target audience is designers, who proabably don't want to learn 4 different ways of doing roughly the same thing ( a dictionary lookup ). Thus there is a single syntax in django templates that performs the lookup in several possible ways.
python has quite a different audience. developers actually make use of the many different ways of doing similar things, and overload each with distinct meaning. When one fails it should fail, because that is what the developer means for it to do.
JUST MY correct OPINION's opinion is indeed correct. I can't say why Guido did it this way but I can say why I'm glad that he did.
I can look at code and know right away if some expression is accessing the 'b' key in a dict-like object a, the 'b' attribute on the object a, a method being called on or the b index into the sequence a.
Python doesn't have to try all of the above options every time there is an attribute lookup. Imagine if every time one indexed into a list, Python had to try three other options first. List intensive programs would drag. Python is slow enough!
It means that when I'm writing code, I have to know what I'm doing. I can't just toss objects around and hope that I'll get the information somewhere somehow. I have to know that I want to lookup a key, access an attribute, index a list or call a method. I like it that way because it helps me think clearly about the code that I'm writing. I know what the identifiers are referencing and what attributes and methods I'm expecting the object of those references to support.
Of course Guido Van Rossum might have just flipped a coin for all I know (He probably didn't) so you would have to ask him yourself if you really want to know.
As for your comment about having to surround these things with try blocks, it probably means that you're not writing very robust code. Generally, you want your code to expect to get some piece of information from a dict-like object, list-like object or a regular object. You should know which way it's going to do it and let anything else raise an exception.
The exception to this is that it's OK to conflate attribute access and method calls using the property decorator and more general descriptors. This is only good if the method doesn't take arguments.
The different methods of accessing
attributes do different things. If
you have a function foo the two lines
of code
a = foo,
a = foo()
do two
very different things. Without
distinct syntax to reference and call
functions there would be no way for
python to know whether the variable
should be a reference to foo or the
result of running foo. The () syntax removes the ambiguity.
Lists and dictionaries are two very different data structures. One of the things that determine which one is appropriate in a given situation is how its contents can be accessed (key Vs index). Having separate syntax for both of them reinforces the notion that these two things are not the same and neither one is always appropriate.
It makes sense for these distinctions to be ignored in a template language, the person writing the html doesn't care, the template language doesn't have function pointers so it knows you don't want one. Programmers who write the python that drive the template however do care about these distinctions.
In addition to the points already posted, consider this. Python uses special member variables and functions to provide metadata about the object. Both the interpreter and programmers make heavy use of these. For example, both dicts and lists have a __len__ member function. Now, if a dict's data were accessed by using the . operator, a potential ambiguity arises if the dict has a key called __len__. You could special-case these, but many objects have a __dict__ attribute which is a mapping of member names and values. If that object happened to be a container, which also defined a __len__ attribute, you would end up with an utter mess.
Problems like this would end up turning Python into a mishmash of special cases that the programmer would have to constantly be aware of. This would detract from the reason why many people use Python in the first place, i.e., its elegant simplicity.
Now, consider that new users often shadow built-ins (if the code in SO questions is any indication) and having something like this starts to look like a really bad idea, since it would exacerbate the problem many-fold.
In addition to the responses above, it's not practical to merge dictionary lookup and object lookup in general because of the restrictions on object members.
What if your key has whitespace? What if it's an int, or a frozenset, etc.? Dot notation can't account for these discrepancies, so while it's an acceptable tradeoff for a templating language, it's unacceptable for a general-purpose programming language like Python.