在继承httplib.HTTP(s)Connection时处理SSL与非SSL连接

1 投票
3 回答
506 浏览
提问于 2025-04-15 13:37

我有一个类,它是从httplib.HTTPSConnection这个类继承来的。

class MyConnection(httplib.HTTPSConnection):
  def __init__(self, *args, **kw):
    httplib.HTTPSConnection.__init__(self,*args, **kw)
    ...

我想知道在创建这个类的时候,是否可以关闭SSL层,这样我就可以用它和不安全的服务器进行通信了?

在我的情况下,在初始化之前就已经知道是否需要使用SSL,所以另一种解决方案是尝试把继承关系从httplib.HTTPSConnection改成httplib.HTTPConnection,但我也不太确定怎么才能合理地做到这一点?

3 个回答

0

看起来你想用 MyConnection 来连接多个不同的主机。如果是这样的话,你就不应该从 HTTP(S)Connection 这个类去继承,因为这个类并不适合用来处理多个连接。相反,你可以让 MyConnection 拥有 一个 HTTP(S)Connection。

2

根据你最后一段的内容,在Python中,你可以使用类似工厂模式的东西:

class Foo:
    def doit(self):
        print "I'm a foo"
class Bar:
    def doit(self):
        print "I'm a bar"

def MakeClass(isSecure):
    if isSecure:
        base = Foo
    else:
        base = Bar

    class Quux(base):
        def __init__(self):
            print "I am derived from", base

    return Quux()

MakeClass(True).doit()
MakeClass(False).doit()

输出结果:

I am derived from __main__.Foo
I'm a foo
I am derived from __main__.Bar
I'm a bar
1

根据我对@Mark回答的评论,我喜欢他提倡的工厂方法。不过,我不会完全按照他的方式来做,因为他每次都新建一个类。相反,这里可以很好地使用混入(mixin)和super,如下所示:

class MyConnectionPlugin(object):
  def __init__(self, *args, **kw):
    super(MyConnectionPlugin, self).__init__(*args, **kw)
    # etc etc -- rest of initiatizations, other methods

class SecureConnection(MyConnectionPlugin,
                       httplib.HTTPSConnection, object):
  pass

class PlainConnection(MyConnectionPlugin,
                      httplib.HTTPConnection, object):
  pass

def ConnectionClass(secure):
  if secure:
    return SecureConnection
  else:
    return PlainConnection

conn = ConnectionClass(whatever_expression())()

等等。

当然,还有其他选择,因为在Python中,一个对象可以改变自己的__class__,等等。不过,就像用犀牛步枪打苍蝇一样,使用过于强大的(非常复杂、深奥,几乎像魔法一样的语言特性)来解决那些可以用合理的方法轻松解决的问题(就像用苍蝇拍一样),并不是一个好主意;-)。

编辑:在基类中额外注入object只是为了弥补一个不太好的事实,那就是在Python 2.*中,HTTPConnection类是旧式的,因此与其他类不太兼容——可以看看...:

>>> import httplib
>>> class Z(object): pass
... 
>>> class Y(Z, httplib.HTTPConnection): pass
... 
>>> Y.mro()
[<class '__main__.Y'>, <class '__main__.Z'>, <type 'object'>, <class httplib.HTTPConnection at 0x264ae0>]
>>> class X(Z, httplib.HTTPConnection, object): pass
... 
>>> X.mro()
[<class '__main__.X'>, <class '__main__.Z'>, <class httplib.HTTPConnection at 0x264ae0>, <type 'object'>]
>>> 

在类Y中,方法解析顺序(也叫MRO)在没有额外注入object基类的情况下,会先找到来自httplib的类(所以super无法正确工作),但额外的注入会调整MRO以进行补偿。可惜的是,在处理旧式类时,Python 2.*需要这样小心;幸运的是,在Python 3中,旧式风格已经消失,每个类都能“和谐相处”,这才是应该的!-)

撰写回答