How can repetitive variable checking be streamlined? - python

I often have to execute some function, save the output, and depending on what the output was, do different things. And then later on use the output as input to more functions.
It results in a very specific pattern of code.
I feel like I'm missing something simple.
... as if some logic here could be somehow streamlined. The variable declaration, variable checking, and forthcoming execution of other stuff onto said variable seems almost redundant.
(tried to make the code as applicable to everyone and as applicable to every application, as possible)
here's some sample code that fits this predicament:
some_sort_of_data=validate(var1, 'type1')
if some_sort_of_data.is_bad:
return some_sort_of_data.is_bad
more_data=validate(var2, 'type2')
if more_data.is_bad:
return more_data.is_bad
get_special_info=get_parent_of_item(some_sort_of_data.validated_item)
if get_special_info['error']:
return get_special_info['data']
if not (has_access_rights() or
special_relationship(more_data.validated_item) or
some_sort_of_other_permissions(get_special_info['result'])):
return "Blah Blah blah some sort of incompatibility"
new_status_result=change_status(some_sort_of_data.validated_item, more_data.validated_item)
if new_status_result['error']
return new_status_result['result']
# If we've passed all the previous checks and managed to get all the way here..
return "yay did a thing successfully"
... is it just me or do you also see how such a pattern feels off? If so, how can it best be streamlined?
edit: I know in some other languages you can streamline it a bit by writing
if (some_sort_of_data=validate(var1, 'type1')=="success")
return some_sort_of_data.some_class_variable
instead of
some_sort_of_data=validate(var1, 'type1')
if some_sort_of_data=="success":
return some_sort_of_data.some_class_variable
but that's still not enough and still quite redundant, right?

Related

What's the point of defining a function to print something?

For example, in my Codecademy it says,
def spam():
print ("Eggs!")
but I feel like you could just print Eggs! if you wanted without the def spam():
Somebody please help
But you could do:
def spam():
print("Eggs!")
And then call spam a thousand times in your code. Now, if you want to change that to print "Bacon!" you only have to change it once, rather than a thousand times.
def spam():
print("Bacon!")
Def helps to make your code reusable. In this case, we can think that it's useless indeed. But in other case, you'll want to be able to call a part of code multiple time !
In this case you're right, there is no reason to create a function for just print, but when you get to more complex writing a function saves you a lot of precious time and space. For example I want to get a specific part of a .json with API, instead of writing all these lines again and again I will write it once and call it whenever I need it.
Best practice would be to define the string once and call the function as many times as needed. It will be easier to maintain. Yes, you can find and replace all instances, but you risk accidentally changing more than you bargained for. Additionally, if you were working on a shared project and someone were to merge code after you made that change, you’d have to go back and update all their new code to reflect the change. If they had just been calling spam(), there’s no update needed post-merge.
Usually it is for demonstration/illustration purposes. Once the code flow reaches the function, you'll get the message printed. Sometimes it is important to understand the sequence of calling the functions or just the fact that the function has been called.

Best practice for using parentheses in Python function returns?

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'>

Using function return in if/else statement

I wanna to make my code look nicer.
Example:
result = somefunction()
if result == what_i_need:
do_something()
else:
print 'that\'s not what i need', result
I'm trying to make something like this:
if somefunction() == what_i_need:
do_something()
else:
print 'that\'s not what i need', <return value of somefunction>
Is this possible?
Here's something you could technically try, but shouldn't:
def somefunction():
val = 3 # calculate value
globals()['somefunction_return'] = val # store it in globals() first
return val # return as normal
def do_something():
print 'got it'
what_i_need = 3
if somefunction() == what_i_need:
do_something()
print 'that\'s not what i need', somefunction_return
# result:
#
# got it
# that's not what i need 3
Why shouldn't you do this?
The assignment is still happening somewhere else, so all its done is sweep the unwanted code out of the way. Pay no attention to the garbage behind the curtain.
Messing with globals() is more fragile than a simple assignment done in the way you're already doing it, partly because it's more difficult for the developer to avoid tripping over it.
It introduces something called "side effects," extra events that a function does without saying so. In this example, somefunction is doing something in addition to its planned purpose, without advertising as much. This makes code much harder to maintain.
It makes the code more difficult to read and follow, which goes against the intent of Python. Imagine that someone is reading the if structure above. How are they supposed to know where somefunction_return came from? They would have to look through every line of code until they found the offending side effect in somefunction. We might have even named it something else, like my_foobar_value, and then the reader wouldn't even have a hint that they should check somefunction.
Please continue to use the ordinary assignment you already have in place.
No, the only sensible way to capture a function's return value in Python is to explicitly assign it to a variable.
Even if there was a device for referring to a previous function's return value through implicit means, Python culture abhors this sort of thing. One oft-cited Python principle is "explicit is better than implicit".

Is it pointless to receive a parameter/argument and do nothing with it?

I'm learning python from a textbook. This code is for the game Tic-Tac-Toe.
The full source code for the problem:
http://pastebin.com/Tf4KQpnk
The following function confuses me:
def human_move(board, human):
""" Get human move."""
legal = legal_moves(board)
move = None
while move not in legal:
move = ask_number("Where will you move? (0 - 8): ", 0, NUM_SQUARES)
if move not in legal: print "\nThat square is already taken. Choose another.\n"
print "Fine..."
return move
I do not know why the function receives 'human' parameter. It appears to do nothing with it.
def human_move(board, human):
How would I know to send 'human' to this function if I were to write this game from scratch? Because I can't see why it is sent to this function if it isn't used or returned.
The answer: it depends. In your example it seems useless to me, but I haven't checked it in depth.
If you create a function to be used only from your code, it is in fact useless.
def calculate_money(bank_name, my_dog_name):
return Bank(bank_name).money
money = calculate_money('Deutsche bank', 'Ralph')
But if you are working with some kind of API/Contract, the callbacks you specify might accept arguments that are not needed for a certain implementation, but for some others, are necessary.
For instance, imagine that the following function is used in some kind of framework, and you want the framework to show a pop up when the operation is finished. It could look something like this:
def my_cool_callback(names, accounts, context):
# do something blablab
context.show_message('operation finished')
But what if you don't really need the context object in your callback? you have to speficy it anyway for the signature to match... You can't call it pointless because that parameter is used sometimes.
EDIT
Another situation in which it could be useful, would be to loop through a list of functions that have almost the same signature. In that case could be ok also to have extra arguments as "garbage placeholders". Let's say all your functions need 3 arguments in general, but one needs only 2.

Best practice for using assert?

Is there a performance or code maintenance issue with using assert as part of the standard code instead of using it just for debugging purposes?
Is
assert x >= 0, 'x is less than zero'
better or worse than
if x < 0:
raise Exception('x is less than zero')
Also, is there any way to set a business rule like if x < 0 raise error that is always checked without the try/except/finally so, if at anytime throughout the code x is less than 0 an error is raised, like if you set assert x < 0 at the start of a function, anywhere within the function where x becomes less then 0 an exception is raised?
Asserts should be used to test conditions that should never happen. The purpose is to crash early in the case of a corrupt program state.
Exceptions should be used for errors that can conceivably happen, and you should almost always create your own Exception classes.
For example, if you're writing a function to read from a configuration file into a dict, improper formatting in the file should raise a ConfigurationSyntaxError, while you can assert that you're not about to return None.
In your example, if x is a value set via a user interface or from an external source, an exception is best.
If x is only set by your own code in the same program, go with an assertion.
"assert" statements are removed when the compilation is optimized. So, yes, there are both performance and functional differences.
The current code generator emits no code for an assert statement when optimization is requested at compile time. - Python 2 Docs Python 3 Docs
If you use assert to implement application functionality, then optimize the deployment to production, you will be plagued by "but-it-works-in-dev" defects.
See PYTHONOPTIMIZE and -O -OO
To be able to automatically throw an error when x become less than zero throughout the function. You can use class descriptors. Here is an example:
class LessThanZeroException(Exception):
pass
class variable(object):
def __init__(self, value=0):
self.__x = value
def __set__(self, obj, value):
if value < 0:
raise LessThanZeroException('x is less than zero')
self.__x = value
def __get__(self, obj, objType):
return self.__x
class MyClass(object):
x = variable()
>>> m = MyClass()
>>> m.x = 10
>>> m.x -= 20
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "my.py", line 7, in __set__
raise LessThanZeroException('x is less than zero')
LessThanZeroException: x is less than zero
The four purposes of assert
Assume you work on 200,000 lines of code with four colleagues Alice, Bernd, Carl, and Daphne.
They call your code, you call their code.
Then assert has four roles:
Inform Alice, Bernd, Carl, and Daphne what your code expects.
Assume you have a method that processes a list of tuples and the program logic can break if those tuples are not immutable:
def mymethod(listOfTuples):
assert(all(type(tp)==tuple for tp in listOfTuples))
This is more trustworthy than equivalent information in the documentation
and much easier to maintain.
Inform the computer what your code expects.
assert enforces proper behavior from the callers of your code.
If your code calls Alices's and Bernd's code calls yours,
then without the assert, if the program crashes in Alices code,
Bernd might assume it was Alice's fault,
Alice investigates and might assume it was your fault,
you investigate and tell Bernd it was in fact his.
Lots of work lost.
With asserts, whoever gets a call wrong, they will quickly be able to see it was
their fault, not yours. Alice, Bernd, and you all benefit.
Saves immense amounts of time.
Inform the readers of your code (including yourself) what your code has achieved at some point.
Assume you have a list of entries and each of them can be clean (which is good)
or it can be smorsh, trale, gullup, or twinkled (which are all not acceptable).
If it's smorsh it must be unsmorshed; if it's trale it must be baludoed;
if it's gullup it must be trotted (and then possibly paced, too);
if it's twinkled it must be twinkled again except on Thursdays.
You get the idea: It's complicated stuff.
But the end result is (or ought to be) that all entries are clean.
The Right Thing(TM) to do is to summarize the effect of your
cleaning loop as
assert(all(entry.isClean() for entry in mylist))
This statements saves a headache for everybody trying to understand
what exactly it is that the wonderful loop is achieving.
And the most frequent of these people will likely be yourself.
Inform the computer what your code has achieved at some point.
Should you ever forget to pace an entry needing it after trotting,
the assert will save your day and avoid that your code
breaks dear Daphne's much later.
In my mind, assert's two purposes of documentation (1 and 3) and
safeguard (2 and 4) are equally valuable.
Informing the people may even be more valuable than informing the computer
because it can prevent the very mistakes the assert aims to catch (in case 1)
and plenty of subsequent mistakes in any case.
In addition to the other answers, asserts themselves throw exceptions, but only AssertionErrors. From a utilitarian standpoint, assertions aren't suitable for when you need fine grain control over which exceptions you catch.
The only thing that's really wrong with this approach is that it's hard to make a very descriptive exception using assert statements. If you're looking for the simpler syntax, remember you can also do something like this:
class XLessThanZeroException(Exception):
pass
def CheckX(x):
if x < 0:
raise XLessThanZeroException()
def foo(x):
CheckX(x)
#do stuff here
Another problem is that using assert for normal condition-checking is that it makes it difficult to disable the debugging asserts using the -O flag.
The English language word assert here is used in the sense of swear, affirm, avow. It doesn't mean "check" or "should be". It means that you as a coder are making a sworn statement here:
# I solemnly swear that here I will tell the truth, the whole truth,
# and nothing but the truth, under pains and penalties of perjury, so help me FSM
assert answer == 42
If the code is correct, barring Single-event upsets, hardware failures and such, no assert will ever fail. That is why the behaviour of the program to an end user must not be affected. Especially, an assert cannot fail even under exceptional programmatic conditions. It just doesn't ever happen. If it happens, the programmer should be zapped for it.
As has been said previously, assertions should be used when your code SHOULD NOT ever reach a point, meaning there is a bug there. Probably the most useful reason I can see to use an assertion is an invariant/pre/postcondition. These are something that must be true at the start or end of each iteration of a loop or a function.
For example, a recursive function (2 seperate functions so 1 handles bad input and the other handles bad code, cause it's hard to distinguish with recursion). This would make it obvious if I forgot to write the if statement, what had gone wrong.
def SumToN(n):
if n <= 0:
raise ValueError, "N must be greater than or equal to 0"
else:
return RecursiveSum(n)
def RecursiveSum(n):
#precondition: n >= 0
assert(n >= 0)
if n == 0:
return 0
return RecursiveSum(n - 1) + n
#postcondition: returned sum of 1 to n
These loop invariants often can be represented with an assertion.
Well, this is an open question, and I have two aspects that I want to touch on: when to add assertions and how to write the error messages.
Purpose
To explain it to a beginner - assertions are statements which can raise errors, but you won't be catching them. And they normally should not be raised, but in real life they sometimes do get raised anyway. And this is a serious situation, which the code cannot recover from, what we call a 'fatal error'.
Next, it's for 'debugging purposes', which, while correct, sounds very dismissive. I like the 'declaring invariants, which should never be violated' formulation better, although it works differently on different beginners... Some 'just get it', and others either don't find any use for it, or replace normal exceptions, or even control flow with it.
Style
In Python, assert is a statement, not a function! (remember assert(False, 'is true') will not raise. But, having that out of the way:
When, and how, to write the optional 'error message'?
This acually applies to unit testing frameworks, which often have many dedicated methods to do assertions (assertTrue(condition), assertFalse(condition), assertEqual(actual, expected) etc.). They often also provide a way to comment on the assertion.
In throw-away code you could do without the error messages.
In some cases, there is nothing to add to the assertion:
def dump(something):
assert isinstance(something, Dumpable)
# ...
But apart from that, a message is useful for communication with other programmers (which are sometimes interactive users of your code, e.g. in Ipython/Jupyter etc.).
Give them information, not just leak internal implementation details.
instead of:
assert meaningless_identifier <= MAGIC_NUMBER_XXX, 'meaningless_identifier is greater than MAGIC_NUMBER_XXX!!!'
write:
assert meaningless_identifier > MAGIC_NUMBER_XXX, 'reactor temperature above critical threshold'
or maybe even:
assert meaningless_identifier > MAGIC_NUMBER_XXX, f'reactor temperature({meaningless_identifier }) above critical threshold ({MAGIC_NUMBER_XXX})'
I know, I know - this is not a case for a static assertion, but I want to point to the informational value of the message.
Negative or positive message?
This may be conroversial, but it hurts me to read things like:
assert a == b, 'a is not equal to b'
these are two contradictory things written next to eachother. So whenever I have an influence on the codebase, I push for specifying what we want, by using extra verbs like 'must' and 'should', and not to say what we don't want.
assert a == b, 'a must be equal to b'
Then, getting AssertionError: a must be equal to b is also readable, and the statement looks logical in code. Also, you can get something out of it without reading the traceback (which can sometimes not even be available).
For what it's worth, if you're dealing with code which relies on assert to function properly, then adding the following code will ensure that asserts are enabled:
try:
assert False
raise Exception('Python assertions are not working. This tool relies on Python assertions to do its job. Possible causes are running with the "-O" flag or running a precompiled (".pyo" or ".pyc") module.')
except AssertionError:
pass
Is there a performance issue?
Please remember to "make it work first before you make it work fast".
Very few percent of any program are usually relevant for its speed.
You can always kick out or simplify an assert if it ever proves to
be a performance problem -- and most of them never will.
Be pragmatic:
Assume you have a method that processes a non-empty list of tuples and the program logic will break if those tuples are not immutable. You should write:
def mymethod(listOfTuples):
assert(all(type(tp)==tuple for tp in listOfTuples))
This is probably fine if your lists tend to be ten entries long, but
it can become a problem if they have a million entries.
But rather than discarding this valuable check entirely you could
simply downgrade it to
def mymethod(listOfTuples):
assert(type(listOfTuples[0])==tuple) # in fact _all_ must be tuples!
which is cheap but will likely catch most of the actual program errors anyway.
An Assert is to check -
1. the valid condition,
2. the valid statement,
3. true logic;
of source code. Instead of failing the whole project it gives an alarm that something is not appropriate in your source file.
In example 1, since variable 'str' is not null. So no any assert or exception get raised.
Example 1:
#!/usr/bin/python
str = 'hello Python!'
strNull = 'string is Null'
if __debug__:
if not str: raise AssertionError(strNull)
print str
if __debug__:
print 'FileName '.ljust(30,'.'),(__name__)
print 'FilePath '.ljust(30,'.'),(__file__)
------------------------------------------------------
Output:
hello Python!
FileName ..................... hello
FilePath ..................... C:/Python\hello.py
In example 2, var 'str' is null. So we are saving the user from going ahead of faulty program by assert statement.
Example 2:
#!/usr/bin/python
str = ''
strNull = 'NULL String'
if __debug__:
if not str: raise AssertionError(strNull)
print str
if __debug__:
print 'FileName '.ljust(30,'.'),(__name__)
print 'FilePath '.ljust(30,'.'),(__file__)
------------------------------------------------------
Output:
AssertionError: NULL String
The moment we don't want debug and realized the assertion issue in the source code. Disable the optimization flag
python -O assertStatement.py
nothing will get print
Both the use of assert and the raising of exceptions are about communication.
Assertions are statements about the correctness of code addressed at developers: An assertion in the code informs readers of the code about conditions that have to be fulfilled for the code being correct. An assertion that fails at run-time informs developers that there is a defect in the code that needs fixing.
Exceptions are indications about non-typical situations that can occur at run-time but can not be resolved by the code at hand, addressed at the calling code to be handled there. The occurence of an exception does not indicate that there is a bug in the code.
Best practice
Therefore, if you consider the occurence of a specific situation at run-time as a bug that you would like to inform the developers about ("Hi developer, this condition indicates that there is a bug somewhere, please fix the code.") then go for an assertion. If the assertion checks input arguments of your code, you should typically add to the documentation that your code has "undefined behaviour" when the input arguments violate that conditions.
If instead the occurrence of that very situation is not an indication of a bug in your eyes, but instead a (maybe rare but) possible situation that you think should rather be handled by the client code, raise an exception. The situations when which exception is raised should be part of the documentation of the respective code.
Is there a performance [...] issue with using assert
The evaluation of assertions takes some time. They can be eliminated at compile time, though. This has some consequences, however, see below.
Is there a [...] code maintenance issue with using assert
Normally assertions improve the maintainability of the code, since they improve readability by making assumptions explicit and during run-time regularly verifying these assumptions. This will also help catching regressions. There is one issue, however, that needs to be kept in mind: Expressions used in assertions should have no side-effects. As mentioned above, assertions can be eliminated at compile time - which means that also the potential side-effects would disappear. This can - unintendedly - change the behaviour of the code.
In IDE's such as PTVS, PyCharm, Wing assert isinstance() statements can be used to enable code completion for some unclear objects.
I'd add I often use assert to specify properties such as loop invariants or logical properties my code should have, much like I'd specify them in formally-verified software.
They serve both the purpose of informing readers, helping me reason, and checking I am not making a mistake in my reasoning. For example :
k = 0
for i in range(n):
assert k == i * (i + 1) // 2
k += i
#do some things
or in more complicated situations:
def sorted(l):
return all(l1 <= l2 for l1, l2 in zip(l, l[1:]))
def mergesort(l):
if len(l) < 2: #python 3.10 will have match - case for this instead of checking length
return l
k = len(l // 2)
l1 = mergesort(l[:k])
l2 = mergesort(l[k:])
assert sorted(l1) # here the asserts allow me to explicit what properties my code should have
assert sorted(l2) # I expect them to be disabled in a production build
return merge(l1, l2)
Since asserts are disabled when python is run in optimized mode, do not hesitate to write costly conditions in them, especially if it makes your code clearer and less bug-prone

Categories