My question is about how to deal with the piece of code where I am using the Caesar´s cipher.
Functions Decrypt and Encrypt have to deal with the limits of the alphabet (A - Z and a - z). I tried to write the two possible cycles for both alphabets in one cycle function named cycleencrypt.
But the function takes about 6 arguments and I have read somewhere that is less readable and understandable having more than 3 arguments in one function so my question is:
Should I reduce the number of arguments by splitting in two functions and make the piece of code longer (but maybe more understandable)? Thanks for any answer I aprreciate that.
EDIT: Docstrings around the functions were deleted to make visible the main purpose of my question.
def offsetctrl(offset):
while offset < 0:
offset += 26
return offset
def cycleencrypt(string, offset, index, listing, first, last):
offset = offsetctrl(offset)
if string >= ord(first) and string <= ord(last):
string += offset
while string > ord(last):
string = ord(first) + (string - ord(last) -1)
listing[index] = chr(string)
Cycle for encrypting with a lots of arguments and control of negative offset´s
def encrypt(retezec, offset):
listing = list(retezec)
for index in range(0, len(retezec)):
string = ord(retezec[index])
cycleencrypt(string, offset, index, listing, 'A', 'Z')
cycleencrypt(string, offset, index, listing, 'a', 'z')
print(''.join(listing))
main encryption part taking many arguments in two lines with printing
def decrypt(retezec, offset):
return encrypt(retezec, -offset)
if __name__ == "__main__":
encrypt("hey fellow how is it going", 5)
decrypt("mjd kjqqtb mtb nx ny ltnsl", 5)
In this kind of situation, it's often better to write your code as a class. Your class's constructor could take just the minimum number of arguments that are required (which may be none at all!), and then optional arguments could be set as properties of the class or by using other methods.
When designing a class like this, I find it's most useful to start by writing the client code first -- that is, write the code that will use the class first, and then work backwards from there to design the class.
For example, I might want the code to look something like this:
cypher = Cypher()
cypher.offset = 17
cypher.set_alphabet('A', 'Z')
result = cypher.encrypt('hey fellow how is it going')
Hopefully it should be clear how to work from here to the design of the Cypher
class, but if not, please ask a question on Stack Overflow about that!
If you want to provide encrypt
and decrypt
convenience methods, it's still easy to do. For example, you can write a function like:
def encrypt(text, offset):
cypher = Cypher()
cypher.offset = offset
return cypher.encrypt(text)
Here is the docstring of datetime.datetime
:
class datetime(date):
"""datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
...
"""
And the signature of its constructor:
def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
What we could learn from it:
Side thought: do you think users of your library would should use cycleencrypt()
? You could mark it private (with underscore), so everybody will see it's not a public API and they should use encrypt()
and decrypt()
instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With