我只有Java的OOP编程经验,并且刚刚开始用Python开发一个项目,我开始意识到Python让我对一些直观的东西产生怀疑。所以我有几个关于Python中OOP的问题。在
场景:我正在写一个可以发送电子邮件的程序。对于电子邮件,to
、from
、text
和{cc
和{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"
问题:
send_mail
方法可以接受多个参数(from, to, subject, text, cc, bcc
,等等),在我的应用程序中只需要其中四个参数。由于该方法的参数数目太多,我决定创建一个名为MailRequest
的包装器对象,它将有四个必要的参数作为属性,所有其他参数都可以在options
字典中定义。问题是,在这里,仅仅看一下代码就不能说options
是。是^{list
?另外,看一下send_email
方法,也没有办法知道mailReq
是什么。这是一种糟糕的编程实践吗?我应该做点别的吗?来自Java世界,编写代码时,如果仅仅通过查看代码就无法判断参数是什么,这让我非常不舒服。我了解了Python中的注释,但我不想使用它们,因为它们只在以后的版本中受支持。
由于options
dict应该用于指定许多其他属性(cc
和bcc
只是其中的两个),我创建了一个新的类MailRequestOptions
,其中所有的选项都可以在选项dict中指定为MailRequestOptions
的静态字符串。这种做法也不好,还是有更好的方法?我知道这并不是Python特有的。
在Python中,不需要专门创建另一个对象。如果要包装邮件请求,可以使用字典:
mailReq = {'from': 'johnsmith@british.com', 'to': '....', ...}
您应该尝试使用
*args
和**kwargs
作为方法。{cd4}可以更简单地使用其他选项。我相信这会更像Python。虽然jornsharpe提供了一个很好的解决方案,但我认为值得一提的是我的方法。在
如前所述,在动态语言中,您不关心类型,只关心对象具有的接口(所谓的“duck”)。那么,您的
MailRequest
对象是将逻辑上属于一起的参数分组的极好方法。然而,它并没有实现它应该实现的一切。我的方法是:然后
^{pr2}$send_email
函数如下所示:注意,您只是记录了
mailReq
参数,指出传递的任何对象都应该提供MailRequest
接口(至少部分)。这样,可以将参数的文档委托给MailRequest
类。在与
**kwargs
魔术相比,我更喜欢这种方法,因为参数在某个时刻显式地传递给一个刚性签名,该签名以某种方式充当文档。缺点是冗长。在编辑
如果您担心
MailRequest
“构造函数”中的参数爆炸,解决方案是再做一个更深层次的操作:再次分组。例如,您可能希望将选项分组到自己的类中:然后
MailRequestClass
将如下所示:最后,如果一个进程需要50个参数,那么在某个时刻,您无法避免将它们全部传递给一个或多个分布式函数。你把他们分成几组取决于你和你在哪里找到平衡。在
Python是一种"duck-typed"语言;如果它走路像鸭子,嘎嘎叫得像鸭子,那它就是鸭子!或者,在实现方面,如果作为
mailReq
传递的对象具有from
、to
、subject
和text
属性,它是否是MailRequest
并不重要。在如果您想记录接口(这当然是一个好主意),通常使用docstrings来完成。我喜欢the Google style,它可以与
sphinx-napoleon
一起使用,以自动生成人类可读的文档,但也可以使用其他文档。在至于您的第二个问题:将大量参数包装到容器对象中是一个pretty common pattern。在Python中,您可以选择使用“
^{pr2}$**kwargs
magic”(参见例如What does ** (double star) and * (star) do for parameters?):(注意,
from
是Python中的关键字,因此不能是参数的名称)。这样做的好处是可以合理地自我文档化——有四个必需的参数,外加一些任意的附加关键字配置选项(同样,这通常会记录在docstring中)。在
相关问题 更多 >
编程相关推荐