3

Found some questions on SO but still have no answer... There is a data class

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

There is a getter class which is supposed to read these data from different sources

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 []

I need to have a Proxy class with more options like

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

Now I want to improve FileProxyGetter as follows:

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

So how do I cast or create an instance of derived class from base class in Python universally. It would be better if no changes to the classes needed.

Or can you suggest more pythonic way of developing such relationships and architecture?

3
  • 1
    I dont get the point - you have Proxy and FileProxyGetter. Then you write SecureProxy and you want that FileSecureProxyGetter appear automatically - thats right? Commented May 25, 2013 at 14:27
  • @GillBates No, I created it manualy. I want to cast create SecureProxy out of Proxy calling only SecureProxy constructor Commented May 25, 2013 at 14:40
  • 2
    Not that it solves your problem, but your way of reading the lines of a file has two issues. Firstly, use a with open(..) as f: to open and automatically close the file, which works even in the presence of exceptions or an early return. Then, for line in f: is the idiomatic way to iterate over the lines of a file. That said, to address your problem at hand, have you considered using a metaclass that registers all derived classes in a factory? Alternatively, you could pass the correct type to ProxyGetter.Get(). Commented May 25, 2013 at 14:48

1 Answer 1

4

You can use inheritance:

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)

but it's probably more useful in this case to use composition.

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")

EDIT: A dirty trick in python to switch the type of an object:

>>> 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

Another dirty trick for two objects of different types to share the same state:

>>> 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'

However, these tricks, while possible in Python, I would not call them pythonic nor a good OO design.

Another possibility in Python 3.x and up, which had removed "unbound method" in place of using regular function:

>>> 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
Sign up to request clarification or add additional context in comments.

4 Comments

The first one is great but I don't like in this solution that Base classes Need to know that there are "kinds" of Proxy classes. Actually I want to create a derrived from base when I have the base instance already
@Romeno: In python, variables are typeless, while objects are strongly typed. There's several dirty tricks to switch the class of an object, see the edit on my answer.
Thanks, that clarifies that python has no such built-in ability because even with those tricks the init is not called and I should design the class with the thought in mind that it can be used that way.
@Romeno: you can call init yourself if you want to. Alternatively, you can do the dict swap inside SecureProxy.__new__(proxy) to emulate an "unsafe up-casting" behavior from other languages. Doing this isn't a good OO design, though Python does make it possible (doing the same in C/C++ will very likely get you silent memory corruptions; or a ClassCastException in Java). More importantly though, what are you really trying to do? There are perhaps better, more OO, and more pythonic way to do what you need to do.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.