I have always wondered why can't we use hyphens in between function names and variable names in python
Having tried functional programming languages like Lisp and Clojure, where hyphens are allowed. Why python doesn't do that.
# This won't work -- SyntaxError
def is-even(num):
return num % 2
# This will work
def is_even(num):
return num % 2
I am sure Sir Guido must have done this because of some reasons. I googled but couldn't manage to find the answer. Can anyone please throw some light on this?
Because hyphen is used as the subtraction operator. Imagine that you could have an is-even function, and then you had code like this:
my_var = is-even(another_var)
Is is-even(another_var) a call to the function is-even, or is it subtracting the result of the function even from a variable named is?
Lisp dialects don't have this problem, since they use prefix notation. For example, there's clear difference between
(is-even 4)
and
(- is (even 4))
in Lisps.
Because Python uses infix notation to represent calculations and a hyphen and a minus has the exact same ascii code. You can have ambiguous cases such as:
a-b = 10
a = 1
b = 1
c = a-b
What is the answer? 0 or 10?
Because it would make the parser even more complicated. It would be confusing too for the programmers.
Consider def is-even(num): : now, if is is a global variable, what happens?
Also note that the - is the subtraction operator in Python, hence would further complicate parsing.
is-even(num)
contains a hyphen ? I thought it was a subtraction of the value returned by function even with argument num from the value of is.
As #jdupont says, parsing can be tricky.
Oddly enough it is possible to have class variable names with hyphens using setattr(), not that you would want to. Here is an example:
class testclass:
pass
x = testclass()
setattr(x, "is-even", True)
getattr(x, "is-even")
True
This still fails:
x.is-even
File "<stdin>", line 1
x.is-even
^
SyntaxError: invalid syntax
Related
I'm learning Python and, so far, I absolutely love it. Everything about it.
I just have one question about a seeming inconsistency in function returns, and I'm interested in learning the logic behind the rule.
If I'm returning a literal or variable in a function return, no parentheses are needed:
def fun_with_functions(a, b):
total = a + b
return total
However, when I'm returning the result of another function call, the function is wrapped around a set of parentheses. To wit:
def lets_have_fun():
return(fun_with_functions(42, 9000))
This is, at least, the way I've been taught, using the A Smarter Way to Learn Python book. I came across this discrepancy and it was given without an explanation. You can see the online exercise here (skip to Exercize 10).
Can someone explain to me why this is necessary? Is it even necessary in the first place? And are there other similar variations in parenthetical syntax that I should be aware of?
Edit: I've rephrased the title of my question to reflect the responses. Returning a result within parentheses is not mandatory, as I originally thought, but it is generally considered best practice, as I have now learned.
It's not necessary. The parentheses are used for several reason, one reason it's for code style:
example = some_really_long_function_name() or another_really_function_name()
so you can use:
example = (some_really_long_function_name()
or
another_really_function_name())
Another use it's like in maths, to force evaluation precede. So you want to ensure the excute between parenthese before. I imagine that the functions return the result of another one, it's just best practice to ensure the execution of the first one but it's no necessary.
I don't think it is mandatory. Tried in both python2 and python3, and a without function defined without parentheses in lets_have_fun() return clause works just fine. So as jack6e says, it's just a preference.
if you
return ("something,) # , is important, the ( ) are optional, thx #roganjosh
you are returning a tuple.
If you are returning
return someFunction(4,9)
or
return (someFunction(4,9))
makes no difference. To test, use:
def f(i,g):
return i * g
def r():
return f(4,6)
def q():
return (f(4,6))
print (type(r()))
print (type(q()))
Output:
<type 'int'>
<type 'int'>
Why is code like
if a = "hello":
pass
invalid in Python? The a = "Hello" is just a expression whose value is the Rvalue. It's valid in most languages like C or php. Some opinions?
While Python will allow you to chain assignment,
a = b = "hello"
it will not allow you to use it in an expression,
"hi" > b = "hello" # => Syntax error
This is for safety, to keep you from accidentally using = when you meant ==
This is intentionally made illegal in python as allowing it is a huge source of error and making it illegal is a minor inconvenience.
See the Design and History FAQ
My experience in python is that this is basically right. I rarely miss not being able to do this.
Consider this example of a function (and its use) that receives one parameter which is only meaningful as int:
def fun(index):
index = int(index)
# do something with index
def main():
print fun(1e6)
I find that I keep repeating this pattern on several functions that deal with integers since it ensures that I really receive some integer number (note that 1e6 is a floating point instance).
This is a bit cumbersome and if forgotten once it could produce problems (there is code that reacts differently to floating-point/integer/string/... values). So could this be somehow encoded in the function signature?
E.g. something along the lines of this pseudo-code:
def fun(int index):
# do something with index
First of all, you shouldn't really be doing this (even though some days I kind of want to as well…). Python is not statically-typed, so you shouldn't really be introducing cludgy static-typing.
Buuut, to answer you question. Decorators:
def ensure_int(fn):
def wrapper(num):
return fn(int(num))
return wrapper
def test(num):
return num + 2
#ensure_int
def test2(num):
return num + 2
Works like:
> test("2")
ERROR!!!
>test2("2")
4
In Python 3 you could use function annotations and then write a decorator that converts (or tries to convert) arguments to the types you specify.
In Python 2 you can't do this in the way you seem to want. Python 2's syntax doesn't support putting anything in the function definition except the arguments themselves, and you can't alter Python's syntax to let you put types in there as well.
I have a python specific question. What does a single underscore _ as a parameter means?
I have a function calling hexdump(_). The _ was never defined, so I guess it has some special value, I could not find a reference telling me what it means on the net. I would be happy if you could tell me.
From what I've been able to figure out, it seems like this is the case:
_ is used to indicate that the input variable is a throwaway variable/parameter and thus might be required or expected, but will not be used in the code following it.
For example:
# Ignore a value of specific location/index
for _ in range(10)
print("Test")
# Ignore a value when unpacking
a,b,_,_ = my_method(var1)
(Credit to this post)
The specific example I came across was this:
def f(_):
x = random() * 2 - 1
y = random() * 2 - 1
return 1 if x ** 2 + y ** 2 < 1 else 0
In Python shells, the underscore (_) means the result of the last evaluated expression in the shell:
>>> 2+3
5
>>> _
5
There's also _2, _3 and so on in IPython but not in the original Python interpreter. It has no special meaning in Python source code as far as I know, so I guess it is defined somewhere in your code if it runs without errors.
underscore is considered a 'don't care' variable, furthermore IDEs like PyCharm will not give a warning for it if it is unused
so in a function
def q(a, b, _, c):
pass
the IDE will underline a,b and c (unused parameter) but not the underscore
why would you use it and not omit the parameter?
->when you inherit from some class and want to override a function where you don't want to use some parameter
other common use is to indicate you don't want to use a part of a tuple when you iterate (or other unpacking) - this reduces clutter
names_and_food = [('michael', 'fruit'), ('eva', 'vegetables')]
for name, _ in names_and_food:
print(name)
I cant find it in any python PEP, but pylint has it even in the FAQ
It doesn't have a special value in the code you write. It stores the result of the last expression you evaluated in your interactive interpreter and is used for convenience
def isBig(x):
if x > 4:
return 'apple'
else:
return 'orange'
This works:
if isBig(y): return isBig(y)
This does NOT work:
if fruit = isBig(y): return fruit
Why doesn't the 2nd one work!? I want a 1-liner. Except, the 1st one will call the function TWICE.
How to make it 1 liner, without calling the function twice?
Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), it's now possible to capture the condition value (isBig(y)) as a variable (x) in order to re-use it within the body of the condition:
if x := isBig(y): return x
I see somebody else has already pointed to my old "assign and set" Cookbook recipe, which boils down in its simplest version to:
class Holder(object):
def set(self, value):
self.value = value
return value
def get(self):
return self.value
h = Holder()
...
if h.set(isBig(y)): return h.get()
However, this was intended mostly to ease transliteration between Python and languages where assignment is directly supported in if or while. If you have "hundreds" of such check-and-return in a cascade, it's much better to do something completely different:
hundreds = isBig, isSmall, isJuicy, isBlah, ...
for predicate in hundreds:
result = predicate(y)
if result: return result
or even something like
return next(x for x in (f(y) for f in hundreds) if x)
if it's OK to get a StopIteration exception if no predicate is satisfied, or
return next((x for x in (f(y) for f in hundreds) if x)), None)
if None is the proper return value when no predicate is satisfied, etc.
Almost invariably, using (or even wishing for;-) the Holder trick/non-idiom is a "design smell" which suggests looking for a different and more Pythonic approach -- the one case where Holder is justified is exactly the special case for which I designed it, i.e., the case where you want to keep close correspondence between the Python code and some non-Python (you're transliterating a reference algorithm in Python and want it working first before refactoring it into a more Pythonic form, or you're writing Python as a prototype that will be transliterated into C++, C#, Java, etc, once it's working effectively).
The one liner doesn't work because, in Python, assignment (fruit = isBig(y)) is a statement, not an expression. In C, C++, Perl, and countless other languages it is an expression, and you can put it in an if or a while or whatever you like, but not in Python, because the creators of Python thought that this was too easily misused (or abused) to write "clever" code (like you're trying to).
Also, your example is rather silly. isBig() will always evaluate to true, since the only string that's false is the empty string (""), so your if statement is useless in this case. I assume that's just a simplification of what you're trying to do. Just do this:
tmp = isBig(y)
if tmp: return tmp
Is it really that much worse?
You could use a generator:
def ensure(x):
if x: yield x
for fruit in ensure(isBig(y)):
return fruit
If you want to code in PHP (or C), code in it. Don't try to force its methods onto another language.
One of the basic tenets behind Python (in my opinion) is its readability. You should be using:
fruit = isBig(y)
if fruit: return fruit
I should also mention that your use of isXXX() is very strange; it's usually used to return boolean values. Especially in this case where you're using it in an IF statement.
The problem is that the assignment operation cannot be evaluated as having a boolean value. The if statement relies on being able to evaluate a boolean. For example,
>>> fruit = 'apple'
>>> bool(fruit = 'apple')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/Users/jem/<ipython console> in <module>()
TypeError: 'fruit' is an invalid keyword argument for this function
>>> bool('a')
True