Methods on descriptors

2019-08-29 05:00发布

I'm trying to implement a wrapper around a redis database that does some bookkeeping, and I thought about using descriptors. I have an object with a bunch of fields: frames, failures, etc., and I need to be able to get, set, and increment the field as needed. I've tried to implement an Int-Like descriptor:

class IntType(object):
    def __get__(self,instance,owner):
        # issue a GET database command
        return db.get(my_val)

    def __set__(self,instance,val):
        # issue a SET database command
        db.set(instance.name,val)

    def increment(self,instance,count):
        # issue an INCRBY database command
        db.hincrby(instance.name,count)

class Stream:
    _prefix = 'stream'
    frames = IntType()
    failures = IntType()
    uuid = StringType()

s = Stream()

s.frames.increment(1)  # float' object has no attribute 'increment'

Is seems like I can't access the increment() method in my descriptor. I can't have increment be defined in the object that the __get__ returns. This would require an additional db query if all I want to do is increment! I also don't want increment() on the Stream class, as later on when I want to have additional fields like strings or sets in Stream, then I'd need to type check the heck out of everything.

标签: python redis
3条回答
2楼-- · 2019-08-29 05:09

Try this:

class IntType(object):
    def __get__(self,instance,owner):
        class IntValue():

            def increment(self,count):
                # issue an INCRBY database command
                db.hincrby(self.name,count)

            def getValue(self):
                # issue a GET database command
                return db.get(my_val)

        return IntValue()

   def __set__(self,instance,val):
       # issue a SET database command
       db.set(instance.name,val)
查看更多
Explosion°爆炸
3楼-- · 2019-08-29 05:10

Why not define the magic method iadd as well as get and set. This will allow you to do normal addition with assignment on the class. It will also mean you can treat the increment separately from the get function and thereby minimise the database accesses.

So change:

    def increment(self,instance,count):
        # issue an INCRBY database command
        db.hincrby(instance.name,count)

to:

    def __iadd__(self,other):
        # your code goes here
查看更多
劫难
4楼-- · 2019-08-29 05:17

Does this work?

class Stream:
    _prefix = 'stream'

    def __init__(self):
        self.frames = IntType()
        self.failures = IntType()
        self.uuid = StringType()
查看更多
登录 后发表回答