1
\$\begingroup\$

In some of my peewee-based ORM models, I need to access the instance as well as the respective class. Since I caught myself always repeating the line cls = self.__class__ at the top of each such methods, I wrote a decorator for that:

def with_class(function):
    """Adds the instance's class as second
    parameter to the wrapped function.
    """

    @wraps(function)
    def wrapper(self, *args, **kwargs):
        """Wraps the given function."""
        return function(self, self.__class__, *args, **kwargs)

    return wrapper

Example use case:

class Location(_TerminalModel):
    """Location of a terminal."""

    address = CascadingFKField(Address, column_name='address')
    annotation = CharField(255, null=True)

    …

    @with_class
    def save_unique(self, cls, *args, **kwargs):
        """Saves the location if it is new or
        returns the appropriate existing record.
        """
        if self.annotation is None:
            annotation_selector = cls.annotation >> None
        else:
            annotation_selector = cls.annotation == self.annotation

        try:
            return cls.get((cls.address == self.address) & annotation_selector)
        except cls.DoesNotExist:
            self.save(*args, **kwargs)
            return self

I'd like to have critique on this solution and am open to alternatives.

\$\endgroup\$
2
  • 3
    \$\begingroup\$ So, you saved typing a single line at the expense of typing a single line? :-\ \$\endgroup\$ – bipll Jul 23 '18 at 13:19
  • \$\begingroup\$ @bipll Good point. \$\endgroup\$ – Richard Neumann Jul 23 '18 at 13:26
3
\$\begingroup\$

I'd recommend not using value.__class__. This is as it's not guaranteed to return the type.

type(x) is typically the same as x.__class__ (although this is not guaranteed – a new-style class instance is permitted to override the value returned for x.__class__).

Take:

class A:
    __class__ = 'something'

print(A.__class__)   # <class 'type'>
print(A().__class__) # 'something'
print(type(A()))     # <class '__main__.A'>

I also think just using type would be cleaner, and easier to understand.

def save_unique(self, *args, **kwargs):
    cls = type(self)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.