Giter VIP home page Giter VIP logo

Comments (9)

GrahamDumpleton avatar GrahamDumpleton commented on June 16, 2024

Not sure. There has to be special code for certain dunder attributes in the pure Python implementation because of how the Python object model works.

class _ObjectProxyMethods(object):

    # We use properties to override the values of __module__ and
    # __doc__. If we add these in ObjectProxy, the derived class
    # __dict__ will still be setup to have string variants of these
    # attributes and the rules of descriptors means that they appear to
    # take precedence over the properties in the base class. To avoid
    # that, we copy the properties into the derived class type itself
    # via a meta class. In that way the properties will always take
    # precedence.

    @property
    def __module__(self):
        return self.__wrapped__.__module__

    @__module__.setter
    def __module__(self, value):
        self.__wrapped__.__module__ = value

    @property
    def __doc__(self):
        return self.__wrapped__.__doc__

    @__doc__.setter
    def __doc__(self, value):
        self.__wrapped__.__doc__ = value

    # We similar use a property for __dict__. We need __dict__ to be
    # explicit to ensure that vars() works as expected.

    @property
    def __dict__(self):
        return self.__wrapped__.__dict__

    # Need to also propagate the special __weakref__ attribute for case
    # where decorating classes which will define this. If do not define
    # it and use a function like inspect.getmembers() on a decorator
    # class it will fail. This can't be in the derived classes.

    @property
    def __weakref__(self):
        return self.__wrapped__.__weakref__

class _ObjectProxyMetaType(type):
    def __new__(cls, name, bases, dictionary):
        # Copy our special properties into the class so that they
        # always take precedence over attributes of the same name added
        # during construction of a derived class. This is to save
        # duplicating the implementation for them in all derived classes.

        dictionary.update(vars(_ObjectProxyMethods))

        return type.__new__(cls, name, bases, dictionary)

class ObjectProxy(with_metaclass(_ObjectProxyMetaType)):

   ...

The line:

dictionary.update(vars(_ObjectProxyMethods))

should only be copying the function definition from the class type, not an instance, so the property shouldn't I don't think be dereferenced at that point.

So would need to work if this is working as intended and where __doc__ property is invoked.

from wrapt.

GrahamDumpleton avatar GrahamDumpleton commented on June 16, 2024

This may have more to do with strange Python rules about lookup order for __doc__ when mixing Python derived class, with C base class vs Python base class. Behaviour between Python and C objects isn't always exactly the same and strange things happen with some of the dunder methods.

from wrapt.

dgrigonis avatar dgrigonis commented on June 16, 2024

Python implementation works fine and metaclass takes care of things for all inherited classes, C implementation is where things "malfunction". And I like C for obvious reasons.

I found that what solves it is:

class MyCustomProxy(wrapt.ObjectProxy):
    @property
    def __doc__(self):
        return self.__wrapped__.__doc__

However, if I inherit from it, then I need to do the same for sub-class again...

Another solution is to mix & match:

class MyCustomProxy(wrapt.ObjectProxy, metaclass=_ObjectProxyMetaType):
    pass

class MyCustomProxy2(MyCustomProxy):
    pass

This way, python's meta implementation will take care of things on top of C implementation, even if inherited from it again.

I would look at it, but I am quite basic at C, so all I can do now is to point it out and give couple of hacks for it.

from wrapt.

GrahamDumpleton avatar GrahamDumpleton commented on June 16, 2024

The disparity with the C object proxy base class will be because it uses a C level getter/setter function slot for handling access to __doc__. A property in pure Python doesn't quite work the same when consider lookup resolution order from memory. To try and make the same one might have to avoid using getter/setter slots and add a descriptor object as attribute, similar to how property objects work. The overhead of that will be a bit more, although still small, and code will be bit more complicated in C implementation. Not sure how hard that would be to do.

from wrapt.

dgrigonis avatar dgrigonis commented on June 16, 2024

Just for curiosity, which functionality of ProxyObject benefits most from C's implementation over python's?

Construction seems to be about 5x, however attribute access, such as doc look similar.

Also, __doc__ access of C object with python's meta is actually slower than just using pure python: 0.038 vs 0.023, which is the same as C: 0.022

from wrapt.

GrahamDumpleton avatar GrahamDumpleton commented on June 16, 2024

Wasn't a case of choosing one over the other for a reason. When doing C based Python objects you just use the most obvious mechanism it provides for it. These strange situations like overriding __doc__ and that they behaved differently only became apparent many years after the original code was written.

from wrapt.

GrahamDumpleton avatar GrahamDumpleton commented on June 16, 2024

If the question was more around why bother with C implementation at all, was because back in Python 2.X days when machines were slower, any pure Python overhead could be noticeable, especially with the original use for wrapt, which was in New Relic Python web application performance monitoring instrumentation. So much was being instrumented and being continually exercised, pure Python variant had a noticeable overhead, which is last thing you want when instrumenting production systems.

from wrapt.

dgrigonis avatar dgrigonis commented on June 16, 2024

Thank you, that answered it.

from wrapt.

dgrigonis avatar dgrigonis commented on June 16, 2024

Do I leave this so that someone can take a look, or do I close this?

from wrapt.

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.