2

I want a class in Python with an interface like the following:

import myclass

client = myclass.Client("user", "password")

client.users.create("user1")
client.posts.create("user1", "Hello, World!")

Note that instead of just create_user or create_post, I want to specify the method using two dots: users.create / posts.create

I want this particular interface to mimic an HTTP API I'm trying to work with (which has endpoints like "/api/users/create" and "/api/posts/create")

If I define my class as follows in myclass.py:

class Client(object):
    def __init__(self, user, pass):
        self.user = user
        self.pass = pass

Then how do I create these dot-namespaced methods? My first thought is to create subclasses like so:

class Client(object):
    def __init__(self, user, pass):
        self.user = user
        self.pass = pass
        self.users = ClientUserAPI()
        self.posts = ClientPostAPI()

class ClientUserAPI(object):
    def create(self):
        # Do some cURL magic

class ClientPostAPI(object):
    def create(self):
        # Do some cURL magic

However if I do this, then I run into one of two problems (one serious, the other just philosophical / ideological)

  1. If ClientUserAPI extends "Client" then the __init__ method creates an infinite loop
  2. If ClientUserAPI extends "object" then it won't directly have access to the self.user and self.pass variables. This means I must create __init__ methods on both of the helper classes which do nothing but assign self.user and self.pass. This is redundant not only in code, but also in memory

Is there a better solution?

5
  • 1
    What you have looks fine. Why would ClientUserAPI need access to self.user? Commented Jan 23, 2018 at 16:25
  • 3
    If you insist on the notation client.users..., then users must be an object, meaning an independent class, meaning you must implement it as standalone class. The Client class would then merely compose two of those independent classes into one client object. There's no need for it to be the parent class of anything. Memory consumption is pretty irrelevant with these values. Commented Jan 23, 2018 at 16:29
  • 1
    In other languages like e.g. Java you could create inner classes but objects of these would internally also hold a reference to the outer object. In Python you should do the same, but with explicit constructor parameter. Commented Jan 23, 2018 at 16:30
  • Only alternative would be to create an object on demand each time the attributes users or posts are requested but this would need CPU instead of memory. Commented Jan 23, 2018 at 16:32
  • ClientUserAPI needs access to self.user because the user and password must be passed to the HTTP API when a request is made. Therefore ClientUserAPI.create must send off an HTTP request with the username and password Commented Jan 23, 2018 at 16:40

1 Answer 1

5
class Client:
  def __init__(self):
    self.users = ClientUserAPI(self)
    self.posts = ClientPostAPI(self)

class ClientUserAPI:
  def __init__(self, client):
    self.client = client

class ClientPostAPI:
  def __init__(self, client):
    self.client = client
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.