简体   繁体   English

减少Python中函数的参数数量?

[英]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) . 函数Decrypt和Encrypt必须处理字母表的限制(A - Z和a - z) I tried to write the two possible cycles for both alphabets in one cycle function named cycleencrypt . 我试图在一个名为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: 但是该函数需要大约6个参数,而且我已经阅读了一个在一个函数中具有3个以上参数的可读性和可理解性较低的地方,所以我的问题是:

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! 希望应该清楚如何从这里开始工作到Cypher类的设计,但如果没有,请在Stack Overflow上提出一个问题!

If you want to provide encrypt and decrypt convenience methods, it's still easy to do. 如果您想提供encryptdecrypt方便的方法,它仍然很容易做到。 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 : 这是datetime.datetime的docstring:

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() ? 一边想:你认为图书馆的用户应该使用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. 你可以将它标记为私有(带下划线),这样每个人都会看到它不是公共API,而是应该使用encrypt()decrypt()代替。

The number of arguments doesn't really matters as long as there are not a dozen of them (maybe someone can link to what you mention about having more than 3 arguments, I may be wrong). 只要不存在十几个参数,参数的数量就不重要了(也许有人可以链接到你提到的关于超过3个参数的内容,我可能是错的)。

To be more readable in the definition of a function, write comments by following docstrings convention. 为了在函数定义中更具可读性,请按照docstrings约定编写注释。

To be more readable at the call of a function, gives default values in the definition as much as possible for the more useful values (for example, offset can have the value 1 by default, and index 0). 为了在函数调用时更具可读性,请在定义中尽可能为更有用的值提供默认值(例如,offset可以默认值为1,索引0)。

Either way, for a long line, use PEP8 guidelines which describes a way to jump lines correctly (the lines must not exceed 80 characters, according to PEP8 ). 无论哪种方式,对于长线,使用PEP8指南描述了正确跳线的方法(根据PEP8 ,线不得超过80个字符)。

def cycleencrypt(string, offset=1, index=0,
                     listing, first, last):
        """Description

        :param string: description
        :param offset: description
        :param index: description
        :param listing: description
        :param first: description
        :param last: description
        :return description
        """
        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)    

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM