2

I was trying to solve the following problem: Draw a star pattern that increases in every step (1st step: 1 star, 2nd step: 2 stars). E.g.

*
**

I am not sure why my code is not showing any output when I am writing return? When I am writing print, it is giving me the star output but also giving me None. May I know why return or print are not working properly? I am using Python 3.7. My code is:

def string(inp):
    for i in range (inp):
        return  i*"*"

print (string(5))
wjandrea
  • 28,235
  • 9
  • 60
  • 81
ktas
  • 83
  • 1
  • 2
  • 5
  • 4
    Return doesn't print anything. You're returning at the first iteration of the loop instead of printing all the elements or concatenating them – Mad Physicist Jun 20 '20 at 01:53
  • 2
    What you describe doesn't match the code. "it gives output but prints None" is the behavior of a function that has `print` but no `return`, that is passed to `print(func())` – Cireo Jun 20 '20 at 02:00
  • 2
    It prints a blank because your range starts from zero – Mad Physicist Jun 20 '20 at 02:01

4 Answers4

2

range starts at 0, and return terminates a function, so that means string will always return an empty string.

Here's one possible option for getting your expected result:

def stars(n):
    for i in range(1, n+1):  # Add one to start and stop
        print(i * "*")  # Print inside the function

stars(2)  # Don't print outside the function

Output:

*
**

If you need to print outside the function, you could use a generator:

def stars(n):
    for i in range(1, n+1):
        yield i * "*"  # "yield" is like "return" but can be used more than once

for s in stars(2):
    print(s)  # Print each string that gets yielded

# Or print all at once, using the "splat" unpacking operator
print(*stars(5), sep='\n')
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • Thank you. I tried the first block of code that you showed. But may I know, why is it printing the result, even if you are not calling the function like this: "print(stars(2))"? Isn't is mandatory to write "print" before calling any function? – ktas Jun 21 '20 at 00:42
  • @ktas No, not at all. `print` prints things, doesn't matter where it's called from. In fact `print` is itself a function, and doing `print(print(anything))` is pointless. Maybe you're used to shell scripting, where output is printed instead of being returned? – wjandrea Jun 21 '20 at 00:59
1

Using return won't print an output, use something like this:

def string(inp):
  for i in range (inp):
    print(i*"*")

string(5)

also this will only print 4, if you make it

for i in range(inp + 1):

It will work as intended, hope this helps!

Ertersy
  • 23
  • 4
  • 1
    "Using return won't print an output" - that's a confusing way to put it, cause OP wrote it so that the return value of the function would be printed. As well, `range` starts from 0 by default, so you're going to get a blank line. Instead use `range(1, inp+1)`. – wjandrea Jun 20 '20 at 02:04
  • Thank you for the suggestion, but I tried to get the expected output by writing range(1,inp+1) . Still it is not printing anything. – ktas Jun 21 '20 at 00:39
1

I will translate the code to plain English, as explicitly as I can:

Here are the rules that take a value `inp` and compute the `string` of that `inp`:
    Letting `i` take on each integer value from 0 up to but not including `inp`:
        We are done. The `string` of `inp` is equal to the string '*' repeated `i` times.

Compute the `string` of `5` and display it.

Hopefully the problem is evident: we can only be done with a task once, and i is equal to 0 at that point, so our computed value is an empty string.

When I am writing print, it is giving me the star output but also giving me None

From the described behaviour, I assume that you mean that you tried to replace the word return in your code with print, giving:

def string(inp):
    for i in range (inp):
        print(i*"*")

print (string(5))

That produces the triangle, of course, except that

  • Since i will be equal to 0 the first time through the loop, a blank line is printed; and since i will be equal to 4 the last time through the loop, there is no ***** line.
  • At the end, None is printed, as you describe. This happens because the value computed by string is the special value None, which is then printed because you asked for it to be printed (print(string(5))).

In Python, each call to a function will return a value when it returns, whether or not you use return and whether or not you specify a value to return. The default is this special None value, which is a unique object of its own type. It displays with the text None when printed, but is different from a string with that text (in the same way that the integer 5 is different from the string "5").

May I know why return or print are not working properly?

They are working exactly as designed. return specifies the result of calling the function, and can only happen once per function, and does not cause anything to be displayed. print displays what it is given.

If you wish to return multiple values from a call, then you need to work around that restriction - either by using a generator instead (as in @MadPhysicist's or @wjandrea's answers), or by using some single, structured datum that contains all those values (for example, a list, or a tuple).

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
-1

A a re-entrant function that preserves state between calls is a generator. To make a generator function, change the keyword return to yield:

def string(n):
    for i in range(n):
        yield (i + 1) * '*'

Calling this version of string will return a generator that yields a new line of your desired output at each iteration.

To print:

for line in string(5):
    print(line)

To print all at once:

print('\n'.join(string(5)))
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264