简体   繁体   中英

Rename instances without duplicates

The code is Python, but it's more an algorithmic question I can't solve.

I use an API which defines a set of instances, each one is reachable by its Name property:

print(APIClass[a_name].Name)
>>> 'a_name'
print(APIClass[another_one].Name)
>>> 'another_one'

I want (and I'm allowed) to rename a specific instance, but I want to prevent any duplicate (which leads to an API crash). If I rename the second in my example to 'a_name' , I have first to rename the first one, eg:

APIClass[a_name].Name = 'a_name_old'
print(APIClass[a_name_old].Name)
>>> 'a_name_old'

and it's OK ( APIClass[another_name] = 'a_name' ). But I have to check first that no one else has a_name_old as property, and so on.

Should I populate a set with the Name properties, then rename each item, and then rename the instances? But in this case (I tried it), how to be sure that a 'new' name will not be the same that an old one? (in this case, my tries failed when renaming instances) Please note I don't want to remove any duplicates, just rename them.

EDIT:

The 'APIClass' are provided, I'm only a user and I can't modify them (by adding methods, or so on). I can only modify instances. So I want to modify the 'Name' property of one of them, but I have to check (and rename if needed) the other ones. If I rename one, in my opinion I have to re-check (and re-rename) the remainings. So I could do it with a recursive algorithm, but I thought this is not efficient (for memory eg).

Yes, you should have some sort of name directory as a class variable. Also, build a simple get/set interface for the Name property, so that any user will go through that instead of directly manipulating the name.

Your set_name method will check the list of existing names and act appropriately if the suggested name is already in use. Resolving a collision can be simple, such as appending a number.

I'm not sure what limitations you have on your APIClass . However, if you can implement some combination of instance name tracking and property setting/deleting then you can achieve what you want. Here is some code that implements just that:

class APIClass:
    instances = set()

    def __init__(self, name):
        self.name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, new_name):

        assert isinstance(new_name, str)
        if new_name in self.instances:
            raise ValueError(f'Name already in use: {new_name}')

        else:
            if hasattr(self, '_name'):  # must not be first time setting name
                self.instances.remove(self._name)  # Don't forget to remove the old name before changing
            self.instances.add(new_name)
            self._name = new_name

    @name.deleter
    def name(self):
        if self._name in self.instances:
            self.instances.remove(self._name)

    def __del__(self):

        # I wont delve into why this is here. If the instance creation gets aborted due to a naming conflict,
        # Then __del__ gets called, but that leads to an attribute error, hence the try block.
        try:
            self.instances.remove(self._name)

        except AttributeError:
            pass

While this isn't great practice, it answers your question.

Here's a demo of what it lets you do:

foo = APIClass('foo')
bar = APIClass('bar')
baz = APIClass('baz')

print(APIClass.instances)  # All 3 names tracked

foo.name = 'changed_foo'

print(APIClass.instances)  # Note the updated foo.name

del foo

print(APIClass.instances)  # foo.name was removed from the set

bar_2 = APIClass('bar')  # Should error since "bar" is in use

output:

{'baz', 'bar', 'foo'}
{'changed_foo', 'baz', 'bar'}
{'baz', 'bar'}
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
# ... < long stack trace here> ...
<ValueError: Name already in use: bar

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM