José
José

Reputation: 1

Pythonic way to encapsulate method arguments of a class

Objects of my class A are similar to network connections, i.e. characterized by a handle per connection opened. That is, one calls different methods with a handle (a particular connection) as argument. My class A (python 2.7) looks like:

class A(object):
  def __init__(self, *args):
    ... some init
  def my_open(self, *args)
    handle = ... some open
    return handle
  def do_this(self, handle, *args):
    foo_this(handle, args)
  def do_that(self, handle, *args):
    foo_that(handle, args)

A typical usage is

a = A(args)
handle = a.my_open(args2)
a.do_this(handle, args3)

Now, in a particular situation, there is only one connection to take care of, i.e. one handle in play. So, it is reasonable to hide this handle but keep class A for the more general situation. Thus, my first thoughts on a class B which "is a" kind of class A (usage stays the same but hides handle) are:

class B(A):
  def __init__(self, *args):
    super(A, self).__init__(args)
    self.handle = None
  def my_open(self, *args):
    self.handle = super(A, self).__init__(args)
  def do_this(self, *args):
    super(A, self).do_this(self.handle, args)
  def do_that(self, *args):
    super(A, self).do_that(self.handle, args)

Unfortunately, in my opinion, it seems very convoluted. Any better ideas?

Upvotes: 0

Views: 590

Answers (2)

Martijn Pieters
Martijn Pieters

Reputation: 1121952

Objects of my class A are similar to network connections, i.e. characterized by a handle per connection opened. That is, one calls different methods with a handle (a particular connection) as argument.

You have inverted the responsibility. The handle object holds the state the methods operate on, so those methods should live on the handle, not the factory.

Move your methods to the handle object, so the API becomes:

a = A(args)
handle = a.my_open(args2)
handle.do_this(args3)

The class implementing the handle() could retain a reference to a if so required; that's an implementation detail that the users of the API don't need to worry about.

You then return new handles, or a singleton handle, as needed.

By moving responsibility to the handle object, you can also make your factory produce handles of entirely different types, depending on the arguments. A(args).my_open(args2) could also produce the singleton handle that you now have class B for, for example.

Upvotes: 1

Matias Cicero
Matias Cicero

Reputation: 26281

How about a class for the handle itself?:

class Handle(object):
    def __init__(self, *args):
        # init ...
        self._handle = low_level_handle
    def do_this(self, *args):
        # do_this ...
        pass
    def do_that(self, *args):
        # do_that
        pass

class A(object):
    def __init__(self, *args):
       # init ...
    def my_open(self, *args):
       handle = Handle(args)
       # handle post-processing (if any)
       return handle

e.g.:

a = A(args)
handle = a.my_open(args2)
handle.do_this(args3)

Upvotes: 0

Related Questions