从Java程序员的角度来看Python OOP

Gro*_*Man 5 python oop

我只有Java的OOP编程经验,刚刚开始使用Python开发项目,我开始意识到Python让我对一些对我来说很直观的事情持怀疑态度.所以我在Python中有一些关于OOP的问题.

场景:我正在编写一个可以发送电子邮件的程序.对于电子邮件的to,from,textsubject领域将需要和其他领域一样cc,并bcc将是可选的.此外,将有一堆类将实现核心邮件功能,因此它们将派生自基类(Mailer).

以下是我不完整的代码段:

class Mailer(object):
    __metaclass__ == abc.ABCMeta

    def __init__(self,key):
        self.key = key

    @abc.abstractmethod
    def send_email(self, mailReq):
        pass


class MailGunMailer(Mailer):
    def __init__(self,key):
        super(MailGunMailer, self).__init__(key)

    def send_email(self, mailReq):
        from = mailReq.from
        to = mailReq.to
        subject= mailReq.subject
        text = mailReq.text
        options = getattr(mailReq,'options',None)
        if(options != None):
            if MailRequestOptions.BCC in options:
                #use this property
                pass
            if MailRequestOptions.CC in options:
                #use this property
                pass



class MailRequest():
    def __init__(self,from,to,subject,text):
        self.from = from
        self.to = to
        self.subject = subject
        self.text = text

    def set_options(self,options):
        self.options = options

class MailRequestOptions():
    BCC = "bcc"
    CC = "cc"
Run Code Online (Sandbox Code Playgroud)

问题:

  1. send_mail方法可以采用多个参数(from, to, subject, text, cc, bcc等等),我的应用程序中只需要其中的四个参数.由于该方法的参数数量太多,我决定创建一个名为的包装器对象MailRequest,该对象将具有作为属性的四个必要参数,并且可以在options字典中定义所有其他参数.问题是,在这里,只看代码,没有办法说options是.是一个dict还是一个list?另外,看看这个send_email方法,也没办法说出是什么mailReq.这是不好的编程习惯吗?我应该做别的吗?来自Java世界,编写代码让我感到非常不舒服,只需查看代码就无法知道参数是什么.我在Python中了解了注释,但我不想使用它们,因为它们仅在以后的版本中得到支持.

  2. 由于optionsdict应该用于指定许多其他属性(cc并且bcc只是其中两个),我创建了一个新类,调用MailRequestOptions了所有可以在选项dict中指定为MailRequestOptionss静态字符串的选项.这也是不好的做法,还是有更好的方法来做到这一点?我知道,这不是特定于Python的.

jon*_*rpe 5

Python是一种"鸭型"语言; 如果它像鸭子一样走路,像鸭子一样嘎嘎叫,它就是一只鸭子!或者,在执行方面,如果传递的mailReqfrom,to,subjecttext属性,它其实并不重要无论它是否是一个MailRequest.

如果你想记录界面(这当然是一个好主意),通常使用docstrings来这样做.我喜欢谷歌风格,它可以用来sphinx-napoleon自动生成人类可读的文档,但其他的可用.

def send_email(self, mailReq):
    """Send an email.

    Args:
      mailReq (MailRequest): the configuration for the email.

    """
    ...
Run Code Online (Sandbox Code Playgroud)

至于你的第二个问题; 将大量参数包装到容器对象中是一种非常常见的模式.在Python中,您可以选择使用" **kwargsmagic"使事情变得更简单(参见例如**(双星)和*(星)对参数做什么?):

def send_email(self, from_, to, subject, text, **config):
    ...
    bcc = config.get('bcc', [])  # option from config or a default
    ...
Run Code Online (Sandbox Code Playgroud)

(注意,这from是Python中的关键字,因此不能是参数的名称).

这样做的优点是可以合理地自我记录 - 有四个必需的参数,以及一些任意的附加关键字配置选项(通常也会记录在docstring中).


Ale*_*lex 4

  1. 在 Python 中,不需要专门创建另一个对象。如果你想包装邮件请求,你可以使用字典:mailReq = {'from': 'johnsmith@british.com', 'to': '....', ...}

  2. 您应该尝试使用*argsand **kwargsfor 方法。它可以使选项变得更加简单:def send_mail(from, to, subject, text, **kwargs),然后可以使用例如检索其他选项kwargs['bcc']。我相信这会更Pythonic。