Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
Following is my function definition
def func_a():
return 1
def func_b(val1):
return val1*2
And this is one way of calling the function:
count = 0
while count < 10000000:
val2 = func_b(func_a())
count += 1
time taken for above is:
real 0m5.003s
user 0m4.989s
sys 0m0.012s
For the below usage with the same function definition:
count = 0
while count < 10000000:
ret1 = func_a()
val2 = func_b(ret1)
count += 1
the time taken is
real 0m5.502s
user 0m5.414s
sys 0m0.010s
I did about 10 runs each and the real time difference between the two was always ~300-500 ms.
Whereas the sys time was usually only about ~1-2 ms different. (max of about 10 ms).
The application I work with deals with about 60-90k transactions with sub millisecond performance, so this is kind of big for me. Why is there this much difference between the two invocations?
EDIT NOTE: The below answer is not much relevant now after the question revamp, please see the question edit for the original question.
From readability perspective (and code maintenance ?) I guess the
first one is better?
Actually the second one is better, especially if you are not using the return value of function_a anywhere else. Otherwise, the first line will create a name that may cause a namespace clash. Consider this:
foo = 42
# many many lines of code later
foo = function_a()
result = function_b(foo)
print foo # oops!
Is the second one better from memory perspective
The cost is insignificant.
Which of the two is better in terms of
performance?
There is no performance benefit that you can get from one approach or the other that would create any practical impact in your application.
It doesn't matter. There might be an incredibly minor speed advantage due to skipping a few loads and stores without the intermediate variable, and using the variable might extend the lifetime of a temporary a bit, slightly affecting memory usage patterns, but the difference isn't even worth considering. In different situations, one might be more readable than the other. Try to avoid ultra-long lines, and if you're going to pull pieces out of an expression for readability, try to pick meaningful pieces.
The disadvantage of the former approach is that you generate intermediate variables that should never be used again, and you or somebody else might accidentally write one of them (that is, later use "val1" instead of "val2"). Intermediate values are not a serious issue, but they do occasionally cause programming mistakes.
The latter approach may be a little less readable. It looks a lot better in an object oriented context:
val2 = function_a().function_b()
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
In both examples, class.method() returns a list.
Example A:
if class.method():
for i in class.method():
# do stuff
Example B
list = class.method()
if list:
for i in list:
# do stuff
Which is better? It would seem to me that in some languages (but I don't know which), example A would result in class.method() being needlessly evaluated twice, and example B would be best practice. However, perhaps other languages (again not knowing which) might retain the output of a method in memory in case that method is called again, therefore avoiding having to do the same evaluation twice and resulting in little difference between examples A and B. Is this so? If so, can you give examples of a language for each case? And the real reason for the question: which is best practice in Python?
Unless your Python interpreter has JIT capabilities, the method will be evaluated every time you call it.
And even when the JIT compilation is possible, methods have to be proven by the compiler / interpreter that they do not have any side effects, that is they are deterministic.
For example, consider a method that pulls data from a database or a method that contains a call to a random number generator:
import random
def method():
return random.uniform(0.0, 1.0)
Output of such a method cannot be saved in memory because the second time you call it, it may change.
On the other hand, getter methods that accumulate data are a great example of a deterministic method, given that they do not call a non-deterministic method in their body.
from dataclasses import dataclass
#dataclass
class Example:
a : list
b : list
def method(self):
return self.a + self.b
In practice, you are better of to not assume anything from the compiler / interpreter and do these small, easy to do optimizations yourself. You also have to consider that your code can be run on multiple platforms, which further complicates things.
So I would recommend you to call the method only once and save its output in a temporary variable:
result = class.method()
if result :
for i in result:
# do stuff
And given that it's Python, I recommend to ask for forgiveness with the try keyword if most of the time you run the method, its output is not None:
result = class.method()
try:
for i in result:
# do stuff
except TypeError:
pass
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
So a few days ago we got this exercise where we need to make a function that takes two lists as input and calculates the difference of their averages.
Sounds simple enough, but there are a few catches:
the entire thing needs to be one line long
you can absolutely NOT use ':'
They encouraged us to use 'import', 'help()' and 'dir()'.
The thing is that I know how to make it only one line long, but the no ':' is really annoying.
The way I see it, I first need to define a function (without code) then change it's 'func_code' attr.
Any ideas on how can I do it?
And how do the params fit into this?
Any answer is appreciated!!!
Edit: thanks for all the answers and the creative minds that said char(58) is the solution, it is really creative and I haven't thought of that solution but it's not allowed since you are using ':' even though not directly.
No : means you can't use lambda. That leaves higher-order functions or eval trickery.
eval('lambda a,b{}sum(a)/len(a)-sum(b)/len(b)'.format(chr(58)))
This meets the letter of the law, but violates its spirit.
Unfortunately, without a function composition function, higher-order functions don't work very well. Implementing one without : is tricky.
Here's what should be a fairly self-contained solution, using a pickled code object. I've created it in Python 3.6, and the specific bytestring is very likely to be version specific, but you can create your own version pretty easily using the expanded code below. Anyway, here's the oneliner:
f = __import__('types').FunctionType(__import__('pickle').loads(b'\x80\x03cipykernel.codeutil\ncode_ctor\nq\x00(K\x02K\x00K\x02K\x04KCC t\x00|\x00\x83\x01t\x01|\x00\x83\x01\x1b\x00t\x00|\x01\x83\x01t\x01|\x01\x83\x01\x1b\x00\x18\x00S\x00q\x01N\x85q\x02X\x03\x00\x00\x00sumq\x03X\x03\x00\x00\x00lenq\x04\x86q\x05X\x01\x00\x00\x00aq\x06X\x01\x00\x00\x00bq\x07\x86q\x08X\x1e\x00\x00\x00<ipython-input-1-384cc87bd499>q\tX\x16\x00\x00\x00difference_of_averagesq\nK\x01C\x02\x00\x01q\x0b))tq\x0cRq\r.'), globals())
Here's what I'm doing without the one-line shenanigans:
import types # replace these import statements with calls to __import__ in the oneliner
import pickle
def difference_of_averages(a, b):
return sum(a)/len(a) - sum(b)/len(b)
payload = pickle.dumps(difference_of_averages.__code__) # embed as a literal in the oneliner
f = types.FunctionType(pickle.loads(payload), globals())
Hmm, having tried this on the few different interpreters I have at hand, it looks like my pickle string includes some nonsense from the IPython interpreter I created it in. If you get errors using my string, I'd suggest just building your own (which, if it contains any junk, will at least be junk compatible with your environment).
Not using ':' is tricky because you normally use it to define the function body, like this:
def average(number_list):
return sum(number_list) / len(number_list)
However, I know of one way to define a function that doesn't require require writing a block for its body: You can assign a lambda function (or even an already-defined function) to a function you want to define, simply by using the equal sign (=). For example, if you want to create an average() function, you might write:
average = lambda number_list: sum(number_list) / len(number_list)
average might look like a variable, but you can use it as a function. It simply calls the lambda function that takes a number_list as input and returns the average value of the number_list. You can call it like this:
value = average([10, 11, 12]) # sets value to 11
Now, lambda functions can only have one line. But that's not really a problem for you, since your task requires you to only use one line.
Do you understand what to do now? Your exercise requires you to find the average of two lists, so you might consider using a lambda function that takes two inputs (instead of just one, like in the example I gave above). Also bear in mind that you need to return the difference, and if the difference should always be positive, consider using Python's abs() function somewhere in your code.
Edit: Well, gilch's response made me realize that I can't use lambda because even they use :. So apparently you can't use my advice. It's still good to know about lambda functions, though.
The fact that you are encouraged to use import makes me wonder if it's okay for you to use an already-defined function from some module to define your own function. Kind of like this:
import math; average = math.difference_of_averages
However, that depends on you being able to find a (probably standard) function that does exactly what you want. (I've briefly checked the math and numpy modules, and haven't found anything that matches yet.)
And maybe this means that you can create a module and define it anyway you like. The module is in its own world, so it's not constrained to the rules of your exercise.
Then again, maybe not.
So unless you want to "sneak-in" a : in an eval statement (as gilch suggested), like this:
average = eval('lambda number_list' + chr(58) + ' sum(number_list) / len(number_list)')
there's no way I know of off hand to avoidi using :.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am making an algorithm that converts numbers into roman numerals, which involves an array. However, when I run my code, I tell it to check if they array exists, and create it if it doesn't (I use this complex method because the code has to restart itself a lot, you will see).
number = input("What number would you like to convert?")
number = int(number)
def alg(n):
if 'roman' in locals():
print("yes")
if n >= 1000:
roman = roman + ["M"]
n = n - 1000
print(roman)
print(n)
#alg(number)
else:
print("end")
else:
print("no")
roman = [""]
print(len(roman))
print(locals())
alg(number)
alg(number)
I have tried researching it on the Python documentation and on this site, but to no avail.
Every invocation of a function has its own set of local variables. Your check will always return false, because you have just entered the function.
If you want to keep the recursive implementation that you currently have, you should pass the roman variable as a second parameter to the alg function.
Are you sure you want to find it in locals() (which will only look in the scope of your function alg which is just starting, thus cannot containing your roman variable) ?
Maybe you want to look up into globals variables with globals() ?
You check for the word 'roman' in locals; this is not going to happen, as you have yet to define roman. A function's locals do not persist from call to call.
Your decrement
n = n - 1000
doesn't do anything useful (yet). The local copy of n gets changed, but you never use it. The original copy (from the main program) is still intact, as integers are not mutable.
Note that your recursive call passes number -- the main program's original number. You're always converting the original, never working on the smaller quantity.
I'll stop here: without design, structure, or comments, this code is a bit hard to follow.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I just want to know which way is more preferable in python.
Imagine two functions:
1 function:
def foo(key):
if bar.has_key(key):
return bar.get(key)
# do something with bar
# this will be executed if bar_key(key) is False
...
return something
2 function:
def foo(key):
if bar.has_key(key):
return bar.get(key)
else:
# do something with bar
# this will be executed if bar_key(key) is False
...
return something
As you can see the only difference is else statement. So the question is will it affect performance somehow. Or are there any reasons to include else in this type of functions?
If the choice is between those two approaches, I would pick the first one. return is pretty explicit that execution terminates at that point. I find if x { return y } else { ... } an anti-pattern for this reason (not just in Python -- I see this in C/C++ code and it irks me there, too).
If you are returning, an else block is entirely unnecessary and causes pointless indentation of a block of code that might be quite large. The more nested structures you have, the more difficult it is to maintain proper context in your head while reading code. For this reason I tend to prefer less nesting when it does not obfuscate logic, and in this case I don't think it would.
The pythonic way:
def foo(key):
return bar.get(key, something)
While this question is a little opinion based, I'd say the second is more Pythonic for the reason of "explicit is better than implicit". The second function is clearly saying "if this condition, do this. Otherwise, do this". On the other hand, the first function implies the "Otherwise" part.
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 9 years ago.
Paul Graham describes the following problem:
We want to write a function that generates accumulators-- a function that takes a number n, and returns a function that takes another number i and returns n incremented by i.
He says that whereas such a function could be implemented in Lisp/Ruby/Perl as simply as something like
(defun foo (n)
(lambda (i) (incf n i)))
, in Python it would be written
class foo:
def __init__(self, n):
self.n = n
def __call__(self, i):
self.n += i
return self.n
So my question is, What exactly about Python (apart from the lack of support for multi-line lambdas) prevents you from implementing an accumulator generator in the terse style of the first code sample above? Would Python ever support such a thing in the future, as Paul Graham speculates?
The example if first of all contrived. After defining the accumulator, you would in Python use it like this:
acc = foo(6)
acc(2)
acc(4)
For what use? In Python you would do this:
acc = 6
acc += 2
acc += 4
I don't know if defining an accumulator in lisp makes sense, but in Python you don't need to define one, because you would have it built in, so to speak.
Second of all the question you ask hits the nail on the head. What prevents Python from doing this in a "terse" style? Because the attitude of Python is that it will going to be a language that is quick to develop in and that is maintainable, and that means easy to read. Code golf and obtuse, terse code is not a part of what Python is designed for.
But ultimately, the reason Python will never evolve this functionality is that is relies on integers being mutable, ie that you can do something like:
>>> g = 6
>>> g++
>>> g
7
This will not happen in Python, where integers are immutable. You can't increase the value of an integer. This simplifies both the language and it's use a lot. For example, if integers were mutable, they could not be used as keys in dictionaries.
Essentially the example centers around increasing the value of integers, something you can't do in Python. In Python, when you add two integers you get a third integer back. You do not increase the value of the first one.
So Python will never become lisp, and only people who have used lisp for too long thinks it should, or persist in the "python is almost lisp" idiom. And it can't do an accumulator in just a few lines, because it neither needs to nor wants to.
He actually describes one reason in his followup post. His brief discussion there covers both of the reasons I mention below, although his take on it is a bit different.
As he talks about earlier in the post, part of what he's concerned with is the difference between statements and expressions. In Python += is a statement, and lambdas cannot contain statements, only expressions.
However, there's another issue. He wants his function to take "a number" as input, but he makes a distinction between "plus" and "increment" (as do many programming languages). However, my own position would be that there is no such distinction for numbers, only for variables (or "objects" or similar things). There is no such thing as "incrementing" the number 5. In this sense, you still can't write a Python lambda that increments a variable containing a builtin in numeric type, but you can do it if it accepts a mutable object instead of a raw number. And you could write your own MutableNumber class that works this way and make it totally interoperable with existing numeric types. So in this sense the reason Python doesn't support has to do with the design of its types (i.e., numbers are immutable) rather than the sort of functional issues he discusses in the post.
Whether any of this is actually a problem for the language is, of course, another question.
It can. The trick is to use a container to hold the original integer and to set and access this number without using the assignment operator.
>>> g=lambda n: (lambda d: lambda i: (d.__setitem__('v', d['v']+i),d['v'])[1])({'v': n})
>>> x=g(3)
>>> x(1)
4
>>> x(1)
5
>>> x(10)
15
>>>
trying to do this as clear as I could, separating lambdas to variables:
concat = lambda arr, val: (arr.append(val), arr)[1]
f = lambda n: (lambda i: concat(n,n.pop(0)+i)[0])
accumulate = lambda n: f([n])
a=accumulate(9)
a(1) #10
a(2) #12