Code Monkey home page Code Monkey logo

Comments (7)

Suor avatar Suor commented on May 24, 2024

funcy already has LazyObject doesn't it work for you? If not can you please explain the specifics?

from funcy.

luismsmendonca avatar luismsmendonca commented on May 24, 2024

Hi @Suor , yes I use it a bunch for initialization too. The pattern I'm describing is something along the lines of:

foo_api = Proxy()
foo_api_1 = FooApi()
foo_api.initialize(foo_api_1)
foo_api.bar() # uses foo_api_1

foo_api_2 = FooApi()
foo_api.initialize(foo_api_2)
foo_api.bar() # uses foo_api_2

I find this pattern useful for testing and abstracting connections to db's and stuff.

This cannot be accomplished with the LazyObject since _setup cannot be called for an adhoc object (same as with other libraries mentioned before). This is not much of a "Lazy" pattern but a "deferred" initialization one I believe.

Thanks. Luis

from funcy.

Suor avatar Suor commented on May 24, 2024

And how you want it to look? The same way it's in your code then that could be achieved with something like:

def make_proxy():
    obj = None

    @LazyObject
    def proxy():
        if obj is None:
            raise ValueError("You need to init the proxy before using it")
        return obj

    def init(api):
        nonlocal obj
        obj = api

    return proxy, init

And use it like:

foo_api, init_foo_api = make_proxy()
init_foo_api(FooApi())
foo_api.bar()

It could also be integrated into LazyObject itself somehow, i.e. by allowing ._setup() to accept arguments or smth. Or simply subclassing it, rewriting how initialization is done.

from funcy.

Suor avatar Suor commented on May 24, 2024

The full thing could be written as:

class DeferInitObject:
    def init(self, obj):
        object.__setattr__(self, '__class__', obj.__class__)
        object.__setattr__(self, '__dict__', obj.__dict__)

    def __getattr__(self, name):
        raise ValueError("You need to init the proxy before using it")

    def __setattr__(self, name, value):
        raise ValueError("You need to init the proxy before using it")

Won't work when obj has a class with slots though, same as LazyObject.

from funcy.

luismsmendonca avatar luismsmendonca commented on May 24, 2024

Hi @Suor,

Thank you very much for your replies.

In the examples you gave the proxy object can only be initialized once and not multiple times like in the example I gave.

Example:

class Foo():
    def bar(self):
        print(id(self))
        
p = DeferInitObject()

p.init(Foo())
p.bar()

p.init(Foo())
p.bar()

on the second init it will raise AttributeError: 'Foo' object has no attribute 'init'

where as with the make_proxy:

p, p_init = make_proxy()

p_init(Foo())
p.bar()

p_init(Foo())
p.bar()

will print same id, i.e.:

$ python foo.py 
140142395670336
140142395670336

effectively not using the second init.

Just as an example:

from peewee import Proxy

p = Proxy()

p.initialize(Foo())
p.bar()

p.initialize(Foo())
p.bar()

gives:

$ python foo.py 
140282243186400
140282243186352

Again, when I'm using peewee I use the Proxy that comes with it, but when no sql db is needed and I don't have peewee installed I find it silly to include a sql db library just to apply this pattern.

Since funcy is always the first in the list :) and this is akin to its sort of utilities, I was wondering if there is an opening to include it.

Thanks,

Luis

from funcy.

Suor avatar Suor commented on May 24, 2024

Ok, I see, I missed that you rewrite the object twice. The name initialize also didn't help. I guess one may get rewiring code out and make it work like:

def rewire(dest, source):
    object.__setattr__(dest, '__class__', source.__class__)
    object.__setattr__(dest, '__dict__', source.__dict__)

foo_api = object()
foo_api_1 = FooApi()
rewire(foo_api, foo_api_1)
foo_api.bar() # uses foo_api_1

foo_api_2 = FooApi()
rewire(foo_api, foo_api_2)
foo_api.bar() # uses foo_api_2

Or you can simply copy this peewee.Proxy code to your project and use it. Or do something in-between.

It might be useful to have it in funcy in some form, not sure which one exactly though.

Also, making it explicit instead of implicit is also an option if you control the using part of your code:

foo_api = Proxy()
foo_api.client = FooApi()
foo_api.client.bar() # uses foo_api_1

foo_api_2 = FooApi()
foo_api.client = foo_api_2
foo_api.client.bar() # uses foo_api_2

This might be easier on the code reader in the future.

from funcy.

luismsmendonca avatar luismsmendonca commented on May 24, 2024

Hi @Suor,

Never realized how easy it to do this with this rewiring snippet you gave.

Thanks :)

from funcy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.