Home > Mobile >  Why does this code print the constructor?
Why does this code print the constructor?

Time:06-07

class CipherTest:
def __init__(self):
    self.shift = 0
    self.direction = 'r'
    self.text = "Testing"

    # Shift to right function
def shift_to_right(self, text, shift):
    encrypted_text = ""
    for i in range(len(self.text)):
        c = self.text[i]
            # Encrypt upper case
        if (c == ' '):
            encrypted_text  = ' '
        elif (c.isupper()):
            encrypted_text  = chr((ord(c)   self.shift - 65) % 26   65)
            # Encrypt lower case
        else:
            encrypted_text  = chr((ord(c)   self.shift - 97) % 26   97)

    return encrypted_text

    # Shift to left function
def shift_to_left(self, text, shift):
    encrypted_text = ""
    for i in range(len(self.text)):
        c = self.text[i]
        # Encrypt upper case
        if (c == ' '):
            encrypted_text  = ' '
        elif (c.isupper()):
            encrypted_text  = chr((ord(c) - self.shift - 65) % 26   65)
        # Encrypt lower case
        else:
            encrypted_text  = chr((ord(c) - self.shift - 97) % 26   97)

    return encrypted_text

if __name__ == "__main__":
user_text = str(input())
user_shift = int(input())
user_direction = str(input().lower())      # user inputs
Cipher_Message = CipherTest()          # create an instance of the class

if user_direction == 'l':               # picking left or right 
    print(CipherTest.shift_to_left(Cipher_Message, user_text, user_shift))

if user_direction == 'r':
    print(CipherTest.shift_to_right(Cipher_Message, user_text, user_shift))

Am I calling the functions within my class incorrectly? Currently no matter the input, it prints "Testing". I'm new to classes but I believe that in the last couple lines, I am calling the new instance, telling it which method to perform, then feeding it the variables it needs to successfully run. From there it should be printing the 'encrypted_text' that is returned using my methods.

CodePudding user response:

The issue is that CipherTest have attributes direction, shift and text but you also have local variables that you pass as parameter which you don't use

So your method keep using Testing and 0, that returns Testing so


The easiest, is to remove the attributs, so the class instance can do both direction, and in fact the method can be static (meaning no instance needed, only the class)

class CipherTest:

    @staticmethod
    def shift_to_right(text, shift):
        encrypted_text = ""
        for c in text:
            if c == ' ':
                encrypted_text  = ' '
            elif c.isupper():
                encrypted_text  = chr((ord(c)   shift - 65) % 26   65)
            else:
                encrypted_text  = chr((ord(c)   shift - 97) % 26   97)
        return encrypted_text

if __name__ == "__main__":
    user_text = "hey how are you"
    user_shift = 2
    user_direction = "l"

    if user_direction == 'l':
        enc = CipherTest.shift_to_left(user_text, user_shift)
        print(enc)  # encrypted
        print(CipherTest.shift_to_right(enc, user_shift))  # back to plain

    elif user_direction == 'r':
        enc = CipherTest.shift_to_right(user_text, user_shift)
        print(enc)  # encrypted
        print(CipherTest.shift_to_left(enc, user_shift))  # back to plain

Another example, so you understand better, is to put the shift as class attribut, in order to use ise, we need to save in the class with self.shift = shift then we can use one cipher instance, with it's shift, to do both operation (also see how we really call a instance method)

class CipherTest:

    def __init__(self, shift: int):
        self.shift = shift

    def shift_to_right(self, text):
        encrypted_text = ""
        for c in text:
            if c == ' ':
                encrypted_text  = ' '
            elif c.isupper():
                encrypted_text  = chr((ord(c)   self.shift - 65) % 26   65)
            else:
                encrypted_text  = chr((ord(c)   self.shift - 97) % 26   97)
        return encrypted_text

if __name__ == "__main__":
    user_text = "hey how are you"
    user_shift = 2
    user_direction = "l"

    cipher = CipherTest(user_shift)

    if user_direction == 'l':
        enc = cipher.shift_to_left(user_text)
        print(enc)  # encrypted
        print(cipher.shift_to_right(enc))  # back to plain

    elif user_direction == 'r':
        enc = cipher.shift_to_right(user_text)
        print(enc)  # encrypted
        print(cipher.shift_to_left(enc))  # back to plain

CodePudding user response:

You're passing the class in as a parameter to your function. CipherTest.shift_to_left(Cipher_Message, user_text, user_shift)

When you define a class method in python, you include self as a parameter but don't actually pass it when calling the function. It's interpreting Cipher_Message (the instance) as what you intended to put in as user_text.

Fix this by simply removing Cipher_Message from your parameters: CipherTest.shift_to_left(user_text, user_shift)

You're not done yet. You're attempting to call a non-static method on the Class, instead of the instance. This means you're telling the 'blueprint' to shift your encryption as opposed to your actual test class. Fix this by changing the class to the instance: Cipher_Message.shift_to_left(user_text, user_shift)

A nonbreaking bug you also have is that your functions seem to be taking parameters that you aren't using. def shift_to_right(self, text, shift): takes two parameters - text & shift, yet you use the class's fields instead of those.

Simply removing them from the definitions and calls will remedy this. def shift_to_right(self): .shift_to_right()

CodePudding user response:

Within your class methods, you are accepting parameters of text and shift, but the code of the methods never references those parameters. The methods only reference the instance variables self.text and self.shift, which are attributes of the instance Cipher_Message, assigned during the execution of __init__ when the new instance was created

Two options:

  1. Update the methods to use the parameters instead of the instance attributes.
  2. Update __init__ to take text and shift as parameters, and assign the instance attributes based on the parameters that were passed in.

CodePudding user response:

Ignoring how the user input is handled, this can be greatly simplified.

class CipherTest:
    @staticmethod
    def shift_to_left(text, shift):
        return CipherTest.shift(text, -shift)
    @staticmethod
    def shift_to_right(text, shift):
        return CipherTest.shift(text, shift)
    @staticmethod
    def shift(text, shift):
        result = ''
        for c in text:
            if c.isupper():
                c = chr((ord(c)   shift - 65) % 26   65)
            elif c.islower():
                c = chr((ord(c)   shift - 97) % 26   97)
            # note that whitespace is neither upper nor lower so just append unchanged
            result  = c
        return result

print(CipherTest.shift_to_left(CipherTest.shift_to_right('Hello world', 3), 3))

...which keeps the interface similar. Alternatively:

print(CipherTest.shift(CipherTest.shift('Hello world', 3), -3))

Output:

Hello world
  • Related