Temple of The Roguelike Forums
Development => Programming => Topic started by: Gr3yling on May 17, 2014, 02:51:41 AM
-
That sounds like a fantastic name for a roguelike, incidentally.
So, I'm having a number of problems, and I suspect they are related to my limited understanding of how variables are bound and re-bound. I don't understand why the following code:
count = 0
def increment(x):
global x
-
I'm wondering if there's some missing words in your post here: "I don't understand why the following code:". Does what?
-
"... doesn't work" most probably ;)
-
Okay, I have no idea how this got posted. The forum interface was acting wonky so I decided to give up and post my question later. Sorry. I didn't realize it actually got submitted.
Suffice to say I've been having a lot of trouble with understanding how variables are bound in Python. Before you link me to the python documentation, let me just say that I have definitely looked there extensively (and a lot of other tutorials).
There are a number of things I'm having a hard time getting, but lets start with this one:
x = 5
def test_function():
x = 5
return id(x)
print test_function()
print id(x)
Output: 31292720 and 31292720
WAAAAAT? Aren't id's in CPYTHON memory addresses? So, why do both x's have the same memory address? I thought the whole point of all this crazy global and local variable stuff was that even though a variable might have the same name inside and outside of a function, it was NOT really the same variable unless global was called. And my understanding is that if two variables have identical memory addresses, they meet the strictest quality for being identical (i.e. x(1) IS x(2), not just x(1) == x(2)).
I've got a lot of other questions but this is the one that's bugging me most right now.
I bought "Python in a Nutshell", and it's a bit over my head. "Introduction to Python" (by O'Reily) should be here soon, so maybe I'll do better once I get started on it.
-
There are a number of things I'm having a hard time getting, but lets start with this one:
x = 5
def test_function():
x = 5
return id(x)
print test_function()
print id(x)
Output: 31292720 and 31292720
WAAAAAT? Aren't id's in CPYTHON memory addresses? So, why do both x's have the same memory address? I thought the whole point of all this crazy global and local variable stuff was that even though a variable might have the same name inside and outside of a function, it was NOT really the same variable unless global was called. And my understanding is that if two variables have identical memory addresses, they meet the strictest quality for being identical (i.e. x(1) IS x(2), not just x(1) == x(2)).
I've got a lot of other questions but this is the one that's bugging me most right now.
The id value is the memory address, but looking for patterns is meaningless. You can easily modify your code to prove that both x's are different independent variables.
Look, if you really want to know, lower integer values are constants. You can see this by doing:
i = 5
id(i)
i += 1
id(i)
Note that there will be different id's. When you're dealing with classes and class instances, the id will of course be persistent and reliable. But basing your code on requiring ids to work in some arbitrary way you picture they should work, will only lead to disappointment.
This is actually a considerable memory saving, that the lower integers work this way. I saw the numbers when the patch was proposed.
-
But I still don't understand how the two x's are independent if they but refer to the same memory address, presumably storing the same value. Like I said, I thought that in the most fundamental way, the memory address *was* the identity of a variable.
-
But I still don't understand how the two x's are independent if they but refer to the same memory address, presumably storing the same value. Like I said, I thought that in the most fundamental way, the memory address *was* the identity of a variable.
If there is an optimisation that lower integers of the same value are the same object, then your two independent variables will point to the same object and have the same id which will be the address of that object. Making common objects (like read only strings, or in this case a small set of the most commonly used integers) shared isn't an optimisation which Python alone uses.
TLDR: The id is the memory address of the actual object you are dealing with, not the memory address of the pointer to that object.
-
I thought Python didn't use pointers:
http://stackoverflow.com/questions/3106689/pointers-in-python
This topic starts with the statement: " I know python doesn't have pointers, but..."
So what gives? Your answers are leaving me with more questions than solutions.
Sorry, I really do appreciate you (and the others who replied) taking the time to answer my question. I just wish I understood enough to write the game I want to make. I'm not trying to be difficult, it just seems that python can be very inconsistent sometimes.
-
I thought Python didn't use pointers:
http://stackoverflow.com/questions/3106689/pointers-in-python
This topic starts with the statement: " I know python doesn't have pointers, but..."
So what gives? Your answers are leaving me with more questions than solutions.
Sorry, I really do appreciate you (and the others who replied) taking the time to answer my question. I just wish I understood enough to write the game I want to make. I'm not trying to be difficult, it just seems that python can be very inconsistent sometimes.
Your problem is that I am explaining id() in terms of why it gives the values it does. Python does not have pointers.
The fact is that id() is not something you should really ever use, and getting stuck on understanding it, is like getting stuck on why grass is pointed when you're mowing the lawn. You can forget about the points on the blades of grass and keep mowing, much the same as you can forget id() and learn and write top level Python code. In fact, I suspect that most anyone who used id() would be writing low quality Python code.
-
The fact is that id() is not something you should really ever use, and getting stuck on understanding it, is like getting stuck on why grass is pointed when you're mowing the lawn. You can forget about the points on the blades of grass and keep mowing, much the same as you can forget id() and learn and write top level Python code. In fact, I suspect that most anyone who used id() would be writing low quality Python code.
Dood, I write the *LOWEST* quality python code right now. I have been trained most of my life for something vastly different than understanding computer science, and the reason that I'm posting here is so that I want to write just barely less low quality code than that which you are referring to.
Look, I know it seems weird, but the best way I seem to understand things is in a bottom-up sort of way, where there slightly less complicated concepts build on the most complicated concepts.
tl:dr (even though I do read all of what *you* post when you say tl:dr) I'm trying to learn about computer science coming from a completely different dimension than most of those who study it. Please be patient with me.
-
As far as I know internally everything in python is refcounted pointer. Even integers. Even None!
x=5
here compiler creates constant 5 during compile time, and simply assigns pointer to this constant to x, when executing this line.
and increment ref count.
id converts this internal pointer to integer. so all 5s in your program will have the same id.
array of equal integers is actually array of pointers pointing to one and the same piece of memory.
-
Thanks for taking the time to answer my question, Xecutor. I do believe that you know what you are talking about (and I actually suspected you would be someone who could help me) but it is confusing to hear some sources say that python does not use pointers, and then in this topic multiple people have said it does. What is the cause of this discrepancy?
And just to be clear, the code I posted is not something I would use in my roguelike, I'm just trying to understand local/global variables so that I can get past where I am stuck right now.
-
Thanks for taking the time to answer my question, Xecutor. I do believe that you know what you are talking about (and I actually suspected you would be someone who could help me) but it is confusing to hear some sources say that python does not use pointers, and then in this topic multiple people have said it does. What is the cause of this discrepancy?
Probably you are confusing talks about internals of python with talks about the language itself.
Statement 'python does not use pointers' probably means something like 'programming language Python does not have pointer type as part of the language'.
It's pretty much obvious, that internals of the language is full of pointers.
And just to be clear, the code I posted is not something I would use in my roguelike, I'm just trying to understand local/global variables so that I can get past where I am stuck right now.
It's pretty simple.
If you assign something to a variable in a body of a function, this variable is considered local, unless you explicitly declare it as global.
But you can read global variables in a function without declaring them as globals.
-
Because python understands that a five is a five is a five. They're immutable so it's okay for the Python runtime to say they're all the same. So if you create a bunch of fives, the runtime reuses the same one instead of creating new instances. It's just an optimization. If you create a bunch of compound objects (like a Player, Tile, or Point), then each will have it's own space in memory even if all the attributes are the same since those objects have mutable state.
-
Ah, so it's a mutable/immutable thing. Okay. That makes sense, because tuples seem to behave the same way, based on my limited testing.
Lets walk through this just to makes sure I understand:
The first variable x gets bound to five. This means 5 is used to generate a hash value (which is also 5, it seems based on testing), which python uses to decide what memory address to store the value '5' at.
Second variable x gets bound to five. Now, I though that with a pointer, a new hash value was generated for a new memory address, and that address just stored the location of the first memory address and told the computer to look there next.
But is the following happening instead for the second x?: python generates an identical hash for the second x, linking both x's back to the same memory address containing the 5 value.
See the distinction I'm trying to understand? With what I understand a pointer to be (and I may be totally wrong) is one address that just contains instructions which 'point' the program to another different address, but with what seems like it is happening in python, there is only one address that both variables refer to.
And you guys are saying that the process is different with mutables/immutables? Which, if either, of the scenarios I described previously happens with each of those?
I know theses seem like odd questions, but I think about things in an odd way, and this really does help me.
-
Ah, so it's a mutable/immutable thing. Okay. That makes sense, because tuples seem to behave the same way, based on my limited testing.
Lets walk through this just to makes sure I understand:
The first variable x gets bound to five. This means 5 is used to generate a hash value (which is also 5, it seems based on testing), which python uses to decide what memory address to store the value '5' at.
Second variable x gets bound to five. Now, I though that with a pointer, a new hash value was generated for a new memory address, and that address just stored the location of the first memory address and told the computer to look there next.
But is the following happening instead for the second x?: python generates an identical hash for the second x, linking both x's back to the same memory address containing the 5 value.
See the distinction I'm trying to understand? With what I understand a pointer to be (and I may be totally wrong) is one address that just contains instructions which 'point' the program to another different address, but with what seems like it is happening in python, there is only one address that both variables refer to.
And you guys are saying that the process is different with mutables/immutables? Which, if either, of the scenarios I described previously happens with each of those?
I know theses seem like odd questions, but I think about things in an odd way, and this really does help me.
It is not a mutable/immutable thing, you can find reasoning in my previous answers that make it clear that this cannot possibly be the case were you to read and understand it. I have no idea what you are talking about with respect to hashes and memory addresses - this is complicated nonsense you've constructed somehow. Many programming languages do not feature pointers, but are implemented using pointers.
If you really wanted to understand how the variable scoping worked, you would google it and find lots of explanations and answers. And you'd experiment in the interpreter and reconcile the facts. And like other experienced programmers, you'd pass this bit in several minutes. But instead you post nonsensical and often pointless questions, ignore some facts provided in various answers and leap on offhand mentions provided in various answers.
It's one thing to have a different learning style, and another to seek procrastination by whatever it is you are doing.
-
chooseusername,
I really appreciate you taking the time to make your most recent post and all the other ones in this topic. I realize that you have been much more patient than most people would have been with the questions I have asked.
That said, please do not post in my topic again. I realize I have no authority to compel you not to do so, but I would greatly appreciate it if you did not. I am sorry if I offended you with something I have said previously, but I do not feel that you are making a good faith attempt to be helpful anymore.
Xecutor, if you, Trystan, Zireael, and Aukustus all feel that this topic is a waste of time as chooseusername does, I will be happy to close it. Otherwise, I look forward to your continued input, as I think you are knowledgeable enough to help me with what I am trying to understand.
*Edited because I can't spell.
-
It's not a waste of time if it helps you.
But is it helping you? It's very rarely useful to know the low level details of a language like this especially since id is a function you almost certainly won't use.
-
I have nothing against this thread. Feel free to continue posting your problems and we shall help you if we can.
-
Second variable x gets bound to five. Now, I though that with a pointer, a new hash value was generated for a new memory address, and that address just stored the location of the first memory address and told the computer to look there next.
<...>
With what I understand a pointer to be (and I may be totally wrong) is one address that just contains instructions which 'point' the program to another different address, but with what seems like it is happening in python, there is only one address that both variables refer to.
The numbers you observe (hashes and hypothetical memory address) are actually the result of an optimization and not the optimization mechanism itself. When you ask for the second variable's properties, interpreter silently follows all those internal pointers and gives you the final result. Therefore for external observer it looks like two variables are the one and the same.
Also, do not confuse Python variables and real memory blocks. In lower-level languages like C they are the same thing. In higher-level languages variable is more like a wrapper around some object and may have very complex relation to actual memory. There is no reason for some variable to point to another variable's data indirectly. Because variable and it's data are not the same here, both variables may just directly point to same data.
-
Also, do not confuse Python variables and real memory blocks. In lower-level languages like C they are the same thing. In higher-level languages variable is more like a wrapper around some object and may have very complex relation to actual memory. There is no reason for some variable to point to another variable's data indirectly. Because variable and it's data are not the same here, both variables may just directly point to same data.
Darn. I guess I am in over my head, then. Trystan, you're right, I thought this was going to help my understand why I keep having problems with my variables, but I guess it won't after all.
Like I mentioned earlier, my python book should be here pretty soon. I guess I just need to study more to understand where I'm going wrong.
-
To answer your question: When python sees (i.e. parses) a numeric, string, or other immutable literal (e.g. 5), it either allocates memory for the corresponding object or recognizes it as another copy of a literal already encountered, in which case it uses the object already allocated. Variables assigned to the same numeric literal (5) therefore have the same "id."
I would also agree with chooseusername. You should ask questions like this on stackexchange or similar sites, if you must (where you will encounter appropriate criticism for them, I might add), or just google. Questions about the mechanics of id or python hashes or whatever else are both uninteresting and better addressed by people well versed in and interested in answering questions about such matters, rather than people who don't know but are eager to indulge your idle curiosity.
-
I would also agree with chooseusername. You should ask questions like this on stackexchange or similar sites, if you must (where you will encounter appropriate criticism for them, I might add), or just google. Questions about the mechanics of id or python hashes or whatever else are both uninteresting and better addressed by people well versed in and interested in answering questions about such matters, rather than people who don't know but are eager to indulge your idle curiosity.
As best as I can determine from my examination of the programming forum, there have been no posts in topics other than this one since May the first. No precious resources that should have been allocated to other concerns have been squandered. No one is wasting your valuable time and alleged expertise. This post is not off topic. It is about the difficulties I have had programming a roguelike and it was posted in the programming forum. If you feel that it violates any kind of rules, by all means, report it to the moderators.
I find it somewhat surprising that you chose to belittle me by saying that this topic satisfied my "idle" curiosity. One wonders, do you find your own posts about video game development in an extremely niche genre to be somehow more productive to society? Do you arrogantly find your own contributions to this forum to be somehow vital to its functioning?
I also find it interesting that you state that others who have made contributions to this topic, like Xecutor, Aukustus, and Zireael "don't know" the answer to my question. And I suppose you think you know far better than them? I personally fail to see how you have distinguished yourself as being more knowledgeable to them.
Finally, I posted at least in part because of the desire to interact with other individuals on these forums who I like and respect. We could have had an enjoyable discussion, if nothing else, had you and chooseusername not come along.
I wish to do absolutely nothing on this forum other than enjoy exchanging ideas and support other people who are trying to develop a game just as I am doing. I don't understand why you don't feel the same way.
-
I don't know how else to account for a question about the "id" method that anyone who really cared could answer with a few minutes of googling (or, alternatively, by actually listening to the people who answered the question in this thread) than "idle curiosity." I answered your question marginally more completely than others in the thread, who you have also ignored as far as I can tell, except to the extent that they have offered validation of whatever it is you're trying to accomplish by this question.
As to why I don't feel exactly the same way as you: I hope to learn something, not find emotional support. It strikes me as kind of self-indulgent to start a thread nominally about a point of trivia in python programming primarily for the opportunity to chit chat. Anyway, from my perspective, your cri de coeur here only erodes my confidence that my goals of actually learning something will be achieved often enough to justify reading any given thread. I suspect there are others who might put the point more delicately, but feel roughly the same way.
-
Gr3yling ignore the blather. You can continue to post programming questions here. It's the reason we have a programming section.
If people do not know the answer you'll have to go somewhere else. No biggie.
A lot of pissy moods around these days. The internet is dark and full of terrors.
-
understand why I keep having problems with my variables, but I guess it won't after all.
Is there a specific problem you are running into or just unsure about python internals and the id function?
-
Gr3yling ignore the blather. You can continue to post programming questions here. It's the reason we have a programming section.
If people do not know the answer you'll have to go somewhere else. No biggie.
A lot of pissy moods around these days. The internet is dark and full of terrors.
Pretty lame. His question has been answered at least twice over.
If questions like this are the reason there's a programming section, I'm not surprised it goes weeks without substantive activity.
-
Yes. There is a specific problem. It's kind of hard for me to know exactly what code to post (I'm so lost It's really hard to be sure). Also, my code is really ugly. The code is based on the complete roguelike tutorial code, but I've tried to come up with my own way to do as many things as I can, which is probably why it doesn't work now. Anyway, maybe this is a decent start.
the monster AI module is supposed to be called after the player has moved, and this is my attempt to do that:
def monster_act():
if player_action != False:
if game_state == 'playing':
for object in objects:
if object.ai == Hostile_AI:
if object.alive:
object.Hostile_AI.take_turn()
Problem is, I get an exception saying that my object class (of which monsters are a member), doesn't have an attribute "Hostile AI"
Well, here is my object class template:
class Object:
def __init__(self, x, y, char, name, color, ai = None, item = None, status = None, equipment = None, inventory = None, alive = True, blocks = False):
self.x = x
self.y = y
self.char = char
self.name = name
self.color = color
self.ai = ai
if self.ai:
self.ai.owner = self
self.item = item
if self.item:
self.item.owner = self
self.status = status
if self.status:
self.status.owner = self
self.equipment = equipment
if self.equipment:
self.equipment.owner = self
self.inventory = inventory
self.alive = alive
self.blocks = blocks
There's more code for object, but this is already a ton, so I won't post it unless you tell me to.
And here's a specific instance of object:
monster = Object(x, y, 'R', 'Razor head ' + str(razorhead_no), libtcod.black, ai = Hostile_AI,
status = razorhead_status, alive = True, blocks = True)
razorhead_no = razorhead_no + 1
Hostile ai is there! I don't see what the problem is.
The whole idea behind my question was that I thought if I knew how python handled attributes/variables, that I would be able to figure out myself what went wrong.
*Edited for clarity
-
You are trying to use attribute named Hostile_AI, while the correct attribute is ai (I'm assuming that Hostile_AI has method take_turn()).
Key is in Object's __init__: self.ai = ai. You're assigning to Hostile_AI to ai attribute.
-
Wow, you were right. This is turning into an enjoyable discussion. So what does the interpreter say after you fix that line?
(i.e. when you change object.Hostile_AI.take_turn() to object.ai.take_turn() ?)
-
Wow, you were right. This is turning into an enjoyable discussion. So what does the interpreter say after you fix that line?
(i.e. when you change object.Hostile_AI.take_turn() to object.ai.take_turn() ?)
I found the problem. There were a number of errors, but the main one was that Hostile_AI was the name of the class itself, not of an instance of the class. I had forgotten to instantiate it at all.
There are a number of bugs still left, but I think I can probably fix them. I actually had a successful program and was at the step of implementing an inventory system when I decided that the roguelike tutorial's way of making almost all in game objects (the PC, monsters, items, etc) members of the same multifunctional class was better than my way of having a separate item and actor class. And then when I tried to implement that, there were a bunch of errors that popped up from the changes I made.
Anyway, thanks for the help turoturo.
-
I decided that the roguelike tutorial's way of making almost all in game objects (the PC, monsters, items, etc) members of the same multifunctional class was better than my way of having a separate item and actor class.
A good idea might be to implement various kinds of game objects as subclasses. Eg.:
class Being:
generic_tile=None # properties that go here, are shared by all instances of the class
def __init__(self):
self.tile=self.generic_tile # now you can change an instance's self.tile without affecting the class as such
class Critter(Being):
generic_maxhealth=0
def __init__(self):
Being.__init__(self)
self.maxhealth=self.generic_maxhealth
class Chicken(Critter):
generic_tile="c" ; generic_maxhealth=1
This way, you can implement generic functions and properties in the Being class, and still get to code special make-up for classes that need it, like having different destroy() functions for items and critters.
On a more general note, your book will surely get you going once it arrives. Worrying about what's going on under the hood will yield a game much slower than going at it with the mentality of a chaos mage: if it works, just do it. The python shell is a good tool to check out what stuff does that you're unsure of. Consider this:
x=5
x is 5 # returns True
y=x # the same as calling y=5, considering that (x is 5)==True
x+=1
x # 6, obviously
y # 5, even though we changed x
As always,
Minotauros