0

I need a class that remembers its constant token (uuid). When I use the property decorator as described here, the property will prevent the uuid function from changing, but not the value:

from uuid import uuid4

class Tokenizer:
    @property
    def token(self):
        return uuid4().hex

t = Tokenizer()

print(t.token)
print(t.token)

This prints diffrent tokens, so how can I achieve the constant token so the output will be the same, without passing token to the class as argument?

Edit: t.__token can by changed but does not affect t.token. Do you know why?

from uuid import uuid4

class Tokenizer:
    def __init__(self):
        self.__token = uuid4().hex
    
    @property
    def token(self):
        return self.__token

t = Tokenizer()

print(t.token)
print(t.token)
Jurakin
  • 832
  • 1
  • 5
  • 19
  • Do you want a single UUID for the *class*, or a separate UUID for each *instance* of the class? – chepner May 01 '23 at 14:33
  • I want separate uuid for each instance of the class, so the `t1` and `t2` are diffrent. `t1 = Tokenizer().token; t2 = Tokenizer().token`. – Jurakin May 01 '23 at 16:20

1 Answers1

1

What is basically done here is I am creating a token if it does not exist and if the instance of class has already set the token, then we will be returning the existing token.

The __token variable in the updated code is not modifiable because it is a class-level variable, and it is defined with double underscores as __token. This makes it a private variable that cannot be accessed or modified directly from outside the class.

from uuid import uuid4

class Tokenizer:
    def __init__(self):
        self.__token = uuid4().hex
    
    @property
    def token(self):
        return self.__token

t = Tokenizer()

print(t.token)
print(t.token)
Jurakin
  • 832
  • 1
  • 5
  • 19
Sanjay Shahi
  • 124
  • 1
  • 6
  • I appreciate your answer, but I would prefer to use a method in which the token cannot be overwritten (`__token` can be overwritten) – Jurakin May 01 '23 at 13:42
  • I thought `class Tokenizer: token = property(lambda self: uuid4().hex)` will work but doesn't. – Jurakin May 01 '23 at 13:47
  • See the updated answer. Now we have remove the set_token method which could have been used to update the token. Since __token is defined with __ it cannot be modified outside class. – Sanjay Shahi May 01 '23 at 14:26
  • 1
    @SanjayShahi It *can*, but anyone doing so proceeds at their own risk. – chepner May 01 '23 at 14:31
  • Your previous approach was better, as now *every* token shares the same UUID. – chepner May 01 '23 at 14:32
  • Thanks for your answer. `t.__token` can by changed but does not affect `t.token`. Do you know why? – Jurakin May 01 '23 at 16:38
  • @Jurakin `Tokenizer.__token` and `t.__token` are two entirely separate attributes (the former a class attribute, the latter an instance attribute). You can't really stop anyone from changing either of them, but the name strongly suggests that one *shouldn't*. `Tokenizer.token`, on the other hand, is a *property*, so assigning to `t.token` triggers the descriptor protocol, and `Tokenizer.token` is defined to raise an error if anyone attempts to do so. – chepner May 01 '23 at 18:12
  • @chepner My apologies, I posted an edit to Sanja's answer (I simplified the answer), but it was not approved. See my question when I included the change. You are correct that `tokenizer.__token` is not the same as `t.__token`, but I was referring to my edit. – Jurakin May 01 '23 at 18:18
  • @Jurakin OK, yes, that's what I would do. Using a property as the public interface to a private attribute is a common pattern. – chepner May 01 '23 at 18:44