13
\$\begingroup\$

I'm a freshman in Python world, I used to program in C.

I wrote a function/method that returns the power of a number:

def pow(x, y):

    powered = x

    if y == 0:
        return 1

    while y > 1:
        powered *= x

        y -= 1

    return powered

Mine is a logic question (correctly): if I set y = 0 then it returns \$1\$, but on the last line of the code I wrote return powered then = x.

Does return work like as break?

\$\endgroup\$

4 Answers 4

25
\$\begingroup\$

return means "Eureka! I have found the answer! It is …." It hands that result back to the caller and stops executing any more code in this function.

Unlike x**y, your function gives incorrect results for negative or non-integer values of y. You should note that caveat in a docstring.

The standard way to do counting loops in Python is to use range() (or, in Python 2, xrange()).

To reduce the complexity of your code, you should avoid unnecessary special cases.

def pow(x, y):
    """Raise x to the power y, where y must be a nonnegative integer."""
    result = 1
    for _ in range(y):   # using _ to indicate throwaway iteration variable
        result *= x
    return result

This particular looping pattern (starting with some initial value and repeatedly applying an operation to the result) could be reduced to a one-liner:

from functools import reduce  # Optional in Python 2, required in Python 3

def pow(x, y):
    """Raise x to the power y, where y must be a nonnegative integer."""
    return reduce(lambda result, _: result * x, range(y), 1)

This solution is admittedly foreign-looking to a C programmer. The reduce() function uses 1 as the starting value (equivalent to result = 1 in the first solution). For each _ in range(y), it does result = result * x. lambda is just a way to define a simple function on the spot.


A more efficient algorithm would be repeated squaring.

\$\endgroup\$
6
  • 3
    \$\begingroup\$ Hello! I up-voted your answer. I especially liked the first part of it, where you explain in a very newbie friendly way what return is, what a possible constraint over the operation parameters is, and what is the standard practice for operations like these in python. I also very much liked your last code, it's very beautiful, but I believe it's a little bit too much for a newbie to grok, since as far as I can understand it requires you to know map, filter and reduce from functional programming to truly understand it, so a newbie is more likely to copy and paste it without understanding it. \$\endgroup\$ Commented Feb 15, 2016 at 21:53
  • \$\begingroup\$ I may be very wrong on my remarks however (the one about the reduce solution being too much for a newbie to grok). \$\endgroup\$ Commented Feb 15, 2016 at 21:54
  • \$\begingroup\$ @NlightNFotis I have to agree, it is much better than mine. \$\endgroup\$
    – Peilonrayz
    Commented Feb 15, 2016 at 21:55
  • 1
    \$\begingroup\$ This is why the beginner tag is useful. \$\endgroup\$
    – Legato
    Commented Feb 16, 2016 at 2:45
  • 1
    \$\begingroup\$ I completely disagree on the special case remark: The 0 as default value is obscure, untransparent and I don't know if that really counts in python, but also I would avoid mutability or mutating wherever possible. \$\endgroup\$
    – Quant
    Commented Feb 16, 2016 at 18:25
8
\$\begingroup\$

Does 'return' works as 'break'?

No. What functions as a break is that you have a condition (y > 1) which will be essentially reduced to being false at some time, since for every iteration of the loop, you decrement the conditional variable (so no matter how big a value it is, it's bound to become less than one at some point, making the conditional expression evaluate to false).

At that point, return just returns the result of the computation that has happened in the loop, which is being stored in powered.


Apart from that, you have a very beautiful problem that can be solved using recursion. You can do that and use Python's version of the C ternary operator (A if B else C), in order to arrive to a very beautiful and pythonic solution, that I consider to be very much in the spirit of computer science:

def pow(x, y):
    return 1 if y == 0 else x * pow(x, y - 1)

This may look weird for a newbie, but it's actually easier if you understand what happens. Let's go through it:

First of all, let's see the nature of a power computation: \$2^5\$ is essentially \$2 * 2 * 2 * 2 * 2\$. Our code produces the following call stack:

pow(2, 5)
2 * pow(2, 4)
2 * 2 * pow(2, 3)
2 * 2 * 2 * pow(2, 2)
2 * 2 * 2 * 2 * pow(2, 1)
2 * 2 * 2 * 2 * 2 * pow(2, 0)
2 * 2 * 2 * 2 * 2 * 1    # because of our base case that the condition eventually get's reduced to
2 * 2 * 2 * 2 * 2 
2 * 2 * 2 * 4
2 * 2 * 8
2 * 16
32

I do not know if the above is super useful to you, because that depends on your programming skills at this point. But since you mentioned you already know C, I reckoned that you may be already exposed to algorithmic concepts such as recursion and I thought that demonstrating this syntax and the concept in a nice solution might help you understand how powerful this concept is and how you could utilize it in your programs.

\$\endgroup\$
5
  • \$\begingroup\$ Yes, I know how iterations work. My question is about return: if y = zero then it returns 1, but going on there is another return. Does function close itself when I hit first return? \$\endgroup\$
    – r0ck3I_I
    Commented Feb 15, 2016 at 21:37
  • \$\begingroup\$ @r0ck3I_I Yes, it does. However, don't think about that this way. Your first return is there only as a sentinel, and that code path is only activated once you have a call like pow(x, 0) where x can be anything. In all other cases where y is not 0, then that branch is not followed, and you actually execute the loop below, and return the result of the computation after the loop condition evaluates to false. \$\endgroup\$ Commented Feb 15, 2016 at 21:40
  • \$\begingroup\$ @r0ck3I_I In other words, you don't go through the first return at all for any y that isn't 0. \$\endgroup\$ Commented Feb 15, 2016 at 21:42
  • 2
    \$\begingroup\$ Note that recursion is a nice academic exercise, but not recommended in practice, especially if the recursion might be very deep. \$\endgroup\$ Commented Feb 15, 2016 at 21:50
  • \$\begingroup\$ Ternary operator is great, Thnk! \$\endgroup\$
    – r0ck3I_I
    Commented Feb 15, 2016 at 21:51
5
\$\begingroup\$

If you didn't know you can use the builtin power function x ** y.


You should reduce the amount of blank lines, and use a for loop, i.e:

for _ in range(y):
    powered *= x

You also return x if y is negative. This is incorrect as \$x^{-y} = \frac{1}{x^y}\$.

To amend this you can create another guard clause:

if y < 0:
    return 1.0 / pow(x, -y)

Note a float cannot be passed to range so pow(4, 2.0) would now be invalid. To amend this you can use int.

def pow(x, y):
    y = int(y)
\$\endgroup\$
3
  • \$\begingroup\$ I know there is a**n operator. thnk anyway! \$\endgroup\$
    – r0ck3I_I
    Commented Feb 15, 2016 at 21:40
  • \$\begingroup\$ What happens with negative y ? \$\endgroup\$ Commented Feb 16, 2016 at 13:00
  • 1
    \$\begingroup\$ @RobAu When you commented it'd return x the same as OP's. Thank you for pointing this out as I've now addressed this error. \$\endgroup\$
    – Peilonrayz
    Commented Feb 16, 2016 at 13:19
-1
\$\begingroup\$

I want to improve time taken by the recursive solution proposed as an answer by @NlightNFotis:

  1. If a ==0, we know that 0 raised to the power of any number will be equal to zero before computing it.
  2. For even numbers, we use the property \$a^{2n}\$=\$(a^{n})^2\$ to reduce by 2 the time taken by the algorithm when calculating the power for an even number.

This is just in case we want to use recursion, but it is not an efficient solution in Python. Just to see the beauty of it, here is an optimization for @NlightNFotis's answer:

 def power(a,b):
      """this function will raise a to the power b but recursivelly"""
      #first of all we need to verify the input
      if isinstance(a,(int,float)) and isinstance(b,int):
        if a==0:
          #to gain time
          return 0
        if b==0:
            return 1
        if b >0:
          if (b%2==0): 
          #this will reduce time by 2 when number are even and it just calculate the power of one part and then multiply 
            if b==2:
              return a*a
            else:
              return power(power(a,b//2),2)
          else:
          #the main case when the number is odd
            return a * power(a, b- 1)
        elif not b >0:
          #this is for negatives exposents
          return 1./float(power(a,-b))
      else:
        raise TypeError('Argument must be integer or float')
\$\endgroup\$
2
  • \$\begingroup\$ You should add a justification why and in which way this is better than what the OP or the other answers have. Note that recursive solutions are usually not the best in Python, due in part to its recursion depth limit. This code will for example fail for power(2, 1000), because in one of the recursive calls, a is no longer an int, but a long. Also, there is a typo in the TypeError message... \$\endgroup\$
    – Graipher
    Commented Jun 23, 2017 at 10:35
  • 1
    \$\begingroup\$ @Graipher thanks for advice and corrections !! I think i could add this as a new questions for the review not as an answer to a question !! Thanks for letting me know why it not working when a=2 , i spend hours before discover that!! Let me try to edit it as a new answer or simply delete it \$\endgroup\$ Commented Jun 23, 2017 at 19:09

Not the answer you're looking for? Browse other questions tagged or ask your own question.