【问题标题】:Universally create Derived class from Base in python在 python 中从 Base 通用创建派生类
【发布时间】:2013-05-20 23:08:45
【问题描述】:

在SO上找到了一些问题,但仍然没有答案...有一个数据类

class Proxy(object):
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port

有一个 getter 类应该从不同的来源读取这些数据

class FileProxyGetter(ProxyGetter):
    def __init__(self, fname = "d:\\proxies.txt"):
        self.fileName = fname 

    def Get(self):
        proxies = []

        f = open(self.fileName)

        for l in f.xreadlines(): 
            proxies.append(Proxy.fromstring(l[:-1]))

        f.close()

        return proxies

    def Update(self):
        return []

我需要一个具有更多选项的代理类,例如

class SecureProxy(Proxy):
    def __init__(self, ip, port):
        super(SecureProxy, self).__init__(ip, port)
        self.transparent = None

现在我想改进 FileProxyGetter 如下:

class FileSecureProxyGetter(FileProxyGetter):
    def Get(self):
        proxies = super(FileProxyGetter, self).Get()
        secureProxies = []
        for proxy in proxies:
            # Create or Cast Proxy to SecureProxy.
            # The transparent should be initialized to None or any other value that I may need
            secureProxies.append(SecureProxy(proxy))

        return secureProxies

那么我如何在 Python 中普遍地从基类转换或创建派生类的实例。如果不需要更改类会更好。

或者你能建议更多的 Pythonic 方式来开发这种关系和架构?

【问题讨论】:

  • 我不明白这一点 - 你有 Proxy 和 FileProxyGetter。然后你写 SecureProxy 并希望 FileSecureProxyGetter 自动出现 - 对吗?
  • @GillBates 不,我是手动创建的。我想从只调用 SecureProxy 构造函数的代理中创建 SecureProxy
  • 并不是说它解决了你的问题,而是你读取文件行的​​方式有两个问题。首先,使用with open(..) as f: 打开和自动关闭文件,即使在出现异常或提前返回的情况下也能正常工作。然后,for line in f: 是遍历文件行的惯用方式。也就是说,为了解决您手头的问题,您是否考虑过使用在工厂中注册所有派生类的元类?或者,您可以将正确的类型传递给ProxyGetter.Get()。

标签: python class architecture derived-class base-class


【解决方案1】:

你可以使用继承:

class FileProxyGetter(ProxyGetter):
    ...
    def MakeProxy(self, *args, **kwargs):
        return Proxy.fromstring(*args, **kwargs)
    def Get(self):
        ...
           proxies.append(self.MakeProxy(l[:-1]))
        ...
    ...
class FileSecureProxyGetter(FileProxyGetter):
    def MakeProxy(self, *args, **kwargs):
        return SecureProxy.fromstring(*args, **kwargs)

但在这种情况下使用合成可能更有用。

class FileProxyGetter(ProxyGetter):
    def __init__(self, proxyclass, fname = "d:\\proxies.txt"):
        self.proxyClass = proxyclass
        self.fileName = fname
    ...
    def Get(self):
        ...
            proxies.append(self.proxyclass.fromstring(l[:-1]))
        ...
    ...

# use this as such
FileProxyGetter(Proxy, "proxies.txt")
FileProxyGetter(SecureProxy, "secure_proxies.txt")

编辑:python 中用于切换对象类型的肮脏技巧:

>>> class A(object):
...     def foo(self):
...         print 'hello A'
... 
>>> class B(object):
...     def foo(self):
...         print 'hello B'
... 
>>> a = A()
>>> a.foo()
hello A
>>> a.__class__
<class '__main__.A'>
>>> a.__class__ = B
>>> a.foo()
hello B

两个不同类型的对象共享相同状态的另一个肮脏技巧:

>>> class B(object):
...     def rename(self, name):
...         self.name = name
... 
>>> class A(object):
...     def say(self):
...         print 'Hello', self.name
... 
>>> a, b = A(), B()
>>> a.__dict__ = b.__dict__
>>> b.rename('john')
>>> a.say()
Hello john
>>> a.rename('mary')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'rename'
>>> b.say()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'B' object has no attribute 'say'

然而,这些技巧虽然在 Python 中是可行的,但我不会称它们为 pythonic 或好的 OO 设计。

Python 3.x 及更高版本中的另一种可能性,它删除了“未绑定方法”以代替使用常规函数:

>>> class A(object):
...     def say(self):
...         print('Hello', self.name)
... 
>>> class B(object):
...     def rename(self, name):
...         self.name = name + name
... 
>>> a = A()
>>> B.rename(a, 'josh')
>>> a.say()
Hello joshjosh

【讨论】:

  • 第一个很好,但我不喜欢在这个解决方案中基类需要知道代理类的“种类”。实际上,当我已经有了基本实例时,我想创建一个派生的基本实例
  • @Romeno:在python中,变量是无类型的,而对象是强类型的。切换对象的类有几个肮脏的技巧,请参阅我的答案中的编辑。
  • 谢谢,这说明了 python 没有这样的内置功能,因为即使有这些技巧 init 也不会被调用,我应该在设计类时考虑到可以这样使用。
  • @Romeno:如果你愿意,你可以自己调用 init。或者,您可以在 SecureProxy.__new__(proxy) 中进行 dict 交换,以模拟其他语言的“不安全向上转换”行为。这样做并不是一个好的 OO 设计,尽管 Python 确实使它成为可能(在 C/C++ 中这样做很可能会导致无声的内存损坏;或者 Java 中的 ClassCastException)。更重要的是,你真正想要做什么?也许有更好、更面向对象、更 Python 的方式来做你需要做的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-02
  • 1970-01-01
  • 1970-01-01
  • 2023-01-26
  • 1970-01-01
  • 2018-05-20
  • 2015-08-10
相关资源
最近更新 更多