0

In the following code, Graph() is acting as a proxy to Vertex and Edge -- clients only access Vertex and Edge through Graph():

from rest import Resource
from elements import Vertex, Edge

class Graph(object):
    def __init__(self,db_url):
        self.resource = Resource(db_url)
        self.vertices = Vertex
        self.edges = Edge

g1 = Graph('http://localhost/one')   
g2 = Graph('http://localhost/two')

What are the best ways for Vertex and Edge to access the resource object, without having to pass it as a param to Vertex and Edge?

One of the reasons I don't want to pass it as a param is because Vertex and Edge have classmethods, such as create(), that need access to the resource object too.

Flask/Werkzeug uses "context locals" (http://werkzeug.pocoo.org/docs/local/) -- is that the right approach here, or is there a better way?

espeed
  • 4,754
  • 2
  • 39
  • 51
  • by proxy you mean just another reference? –  Jun 28 '11 at 03:25
  • In this case Graph() is acting as a proxy to Vertex and Edge because clients are only accessing Vertex and Edge through Graph(). – espeed Jun 28 '11 at 03:33
  • 1
    You probably want to stop using "proxy objects", and read up about "Dependency Injection" instead, although python fans tend to ignore that saying that the interpreter itself is a dependency injection framework (because you can dynamically change the name of a class to suit your circumstances) – Arafangion Jun 28 '11 at 03:38

1 Answers1

1

If your resource object is unique, could you make it a singleton? The fact that you want to use it from a class method makes me think that it's probably the case. If its only purpose is to provide the database connection, could you consider using a connection pool?

If you still need to pass it to your classes, you can simply assign it to class attributes.

class Vertex(object):
    @classmethod
    def foo(cls):
        print cls.resource

Vertex.resource = 'something'
v = Vertex()
v.foo()

This can also be done in __init__:

class Vertex(object):

    def __init__(self, resource):
        if not hasattr(self.__class__, 'resource'):
            self.__class__.resource = resource

    @classmethod
    def foo(cls):
        print cls.resource

resource = 'some resource'
v = Vertex(resource)
v.foo()

But really my intuition is that you should look into using a singleton, which in many cases can be implemented in Python simply as a module.

Finally if I can make a couple of remarks about your code, I find it confusing that you're assigning classes to plural variable names. When I see self.edges I would expect a collection or an iterable, not a class. I also wonder why you would want a class method called create. What does it do that __init__ cannot do?

Alex Marandon
  • 4,034
  • 2
  • 17
  • 21
  • Hi Alex - Thanks for the feedback. The Vertex and Edge class provide interfaces for interacting with the graph DB, such as graph.vertices.get_all() and graph.edges.get(edge_id), etc. Are you suggesting they should be renamed to graph.vertex.get_all(), etc? The db_url is passed in as a param when creating the resource object, and the graph API provides the user the ability to access multiple DBs by passing in a different DB URL when creating the graph object. I have looked into using a module as a global singleton but this had issues when creating two graph objects with different URLs. – espeed Jun 28 '11 at 06:19
  • 1
    OK I think the problem is that you're trying to make classes behave like objects. You're trying to make classes that dynamically change their behaviour depending on data. That's really what objects are for. I suggest you introduce container classes to manage your vertices and edges. – Alex Marandon Jun 28 '11 at 07:14
  • By the way, as Arafangion suggested, you're not proxying here, because you're giving direct access to the objects you intend to proxy. To convince yourself of this, ask yourself how you would log or count access to your "proxied" objects (typical use cases for proxies). – Alex Marandon Jun 28 '11 at 07:20
  • +1. Classes define data types. A dog owner owns one or more dogs; s/he does not own the concept of a dog. The lines `self.vertices = Vertex` and `self.edges = Edge` are therefore very worrying. – Karl Knechtel Jun 28 '11 at 07:22
  • Using multiple classes is how I had originally designed it. Switching to a single class simplified much of the code, and now I'm just trying to work through this last little issue. I'll go back an reevaluate. Thanks. – espeed Jun 28 '11 at 07:25