The Python programming language is often considered the most beautiful language for computer programming. It offers a simple syntax, good abstraction facilities, dynamic typing, powerful built-in modules, an object-oriented design, and a large ecosystem of open source libraries. The language is popular and used in many different industries, ranging from web development to scientific computing.
Python is Case Sensitive When Dealing with Identifiers?
The Python language is case-sensitive. Identifiers, keywords, and names of classes must be written in lowercase letters. However, Python allows developers to write in uppercase letters for constants (i.e. variables that have a value assigned to them during program execution), and for built-in functions, and for class and module names, etc.
The identifier is case sensitive, so “foo”, “FOO” and “foo” are different variables. This is a very basic Python thing.
If you have to work in legacy code, you can often use the underscore character in a variable name. So, instead of “foo” or “foo_bar”, you’d use “__foo”. However, that is not a recommended practice. There’s nothing wrong with using the underscore in variable names, but it is not idiomatic and it may confuse people reading the code.
When using the _ character in a variable name, the identifier is not case sensitive. So, “Foo” and “FOO” are both the same variable.
This case sensitivity of identifiers is a very useful feature. For example, consider the following code:
if __name__ == '__main__':
...
if name == 'BRANDI'
This code does not raise any error because the identifier name is treated as a constant, but not as a variable. This feature is sometimes referred to as “camel case” or “snake case”.
Python has a special function called eval() which evaluates a string and returns the resulting object. It should be noted that it is possible to use eval() to run arbitrary Python code. In order to protect against code injection attacks, it is possible to restrict the use of eval() by wrapping it in a try…except block.
However, using eval() can sometimes lead to security issues. For example, consider the following snippet of code:
eval("print('Hello')")
The eval() function executes the given statement without any restrictions. Thus, it is possible to run malicious code in the interpreter. If the user input contains a malicious payload (for example, a string with an embedded shell command), it may be executed by the interpreter.
When writing Python code, it is therefore important to avoid using eval(). Instead, it is recommended to use the safer alternatives such as exec(), eval(compile(source, filename, ‘exec’)) and eval(source, locals()).
In addition, there are several language features that make it easier to identify and fix security bugs. Some of these features include the import mechanism, which enables programmers to import a module (i.e. a collection of Python code) from another file, and the try…finally statement, which ensures that resources are released even in the case of exceptions.
Python has an exception to this rule. The “self” keyword indicates that the identifier refers to the current object. So, “self.myVar” refers to the myVar attribute of the current object, while “self.foo” refers to the foo attribute of the current object.
This is a very basic Python thing. The rule applies to all Python identifiers, including built-in functions and classes, and also to variables.
In other words, if you write
>>> def foo(bar):
... print "BAR IS %s" % bar
...
Then the output is BAR IS bar. This is not surprising, as you have a variable named bar that corresponds to the parameter bar of the function.
On the other hand, if you try to pass the name of a variable into a function, then Python makes no attempt to preserve case:
>>> def foo(bar):
... print "BAR IS %s" % bar
... bar = 'baz'
...
Then the output is:
BAR IS baz
This is also not surprising, since the only thing that changed here was the value of bar. If you change the name of the variable bar to Baz, then you get the same result:
>>> def foo(Baz):
... print "BAR IS %s" % Baz
... Baz = 'baz'
...
The problem here is that the function foo doesn’t know what to do with the name Baz. There is no variable in the local scope called Baz, and so the call to print fails. If you want to preserve the case of the names of variables that are passed to functions, then you need to use the argument keyword:
>>> def foo(bar, Baz):
... print "BAR IS %s" % bar
... print "BAZ IS %s" % Baz
...
Now you get the correct results:
>>> foo('Foo', 'bar')
BAR IS Foo
BAZ IS bar
The problem is that the function now requires two parameters. A new argument is required to hold the name of the variable that is passed in as an argument. In order to accept two arguments, you need to change the function signature to accept the names of both the argument and the local variables:
>>> def foo(*args, **kwargs):
... print "BAR IS %s" % args[0]
... print "BAZ IS %s" % kwargs['Baz']
...
You can also create a dictionary with the keys bar and Baz and use that to pass in the values:
>>> def foo(*args, **kwargs):
... print "BAR IS %s" % kwargs.get('bar', '')
... print "BAZ IS %s" % kwargs.get('Baz', '')
...
>>> foo(bar='Foo', Baz='bar')
BAR IS Foo
BAZ IS bar
A third alternative is to use the star (*) notation to indicate that the arguments are optional. Then you can simply omit the argument for bar:
>>> def foo(*args, **kwargs):
... print "BAR IS %s" % kwargs.get('Baz', '')
...
>>> foo()
BAR IS None
>>> foo('foo', 'bar')
BAR IS foo
>>> foo('foo')
BAR IS foo
But this is not recommended. It’s better to stick to the second or third alternatives, which are clearly more robust.
In addition to being case-sensitive with identifiers, Python is also case-insensitive with strings. So when you pass in the string ‘Foo’ to the function, then the function can find and use the variable of the same name:
>>> def foo(bar):
... print "BAR IS %s" % bar
...
>>> foo('Foo')
BAR IS Foo
Note that in this example, the parameter bar is implicitly converted to a string. This is because the function expects a string. However, there is also the possibility that a user might pass in a variable of type str, in which case the variable would be assigned to the argument bar and then the function would see that the variable bar is of type str and so it could use it as a string.
In conclusion, You must keep in mind that Python is case sensitive when dealing with identifiers. This means that if you want to use a variable name that matches the actual name of your identifier, you have to ensure that you’re using that name in lowercase. If you’re working with other people or on a team, you may want to choose a naming convention that makes it easier to figure out what variable names refer to, for instance, always use upper case for your variable names.