Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reducing the number of arguments in function in Python?

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)
like image 445
luky suky Avatar asked Nov 03 '17 13:11

luky suky


2 Answers

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)
like image 158
Daniel Pryden Avatar answered Oct 11 '22 01:10

Daniel Pryden


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:

  • Add exactly as many arguments as it makes sense to add
  • Use parameters and to give sensible default values to arguments

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.

like image 31
Art Avatar answered Oct 11 '22 02:10

Art