search

Home  >  Q&A  >  body text

python - 如何交换两个shelve对象?

假定db1, db2 是shelve对象

if switch_d1_and_db2:
    func(db1, db2)
else:
    func(db2, db1)

怎么才能改写成:

if switch_d1_and_db2:
    db1, db2 = db2, db1 # 错误写法
func(db1, db2)

db1, db2 = db2, db1 肯定是不行的,怎么改写呢

PHPzPHPz2891 days ago662

reply all(1)I'll reply

  • 高洛峰

    高洛峰2017-04-18 09:18:15

    Hello, after studying this problem for a while, I came to the conclusion:

    1. It’s too difficult to do and the syntax you want to use doesn’t match what you want to do

    2. I think there is nothing wrong with using the original method

    3. If you want to achieve the exchange you defined, then I have an alternative that is not too beautiful, you can refer to it

    The following is an explanation of the above three points:

    For the first point, you want:

    db1, db2 = db2, db1

    No matter what kind of object db1, db2 is here, the meaning of this exchange is

    Let db1 這個變數參考到原本 db2 所參考的 object, 並讓 db2 這個變數參考到原本 db1 be the object referenced.

    But what you want to do is:

    Let db1 這個 file 和 db2 swap the contents of this file

    Think about it carefully, these two things are not the same. To put it another way, db1, db2 = db2, db1, it will only make the things referenced by the variables interchange (the variable names are not equal to the file names of the db), but the contents of each file are still not interchangeable. Change.

    So using this syntax to interchange is not consistent with the effect you want to achieve.

    I won’t elaborate on the second point because it’s reasonable, but you may not like it.

    The third point is that I gave a less beautiful alternative, which is to simply define a shelf 的代理類 ShelfProxy, 這個類盡量模擬 Shelf 類的行為(僅是介面上相似), 並且重載了運算符 ^ defined as exchange:

    import shelve
    
    class ShelfProxy:
    
        def __init__(self, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs
            self.file = args[0]
            self.loaddb()
    
        @classmethod
        def open(cls, *args, **kwargs):
            return cls(*args, **kwargs)
    
        def __getattr__(self, name):
            return getattr(self.dic, name)
    
        def __setitem__(self, name, value):
            self.dic[name] = value
    
        def __getitem__(self, name):
            return self.dic[name]
    
        def __xor__(self, other):
            self.dic, other.dic = other.dic, self.dic
            return True
    
        def __str__(self):
            return str(self.dic)
    
        def loaddb(self):
            db = shelve.open(*self.args, **self.kwargs)
            self.dic = dict(db.items())
            db.close()
    
        def close(self):
            newdb = shelve.open(self.file, *self.args[1:], **self.kwargs)
            for key in newdb.keys():
                del newdb[key]
            for key, value in self.dic.items():
                newdb[key] = value
            newdb.close()

    I define ^ as ^ 定義為 內容上的交換, 之所以選 ^exchange of content

    . The reason why I chose ^ is just because I can’t think of a more suitable symbol. Generally speaking, overloading will not be done like this. And it is unlikely to return instances of other classes, but for convenience and because you want a simple interface, I came up with this strategy.

    Then we define some test functions:

    def define():
        db1 = ShelfProxy.open('db1', writeback=True)
        db2 = ShelfProxy.open('db2', writeback=True)
        db1['name'] = 'db1'
        db2['name'] = 'db2'
        db1.close()
        db2.close()
    
    def check():
        db1 = ShelfProxy.open('db1', writeback=True)
        db2 = ShelfProxy.open('db2', writeback=True)
        print('db1:', db1)
        print('db2:', db2)
        db1.close()
        db2.close()
    
    def switch():
        print('switch')
        db1 = ShelfProxy.open('db1', writeback=True)
        db2 = ShelfProxy.open('db2', writeback=True)
        db1 ^ db2
        db1.close()
        db2.close()

    Test code:

    if __name__ == '__main__':
        define()
        check()
        switch()
        check()

    Result:

    db1: {'name': 'db1'}
    db2: {'name': 'db2'}
    switch
    db1: {'name': 'db2'}
    db2: {'name': 'db1'}

    Conclusion

    Shelf 相同的介面來操作 ShelfProxyMost of the time, you can use

    , and the overall effect is similar, but don’t you think it’s easier to use the method from the beginning after writing so much? XD

    Questions I answered

    : Python-QA🎜

    reply
    0
  • Cancelreply