Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #97199 > unrolled thread
| Started by | plewto@gmail.com |
|---|---|
| First post | 2015-09-29 02:27 -0700 |
| Last post | 2015-09-29 13:11 +0200 |
| Articles | 11 — 8 participants |
Back to article view | Back to comp.lang.python
Question re class variable plewto@gmail.com - 2015-09-29 02:27 -0700
Re: Question re class variable alister <alister.nospam.ware@ntlworld.com> - 2015-09-29 10:00 +0000
Re: Question re class variable John Gordon <gordon@panix.com> - 2015-09-29 14:44 +0000
Re: Question re class variable Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2015-09-29 20:41 -0400
Re: Question re class variable Antoon Pardon <antoon.pardon@rece.vub.ac.be> - 2015-09-29 12:40 +0200
Re: Question re class variable Anssi Saari <as@sci.fi> - 2015-09-29 14:17 +0300
Re: Question re class variable Antoon Pardon <antoon.pardon@rece.vub.ac.be> - 2015-09-29 14:02 +0200
Re: Question re class variable Steven D'Aprano <steve@pearwood.info> - 2015-09-29 22:06 +1000
Re: Question re class variable Dennis Lee Bieber <wlfraed@ix.netcom.com> - 2015-09-29 08:21 -0400
Re: Question re class variable jmp <jeanmichel@sequans.com> - 2015-09-29 13:02 +0200
Re: Question re class variable jmp <jeanmichel@sequans.com> - 2015-09-29 13:11 +0200
| From | plewto@gmail.com |
|---|---|
| Date | 2015-09-29 02:27 -0700 |
| Subject | Question re class variable |
| Message-ID | <3948d9cd-24b1-4a3b-8ed0-46bb60a8d738@googlegroups.com> |
I have a perplexing problem with Python 3 class variables. I wish to generate an unique ID each time an instance of GameClass is created. There are two versions of the __gen_id method with test run results for each listed below the code.
Originally I used the version which is now commented out. When a new instance was created it created an ID by appending the value of __instance_counter to the class name, it then checked the contents of of __instatance_registrty to see if this ID was already in use. If so it incremented the counter until it found an unused ID. This version works exactly as I expected.
Later I decided to get rid of __instance_registry and rely solely on the restricted access to __instance_counter and the fact that it is monotonically increasing to generate IDs. I wrote the second, simpler version of __gen_id to that end, but it doesn't work! No doubt I'm overlooking something very simple here but I'm not seeing it.
Any help appreciated.
class GameObject:
# __instance_registry = {"":None}
__instance_counter = 0
def __init__(self, name):
self.__name = str(name)
self.__id = self.__gen_id()
# def __gen_id(self):
# ty = self.__class__.__name__
# id = ''
# while id in self.__instance_registry:
# id = '%s_%d' % (ty, self.__instance_counter)
# self.__instance_counter += 1
# self.__instance_registry[id] = self
# return id
def __gen_id(self):
ty = self.__class__.__name__
id = '%s_%d' % (ty, self.__instance_counter)
self.__instance_counter += 1
return id
def __str__(self):
return "name = '%s' id = '%s'" % (self.__name, self.__id)
go1 = GameObject("GO1")
go2 = GameObject("GO2")
go3 = GameObject("GO3")
print(go1)
print(go2)
print(go3)
# Results with original __gen_id method
# name = 'GO1' id = 'GameObject_0'
# name = 'GO2' id = 'GameObject_1'
# name = 'GO3' id = 'GameObject_2'
# Results with new simpler __gen_id method, __instance_counter not being incremented
# name = 'GO1' id = 'GameObject_0'
# name = 'GO2' id = 'GameObject_0'
# name = 'GO3' id = 'GameObject_0'
[toc] | [next] | [standalone]
| From | alister <alister.nospam.ware@ntlworld.com> |
|---|---|
| Date | 2015-09-29 10:00 +0000 |
| Message-ID | <mudnfg$cqo$1@speranza.aioe.org> |
| In reply to | #97199 |
On Tue, 29 Sep 2015 02:27:23 -0700, plewto wrote:
> I have a perplexing problem with Python 3 class variables. I wish to
> generate an unique ID each time an instance of GameClass is created.
> There are two versions of the __gen_id method with test run results for
> each listed below the code.
>
> Originally I used the version which is now commented out. When a new
> instance was created it created an ID by appending the value of
> __instance_counter to the class name, it then checked the contents of of
> __instatance_registrty to see if this ID was already in use. If so it
> incremented the counter until it found an unused ID. This version works
> exactly as I expected.
>
> Later I decided to get rid of __instance_registry and rely solely on the
> restricted access to __instance_counter and the fact that it is
> monotonically increasing to generate IDs. I wrote the second, simpler
> version of __gen_id to that end, but it doesn't work! No doubt I'm
> overlooking something very simple here but I'm not seeing it.
>
> Any help appreciated.
>
>
> class GameObject:
>
> # __instance_registry = {"":None}
> __instance_counter = 0
>
> def __init__(self, name):
> self.__name = str(name)
> self.__id = self.__gen_id()
>
> # def __gen_id(self):
> # ty = self.__class__.__name__
> # id = ''
> # while id in self.__instance_registry:
> # id = '%s_%d' % (ty, self.__instance_counter)
> # self.__instance_counter += 1 #
> self.__instance_registry[id] = self # return id
>
> def __gen_id(self):
> ty = self.__class__.__name__
> id = '%s_%d' % (ty, self.__instance_counter)
> self.__instance_counter += 1 return id
>
> def __str__(self):
> return "name = '%s' id = '%s'" % (self.__name, self.__id)
>
>
> go1 = GameObject("GO1")
> go2 = GameObject("GO2")
> go3 = GameObject("GO3")
> print(go1)
> print(go2)
> print(go3)
>
>
> # Results with original __gen_id method # name = 'GO1' id =
> 'GameObject_0'
> # name = 'GO2' id = 'GameObject_1'
> # name = 'GO3' id = 'GameObject_2'
>
>
> # Results with new simpler __gen_id method, __instance_counter not being
> incremented # name = 'GO1' id = 'GameObject_0'
> # name = 'GO2' id = 'GameObject_0'
> # name = 'GO3' id = 'GameObject_0'
why reinvent the wheel?
why not simply use pythons builtin id function?
each new instance of an object is automatically assigned a unique ID
--
I'm a soldier, not a diplomat. I can only tell the truth.
-- Kirk, "Errand of Mercy", stardate 3198.9
[toc] | [prev] | [next] | [standalone]
| From | John Gordon <gordon@panix.com> |
|---|---|
| Date | 2015-09-29 14:44 +0000 |
| Message-ID | <mue84o$l3l$1@reader1.panix.com> |
| In reply to | #97200 |
In <mudnfg$cqo$1@speranza.aioe.org> alister <alister.nospam.ware@ntlworld.com> writes:
> why not simply use pythons builtin id function?
> each new instance of an object is automatically assigned a unique ID
It's only guaranteed to be unique for objects that exist at the same time.
If an object is created and destroyed and then another new object is
created, the ID of those two objects can be the same.
--
John Gordon A is for Amy, who fell down the stairs
gordon@panix.com B is for Basil, assaulted by bears
-- Edward Gorey, "The Gashlycrumb Tinies"
[toc] | [prev] | [next] | [standalone]
| From | Dennis Lee Bieber <wlfraed@ix.netcom.com> |
|---|---|
| Date | 2015-09-29 20:41 -0400 |
| Message-ID | <mailman.250.1443573691.28679.python-list@python.org> |
| In reply to | #97211 |
On Tue, 29 Sep 2015 14:44:40 +0000 (UTC), John Gordon <gordon@panix.com>
declaimed the following:
>In <mudnfg$cqo$1@speranza.aioe.org> alister <alister.nospam.ware@ntlworld.com> writes:
>
>> why not simply use pythons builtin id function?
>> each new instance of an object is automatically assigned a unique ID
>
>It's only guaranteed to be unique for objects that exist at the same time.
>
>If an object is created and destroyed and then another new object is
>created, the ID of those two objects can be the same.
Since the code binds the object to the resultant entry
(registry[id]=self) -- it isn't going to go away without deliberately
rebinding the entry.
--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com HTTP://wlfraed.home.netcom.com/
[toc] | [prev] | [next] | [standalone]
| From | Antoon Pardon <antoon.pardon@rece.vub.ac.be> |
|---|---|
| Date | 2015-09-29 12:40 +0200 |
| Message-ID | <mailman.232.1443523293.28679.python-list@python.org> |
| In reply to | #97199 |
Op 29-09-15 om 11:27 schreef plewto@gmail.com:
> I have a perplexing problem with Python 3 class variables. I wish to generate an unique ID each time an instance of GameClass is created. There are two versions of the __gen_id method with test run results for each listed below the code.
The problem is that in python you can't change a class variable through an instance. The moment you
try, you create an instance attribute.
> class GameObject:
>
> # __instance_registry = {"":None}
> __instance_counter = 0
>
> def __init__(self, name):
> self.__name = str(name)
> self.__id = self.__gen_id()
>
> def __gen_id(self):
> ty = self.__class__.__name__
> id = '%s_%d' % (ty, self.__instance_counter)
> self.__instance_counter += 1
This last line doesn't work as expected. What happens is equivallent to
the following.
self.__instance_counter = self.__instance_counter + 1
But the self.__instance_counter are two different things here. On the right hand
python finds that self has no __instance_counter attribute so it will fetch the
value from the class.
However on the left hand, python will create an attribute for self and assign the
value to it. Python will not rebind the class variable.
--
Antoon Pardon
[toc] | [prev] | [next] | [standalone]
| From | Anssi Saari <as@sci.fi> |
|---|---|
| Date | 2015-09-29 14:17 +0300 |
| Message-ID | <vg3k2r9wk34.fsf@coffee.modeemi.fi> |
| In reply to | #97201 |
Antoon Pardon <antoon.pardon@rece.vub.ac.be> writes:
> Op 29-09-15 om 11:27 schreef plewto@gmail.com:
>> I have a perplexing problem with Python 3 class variables. I wish to
>> generate an unique ID each time an instance of GameClass is
>> created. There are two versions of the __gen_id method with test run
>> results for each listed below the code.
>
> The problem is that in python you can't change a class variable through an instance. The moment you
> try, you create an instance attribute.
That much is clear but why does his other version of __gen_id() work
(after a fashion)? It doesn't increment the class variable but the
instances get an incremental id.
The function was like this:
def __gen_id(self):
ty = self.__class__.__name__
id = ''
while id in self.__instance_registry:
id = '%s_%d' % (ty, self.__instance_counter)
self.__instance_counter += 1
self.__instance_registry[id] = self
return id
Also, is there any problem with incrementing
GameObject.__instance_counter from __gen_id()? I guess not?
[toc] | [prev] | [next] | [standalone]
| From | Antoon Pardon <antoon.pardon@rece.vub.ac.be> |
|---|---|
| Date | 2015-09-29 14:02 +0200 |
| Message-ID | <mailman.236.1443528161.28679.python-list@python.org> |
| In reply to | #97204 |
Op 29-09-15 om 13:17 schreef Anssi Saari: > Antoon Pardon <antoon.pardon@rece.vub.ac.be> writes: > >> Op 29-09-15 om 11:27 schreef plewto@gmail.com: >>> I have a perplexing problem with Python 3 class variables. I wish to >>> generate an unique ID each time an instance of GameClass is >>> created. There are two versions of the __gen_id method with test run >>> results for each listed below the code. >> The problem is that in python you can't change a class variable through an instance. The moment you >> try, you create an instance attribute. > That much is clear but why does his other version of __gen_id() work > (after a fashion)? It doesn't increment the class variable but the > instances get an incremental id. > > The function was like this: > > def __gen_id(self): > ty = self.__class__.__name__ > id = '' > while id in self.__instance_registry: > id = '%s_%d' % (ty, self.__instance_counter) > self.__instance_counter += 1 > self.__instance_registry[id] = self > return id Because you check against the class variable __instance_registry. That variable isn't rebound, it is mutated, so it remains a class variable and can thus be used to check which id's are already in use. So you increment your counter until the corresponding id is not in the __instance_registry. -- Antoon Pardon.
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2015-09-29 22:06 +1000 |
| Message-ID | <560a7eb7$0$1607$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #97204 |
On Tue, 29 Sep 2015 09:17 pm, Anssi Saari wrote: [...] >> The problem is that in python you can't change a class variable through >> an instance. The moment you try, you create an instance attribute. > > That much is clear but why does his other version of __gen_id() work > (after a fashion)? It doesn't increment the class variable but the > instances get an incremental id. > > The function was like this: > > def __gen_id(self): > ty = self.__class__.__name__ > id = '' > while id in self.__instance_registry: > id = '%s_%d' % (ty, self.__instance_counter) > self.__instance_counter += 1 > self.__instance_registry[id] = self > return id This works because it doesn't assign to self.__instance_registry itself, it assigns to an item within the existing self.__instance_registry. So the registry object (a dict?) gets modified in place, not re-bound or shadowed by an instance attribute of the same name. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Dennis Lee Bieber <wlfraed@ix.netcom.com> |
|---|---|
| Date | 2015-09-29 08:21 -0400 |
| Message-ID | <mailman.237.1443529284.28679.python-list@python.org> |
| In reply to | #97204 |
On Tue, 29 Sep 2015 14:17:35 +0300, Anssi Saari <as@sci.fi> declaimed the
following:
>That much is clear but why does his other version of __gen_id() work
>(after a fashion)? It doesn't increment the class variable but the
>instances get an incremental id.
>
>The function was like this:
>
> def __gen_id(self):
> ty = self.__class__.__name__
> id = ''
> while id in self.__instance_registry:
> id = '%s_%d' % (ty, self.__instance_counter)
> self.__instance_counter += 1
> self.__instance_registry[id] = self
> return id
>
They get an incremental ID because he constantly searches the
class-wide "instance registry" for the duplicate values -- which are always
being generated since the counter starts at 0 (+1) for each instance...
Would get quite slow if enough instances were to be created... While the
registry was initialized with
# __instance_registry = {"":None}
Preloaded with a dummy value just so the first pass of the "while" loop
wouldn't drop out.
Whereas the counter is a rebinding into a local, the registry is a
mutation of the classwide value, not a rebinding -- so it IS shared among
all.
--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com HTTP://wlfraed.home.netcom.com/
[toc] | [prev] | [next] | [standalone]
| From | jmp <jeanmichel@sequans.com> |
|---|---|
| Date | 2015-09-29 13:02 +0200 |
| Message-ID | <mailman.233.1443524549.28679.python-list@python.org> |
| In reply to | #97199 |
On 09/29/2015 11:27 AM, plewto@gmail.com wrote:
> I have a perplexing problem with Python 3 class variables.
Your problem is that when assigning values to your class attribute, you
are actually creating a instance attribute.
class Foo:
bar = "I'm a class attribute"
def __init__(self):
self.bar = "I'm an instance attribute"
def foo(self):
print self.bar
print Foo.bar
# this is how you set a class attribute from an instance
Foo.bar = "I am still a class attribute"
print Foo.bar
Foo.foo()
I'm an instance attribute
I'm a class attribute
I am still a class attribute
What can be confusing is that assuming you never use the same name for a
class an instance attribute (that would be bad code), you can access
your class attribute from the instance:
class Foo:
bar = "I'm a class attribute"
def foo(self):
# python will look into the class scope if not found in the instance
print self.bar # this is not an assignment so we're fine
Foo.foo()
I'm an class attribute
As side note and unrelated topic, your are using name mangling
(attribute starting with __), are you sure you need it ? You need a
strong motive to use this feature otherwise you're making things
difficult for yourself without any benefit.
Finally here's how I'd code your id, to give some idea on alternative ways:
class GameObject:
@property
def id(self):
return id(self) #use the builtin id function
print GameObject().id
Cheers,
JM
[toc] | [prev] | [next] | [standalone]
| From | jmp <jeanmichel@sequans.com> |
|---|---|
| Date | 2015-09-29 13:11 +0200 |
| Message-ID | <mailman.234.1443525084.28679.python-list@python.org> |
| In reply to | #97199 |
On 09/29/2015 01:02 PM, jmp wrote:
> class GameObject:
>
> @property
> def id(self):
> return id(self) #use the builtin id function
>
> print GameObject().id
>
> Cheers,
>
> JM
I should add that until you don't serialize your object you're fine.
If you need to serialize it, you may want to look at
https://docs.python.org/3/library/uuid.html
import uuid
class GameObject:
def __init__(self):
self._id = None
@property
def id(self):
if self._id is None:
# make a UUID based on the host ID and current time
self._id = uuid.uuid1()
return self._id
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web