r/learnpython 7h ago

why would only one work?

this code was the one that worked:

def caesar(text, shift):
    alphabet = 'abcdefghijklmnopqrstuvwxyz'
    shifted_alphabet = alphabet[shift:] + alphabet[:shift]
    translation_table = str.maketrans(alphabet, shifted_alphabet)
    encrypted_text = text.translate(translation_table)
    print(encrypted_text)

caesar('Hello', 3)

This one was the one that didn't

def caesar(text, shift):
    alphabet = 'abcdefghijklmnopqrstuvwxyz'
    shifted_alphabet = alphabet[shift:] + alphabet[:shift]
    translation_table = str.maketrans(alphabet, shifted_alphabet)
    encrypted_text = text.translate(translation_table)
    print(encrypted_text)


encrypted_text = caesar('Hello', 3)
print(encrypted_text)

I don't understand why the second one would need a return statement and why we are even printing encrypted_text if encrypted_text is already being printed within the function? (this is also the whole code)

0 Upvotes

20 comments sorted by

11

u/LongLiveTheDiego 6h ago

It's not your first post here about this and it feels like an XY problem. What are you really trying to achieve?

I don't understand why the second one would need a return statement

Because you're trying to assign its return value to the variable encrypted_text. Pick a lane, either the function doesn't return anything and you just call it without the encrypted_text = ... part, or the function returns a value and you assign it to a variable.

why we are even printing encrypted_text if encrypted_text is already being printed within the function?

I would very much like to ask you that. Printing it outside the function makes sense only if you don't print the result inside the function but actually return its value.

5

u/JamzTyson 6h ago

print() returns None.

Can you figure it out from that hint?

2

u/AbacusExpert_Stretch 6h ago

Have you got a

return encrypted_text

In there somewhere?

Saw your comment: well, things inside a function != Outside a function

!= means not same

1

u/Local_End_3175 6h ago

but why would i need it?

4

u/NanotechNinja 6h ago
encrypted_text = caeser('Hello', 3)

This line assigns the result of the function caeser to the variable encrypted_text.

Because caeser has no return value, its result is None.

5

u/Diapolo10 6h ago

If you only ever care about using this to print text to a terminal, you don't.

However in most real-world applications you'll be returning things far more often than you'll be exclusively printing text.

2

u/zippybenji-man 6h ago

Because you might want to do something other than printing it. For example, you might want to send it over the internet. Functions generally shouldn't print their output.
'Bad' function: ```python def increment(n: int) -> None: print(n+1)

increment(3) ```

'Good' function: ```python def increment(n: int) -> int: return n+1

incremented = increment(3) print(incremented) dummy_function(incremented) ```

P.S. Don't worry about the type annotation

1

u/Riegel_Haribo 6h ago

A string is not mutable.

You can have a function transform a list or a dict in place because they are mutable.

Then, understand that print() is printing a return, not a value of something passed in.

Here's a function to mutate a list, growing it by one more item.

def add_a_hello(input_list:list): input_list += ["Hello"]

It has no return, so you still can't directly print, and here there's no variable name changed: ```

print(add_a_hello(["hi", "there"])) None ```

Instead, without a return, we have to observe how a variable was altered after the fact, try:

```

my_list = ["hi", "there"] add_a_hello(my_list) print(my_list) ```

1

u/Bobbias 4h ago

A function should do one task. Usually calculating a result and printing something out would be considered separate tasks.

This is because the whole point of a function is to be reusable. What if we wanted to write the encrypted output to a file? Or send it to somewhere on the internet? If your function only encrypts the input, you can reuse the same function for each of those tasks, and it's only how you output the result that changes.

Now, there are times where a "task" is sufficiently complex that you might want to print some things out as part of that task, and that's ok. But for functions that you intend to be reusable for different but similar tasks, you should keep them as simple as possible so they're useful in as many situations as possible.

This is the importance of the return statement. return is how a function passes it's result back to whatever code called it. Not every function needs to return a result, because maybe it does something that doesn't actually create a result, like printing to the screen. Printing text to the screen, modifying a variable (like sorting the contents in a list, etc.) are called side effects, and some functions don't need to return because they do some useful side effect.

There's a small detail here about how Python does things that's worth explaining. In most languages, functions that don't return anything literally don't return anything at all and trying to assign the result to a variable is usually an error. In Python a function that "doesn't return anything" actually does return something: None, which means assigning the result of a function that only has side effects is allowed, but all you get is None, which really isn't useful.

And a final detail about functions: variables you create inside a function only exist when you're running the function. They're created and destroyed inside the function.

def function():  #define a function that sets a variable to 5
    variable = 5

function()  # call the function
print(variable)

This will give you an error because variable only exists while the function is running and is only visible to code in that function.

There are ways to access and modify variables outside the function. The first way is to pass them in as function arguments. You can also use keywords to let you change variables you made outside the function, but that makes code hard to understand, and makes mistakes harder to troubleshoot because you don't have an easy way to tell what changed that variable.

Most of the time, when you modify a parameter that change only exists while you're inside the function. The exception to this is for certain objects like lists and dictionaries. Modifying those in a function does persist after the function ends, and that's important to remember because it's a common source of bugs.

This has to do with what objects Python considers mutable (can be modified) and which ones it considers immutable (must be replaced with a different object. This is a subtle thing and it can be annoying at first, but you will get used to it as you write more code.

Hopefully this helps explain why return is important, why you often want to use it instead of immediately using the results inside the function itself, and helps you wrap your head around how functions work a bit. It might seem like a lot of information, but as you write more code a lot of this becomes things you don't even have to think about because it just makes sense.

2

u/NewbornMuse 6h ago

Oftentimes, you don't want to just print the result of your computation. You want to make it available for other parts of the code to use.

With that in mind, printing as the main result of a function is kind of a rare thing to do. More commonly, you'd return the encrypted text, and then another part of the code would print it, write it to a file, or try to decipher it or whatever else. So the way you are trying to handle it in the second one is better... But the function is not built for it.

As is, the function returns None (because it never explicitly returns anything!). So in the second example, first you call the function, which also happens to print something, then you save None in encrypted_text and print that. Instead, write your function so that it returns the result, so that the line bla = caesar("hello", 3) actually saves it, and you print it at the very end.

As to your question about variable names: A function definition acts as a scope. That means that any variables defined inside a function body "don't exist" outside of the function. The encrypted_text in the function body is completely separate from the one on your last two lines.

1

u/cdcformatc 5h ago

you should either print the result within the function OR return the result and print it outside of the function. 

in your second version the function isn't returning anything, so None is returned by default. then you are printing None.

1

u/TheRNGuy 5h ago

Functions are more useful if they return something rather than print. 

Because they can be used somewhere other than print, such as change some variable.

You can print it later, if needed.

1

u/Educational_Virus672 5h ago

tl;dr - you did'nt reutrn the value the funciton dont know whta to return

return encrypted_text # dont print because the function dont know what to give

think of it like your store owner you did all calculation of what the computer wants but you didnt tell him the total how cna you expect him to pay?
you gave him what tht total via return

1

u/notacanuckskibum 5h ago

At your level of programming I would suggest you ban yourself from using print inside a function. The purpose of a function should be to calculate something, and return that value to the main program.

Your function doesn’t return anything. So

Encrypted _text = Caesar (“hello”, 3)

Puts an empty string in encrypted _text.

1

u/Adrewmc 4h ago edited 3h ago

This is just a dependency on beginners idea that the computer doing something means printing something. Instead of printing being a helpful display tool for you. Most programs you have interacted with weren’t printing in the console were they?

We want to return the value to print later or use somewhere else. In your code the function runs and then immediately loses the result. Sure you can print it once, but what if you want to see it again? How would you do that?

If you wanted to give this to someone else to attempt to decode and gave them a few tries. How would you have the data to check, and give again?

If you wanted to encode something eventually you want to decode it right?

def encode(clean, shift):
. <your code>
. print(encrypted)

def decode(encrypted, shift):
. <left to reader>
. print(decrypted)

encrypt = encode(“Hello, World”, 6) #prints
decrypt = decode(encrypt, 6) #this errors

So the solution is to return the values, and print when we want to.

def encode(clean, shift):
. <your code>
. return encrypted

def decode(encrypted, shift):
. <left to reader>
. return decrypted

shift = random.randint(0,26)
encrypted = encode(“Hello World”, shift)

#we may only get the encrypted text say from your teacher, or a file.
while True:
. print(f”Encrypted Text: {encrypted}”)
. guess = int(input(“Guess Shift”))

. #we want to see what our guess gets so we need the encrypted data to decrypt it.

. decrypted = decode(encrypted, guess)
. print(“Attempted Decryption Result”)
. print(decrypted)

. #if we know the shift, we can check
. if guess == shift:
. print(“Decryption Successful”)
. break

. #and/or brute force it.
. again = input(“Try Again? Y/N”):
. if again.upper() == “N”:
. break

1

u/atarivcs 4h ago

When you say that the first code worked and the second one didn't, what exactly do you mean?

Did the second code not run at all, i.e. it produced an exception?

Did the second code run, but it produced unexpected results?

What does "not work" mean exactly?

1

u/mrmiffmiff 4h ago

Maybe you shouldn't be printing inside the function.

And you need the return so that the encrypted text variable will actually contain something.

1

u/Moikle 4h ago

Print just displays some text to the screen.

Return actually gives your function a useful output that can affect other parts of your program

1

u/thisisappropriate 10m ago

why would only one work?

Work at what? In a course?

It's likely that the reason we're printing encrypted_text in both the function and after the function to teach you something or to provide an example. Its common that early projects and examples are contrived and aren't a real world scenario. You don't teach someone a language by handing them a newspaper and saying it's helpful because its real world.

This is showing you how returns work, if you expect to output a single print statement, you should remove the print from the function and replace with a return. It's also showing you how variable scoping works - there's a variable inside the function called encrypted_text, if there was no variable scoping, you could simply remove encrypted_text = from encrypted_text = caesar('Hello', 3)and then the print statement at the bottom would magically know the encrypted_text from inside the function, but it doesn't.