How can I create an indefinite iterations of objects in python? - python

I'm new to python and am trying to create a program to test some methods of object creation. Currently, I'm writing a program that involves creating objects, giving them a unique numeric variable, and assigning them to a list for future referencing. Here's what I wrote to create the variable names:
def getRectangleName():
rectName = list("Rectangle")
SPAWNEDOBJECTLIST.append(len(SPAWNEDOBJECTLIST))
rectName.append(str(len(SPAWNEDOBJECTLIST)))
return rectName
and then that's passed onto something to turn that string into a variable name. I tried eval(), learned this was Bad for some reason and it didn't work anyway, and tried some workarounds to no avail.
I figure there's plenty of games that have an indefinite number of characters on the screen. Is there an established way of making iterations of objects like this?
The objects themselves have an X and Y so that they act as reference points for the display of rectangles on screen(the idea in the future is to have each one move around on their own, so simply making lists of X and Y to draw rectangles isn't useful).
Edit: The problem is that I don't know how to give each object its own variable to put it on a list for future referencing.
Edit2: I don't think I'm asking the right question, actually, or using the right terminology. I need to be able to have an indefinite number of objects created on the fly after the program is already running, and be able to reference them individually.

The problem is that I don't know how to give each object its own variable to put it on a list for future referencing.
Whenever you think you need variables you didn't type into your program, you're doing something wrong. You don't need to assign something to a variable to put it on a list:
x = [1, 2, 3] # Note how I don't assign 1, 2, or 3 to variables.
x.append(4) # 4 doesn't get a variable either.
x.append(make_a_rectangle()) # We create a rectangle and stick it on the list.
do_stuff_with(x[4]) # We pass the rectangle to a function.
x = [] # New list.
for i in xrange(n):
x.append(make_a_rectangle()) # This happens n times.
# At this point, we have n rectangles, none of them associated with their own
# variable, none of them with a name.
If you think you need names for things (and quite often, you don't really need the names), you can use a dict:
x = {}
x['foo'] = make_a_rectangle()
do_stuff_with(x['foo'])

It's not a great idea to combine the function of managing the rectangles -- accessing, adding, or deleting them -- with the idea of being rectangles. You never know when you might need to maintain multiple lists, or change from unordered lists to organized ones.
Until you really need more, keep the management functions simple: use built-in lists or dictionaries. Use lists if you just care about ordering, or only need to know you have a bunch of stuff:
class Rectangle (object):
def __init__(self, top, bottom, left, right):
self.Top = top
self.Left = left
self.Right = right
self.Bottom = bottom
list_of_rects = [Rectangle(10,0,0,10), Rectangle(20, 10, 10 ,20)]
# how many rects?
len(list_of_rects)
# result: 2
# where is this particular rect?
fred = Rectangle(30,20,20, 30)
list_of_rects.insert(fred, 1)
list_of_rects.index(fred)
# result: 1
#remove an item from the list:
list_of_rects.remove(fred)
#search the list:
right_of_5 = [rect for rect in list_of_rects if rect.Left > 5]
If you need to get access to the individual rects for some reason -- 'what's the rectangle of the goal' or something -- you have two choices:
1) the code that needs the rect just keeps a reference to it:
class Goal(object):
def __init__(self, rect):
self.Rect = rect
goalrect = Rectangle (0,0,20,20)
mygoal = Goal(goalrect)
list_of_rects.append(goalrect)
# now goalrect always knows about it's own rect, but the list can keep track of it too...
2) Or, use a dictionary:
named_rects = {}
named_rects['goal'] = Rectangle(0,0,20,20)
You get all the same abilities with a dictionary that you do with a list -- add, delete, and find -- except dictionaries don't preserve order, so you can't manage things like priority:
# add to the dict:
named_rects['new_rect'] = Rectangle(90,90,95,95)
# remove
del named_rects['new_rect']
# find = is there a known key?
if 'new_rect' in named_rects: print new_rect
# search:
right_of_5 = [rect for rect in named_rects.items() if rect.Left > 5]
There are cases where you need fancier things than plain old lists and dicts -- but always try it with the free stuff first :)

If you dynamically want to create variables and add them to class instances, use this
class MainClass:
def __setattr__(self, name, value):
self.__dict__[name] = value
def getRectangleNameGenerator(N = 10):
X = 0
while X <= N:
X += 1
yield "Rectangle" + str(X)
RectangleName = getRectangleNameGenerator()
ClassInstances = {next(RectangleName) : MainClass}
ClassInstances[next(RectangleName)] = MainClass
ClassInstances["Rectangle1"].Temp = 10
print ClassInstances["Rectangle1"].Temp
If the class is going to have only X and Y,
class MainClass:
X, Y = 0, 0
def getRectangleNameGenerator(N = 10):
X = 0
while X <= N:
X += 1
yield "Rectangle" + str(X)
RectangleName = getRectangleNameGenerator()
ClassInstances = {next(RectangleName) : MainClass}
ClassInstances[next(RectangleName)] = MainClass
ClassInstances["Rectangle1"].X = 11
print ClassInstances["Rectangle1"].X

If you really want to refer to your rectangle instances by name, I would suggest to keep a dictionary at class level. Something like this:
#! /usr/bin/python3
from threading import Lock
import random
class Rectangle:
instances = {}
lock = Lock ()
#classmethod
def forName (cls, name):
return cls.instances [name] if name in cls.instances else None
#classmethod
def push (cls, inst):
with cls.lock:
name = None
while not name or name in cls.instances:
name = ''.join (random.choice ('abcdefghij') for i in range (16) )
cls.instances [name] = inst
return name
def __init__ (self):
self.name = Rectangle.push (self)
names = [Rectangle ().name for i in range (5) ]
for name in names:
print (name, Rectangle.forName (name) )

Related

Python - How to print the variable name of an Object

Thanks for reading. Preface, I don't mean how to make a print(objectA) make python output something other than the <__main__.A object at 0x00000273BC36A5C0> via the redefining the __str__ attribute.
I will use the following example to try to explain what I'm doing.
class Point:
'''
Represents a point in 2D space
attributes: x, y
'''
def __init__(self, x=0, y=0):
allowed_types = {int, float}
if type(x) not in allowed_types or type(y) not in allowed_types:
raise TypeError('Coordinates must be numbers.')
else:
self.x = x
self.y = y
def __str__(self):
return f' "the points name" has the points: ({self.x}, {self.y})'
__repr__ = __str__
I would like the "the points name" to be replaced with whatever the variable name assigned to a specific object. So if I instantiated pointA=Point(1,0), I would like to be able to print
pointA has the points: (1,0)
I can't seem to find anything like this online, just people having issues that are solved by redefining __str__. I tried to solve this issue by adding a .name attribute, but that made this very unwieldy (especially since I want to make other object classes that inherit Point()). I'm not entirely sure if this is possible from what I know about variable and object names in python, but after wrestling with it for a couple of days I'd figured I'd reach out for ideas.
Note that an object may be referred to as multiple names.
It is also possible that there is no object name referring to the object.
Below is one approach that achieves your goal. It uses globals(), the dictionary that stores mappings from names to objects inside the global environment. Essentially, the __str__ method searches the object in the global listings (so it can be very slow if there are many objects) and keeps the name if matches.
You could possibly use locals instead to narrow the search scope.
In the example, C is referring to the same object as A. So print(C) tells both A and C are the names.
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
results = []
for name, obj in globals().items():
if obj == self:
results.append(f' "{name}" has the points: ({self.x}, {self.y})')
return "; ".join(results)
A = Point()
B = Point()
print(A)
#"A" has the points: (0, 0)
print(B)
# "B" has the points: (0, 0)
C = A
print(C)
# "A" has the points: (0, 0); "C" has the points: (0, 0)

Python list assignation

I've got this code
class coordenates:
x = 0
y = 0
coor = coordenates()
coor.x=0
coor.y=0
list = []
list.append(coor)
list.append(coor)
Now, the problem is that when I update
list[0].x=100
it is also modifing list[1].x somehow!
print str(list[0].x)
>> 100
print str(list[1].x)
>> 100
which must remain in 0 since I haven't update it. Is append() creating the same object pointing in the same position in memory in positions 0 and 1? why creating 2 different objects solves the problem?
In your current code, x and y are class-level attributes. I suspect that you want them to be instance-level attributes. If so, set them in __init__():
class Coordinates:
def __init__(self):
self.x = 0
self.y = 0
More important, if you append the same coor to the list twice, any mutation of the coor will be reflected in "both" coordinates (because the list is just holding a reference to the same underlying coordinate in both positions of the list). Maybe you want something like this instead, where you create two independent coordinate instances?
list = []
list.append(Coordinates())
list.append(Coordinates())
You can see an illustration of your problem with this code:
c = Coordinates()
cs = []
cs.append(c)
cs.append(c)
for c in cs:
print id(c) # Both elements of the list refer to the same object.

Python static variable in function global name not defined

I have written a function to calculate the heading between two points only if a vehicle reports that it's moving and that the vehicle has moved 20cm between points.
The function uses static variables - or at least it would if it worked - to keep track of previous positions and heading values.
Here is the code:
def withCan(pos):
eastdist = pos[0]-previous_pos[0]
northdist = pos[1]-previous_pos[1]
canflag = pos[2]
if (canflag == 1 or canflag==2):
if (previous_canflag == 1 and canflag == 2):
previous_heading += 180.0
previous_canflag = canflag
elif (previous_canflag == 2 and canflag == 1):
previous_heading += 180.0
previous_canflag = canflag
else:
previous_canflag = canflag
if ( (canflag == 1 or canflag == 2) and math.sqrt(northdist*northdist+eastdist*eastdist) > canstep ):
previous_heading = math.degrees(math.atan2(eastdist, northdist))
previous_pos[0] = pos[0]
previous_pos[1] = pos[1]
return previous_heading
withCan.previous_pos = [0.0,0.0]
withCan.previous_heading = 0.0
withCan.previous_canflag = 0
withCan.canstep = 0.2
positions = backandforth([100,100]) #populates an array of form [x,y,canflag]
for p in positions:
print withCan(p)
I am getting an error that says eastdist = pos[0]-previous_pos[0]
NameError: global name 'previous_pos' is not defined. Please could someone explain the cause of this error?
When you do this:
def foo():
pass
foo.name = 1
You are not creating a global name name. Instead you are adding a property to the foo function! You can access it with:
def foo():
return foo.name
foo.name = 1
But that is quite weird. If you need a global name, just do it:
def foo():
global name
name += 1
return name
name = 1
Remember that if you want to modify the global name from the function, you have to declare it as global. If you fail to do this, you can use it but you cannot assign to it.
Your confusion with static names may come from using classes. But note that in your code withCan is not a class, it is a plain function!
It looks like what you are trying to do is writing a class...
class WithCan():
def __init(self, previous_pos)__:
self.previous_pos=previous_pos
def withCan(self, pos):
# your function as class method
Then you could initialize an instance
withCan=WithCan(previous_pos)
and access it
withCan.previous_pos=...
You can do static variables in Python using function attributes, but you need to use the full name inside the function to access those attributes.
Here's a short demo.
def test(a):
print a, a + test.b
test.b += 1
test.b = 5
test(3)
test(10)
output
3 8
10 16
However, it would be more usual to do this sort of thing using a class, as shown in Tim's answer.
Another way to do statics in Python is to give your function default mutable arguments, but many people are uncomfortable with that. But if you're curious, please see “Least Astonishment” in Python: The Mutable Default Argument.
Let me contribute a perhaps more streamlined way of emulating static variables in functions that could make the OP's example maybe easier to read:
def with_can(pos):
if not hasattr(with_can, "canflag"):
# set up and initialise the static variables
with_can.canflag = 0
with_can.previous_pos = [0.0,0.0]
with_can.previous_heading = 0.0
with_can.canstep = 0.2
# ... use them ...
eastdist = pos[0]-with_can.previous_pos[0]
# ... etc ...
Basically at the first invocation we detect that one of the "static" variables (canflag) is not yet there so we add and initialise all of them. After that they can be used as indicated.
However, as others have pointed out already, it is much better to write a class with data members instead of these "static" function variables.

sorting a certain value python

class otherclass:
def __init__(self,instance,town):
list=[]
for i in line.split(','):
list.append(i)
self.firstname = str(list[0])
self.height = int(list[1])
def__str__(self):
return '%s %d' %(self.firstname,self.height)
class xray(list):
def __init__(self, file, town):
self.file=open(file)
line=self.file.readlines()
line1= line[10:]
for g in line:
self.append(otherclass(g,town))
def sort1(self):
#sort function here
So basically there are three classes one xray, otherclass, and town. Basiclly otherclass is creating data attributes for every object then xray is suppose to read the file and create an object for each item (each line) and append it to the self list. I then have to create some functions to sort the data. For example I have to sort everyone by height. This is where I am stuck since how do I call it to sort based on height? so basically when I say x=xray(file,town) and then x.sort1() it prints everyone sorted by height
Seems like you're going about this wrong. Classes are for objects, not to group code together. Modules are to group code together. This is different than how some other languages (e.g. Java) do things.
Sorting by an attribute, however, isn't hard. Try this:
class Dummy(object):
def __init__(self,name,height):
self.name = name
self.height = height
Adam = Dummy("Adam",72)
Steve = Dummy("Steve",71)
user3521527 = Dummy("user3521527",90) # damn you're tall.
dummies = [Adam,Steve,user3521527]
sorted_dummies = sorted(dummies, key = lambda x: x.height)
The stdlib sort function accepts a kwarg named key that accepts a function to run the sort on. In this case, it runs through the list dummies, pulls out each element of the list, assigns it to x, then returns x.height. It sorts the elements based on the return from the key function, so they'll all be sorted according to their height.
Alternatively, you can implement __cmp__ in your object.
class Dummy(object):
def __init__(self,name,height):
self.name = name
self.height = height
def __cmp__(self,other):
"""self < other if self.height < other.height"""
if self.height < other.height: return -1
elif self.height == other.height: return 0
elif self.height > other.height: return 1
This tells Python how to compare objects of that type, so the regular sort function works without a key argument.
>>> Adam < Steve
True
>>> Adam < user3521527
False

Returning an lvalue from a function in python

[Sorry, I'm new in Python. Although it seems to be a very basic question, I did my share of due diligence before asking this audience, trying to avoid really stupid questions].
I'm trying to figure out the correct idiom for returning an l-value from a function. Assume I've a container of 64 objects, and I want to be able to return a reference to these objects.
class ChessBoard:
def __init__(self):
self.squares = [None for x in range(64)]
square( row, col ):
return self.squares(row*8+col) <---- I'd like this to be l-value
Then, from outside the class I want to:
board = ChessBoard()
board.square(0,0) = Piece( Shapes.ROOK, Colors.White ) <-- I'm getting an error here
board.square(0,1) = Piece( Shapes.BISHOP, Colors.White )
... etc.
So, I would like the function 'at' to return a lvalue (Something like a reference in C++), but I can't find anything resembling a reference or a pointer in the language. If I stored a list in each square containing one Piece, it is possible I could do something like: board.square(0,0)[0] = Piece - but it seems crazy (or maybe not - as I said, I'm new to the language).
How would you approach this data structure?
In Python, everything is a reference. The only problem is that None is immutable, so you can't use the returned reference to change the value.
You also can't override the assignment operator, so you won't get this particular kind of behaviour. However, a good and very flexible solution would be to override the __setitem__ and __getitem__ methods to implement the subscription operator ([]) for the class:
class ChessBoard(object):
def __init__(self):
self.squares = [None] * 64
def __setitem__(self, key, value):
row, col = key
self.squares[row*8 + col] = value
def __getitem__(self, key):
row, col = key
return self.squares[row*8 + col]
Usage:
>>> c = ChessBoard()
>>> c[1,2] = 5
>>> c[1,2]
5
You can try something like this, at the cost of having to put bogus [:] indexers around:
class Board:
def __init__(self):
self.squares=[None for x in range(64)]
def square(self, row, col):
squares=self.squares
class Prox:
def __getitem__(self, i):
return squares[row*8+col]
def __setitem__(self, i, v):
squares[row*8+col]=v
return Prox()
Then you can do
b=Board()
b.square(2,3)[:]=Piece('Knight')
if b.square(x,y)[:] == Piece('King') ...
And so on. It doesn't actually matter what you put in the []s, it just has to be something.
(Got the idea from the Proxies Perl6 uses to do this)
As Niklas points out, you can't return an l-value.
However, in addition to overriding subscription, you can also use properties (an application of descriptors: http://docs.python.org/howto/descriptor.html) to create an object attribute, which when read from, or assigned to, runs code.
(Not answering your question in the title, but your "How would you approach this data structure?" question:) A more pythonic solution for your data structure would be using a list of lists:
# define a function that generates an empty chess board
make_chess_board = lambda : [[None for x in xrange(8)] for y in xrange(8)]
# grab an instance
b = make_chess_board()
# play the game!
b[0][0] = Piece(Shapes.ROOK, Colors.White)
b[0][1] = Piece(Shapes.BISHOP, Colors.White)
# Or use tuples:
b[0][0] = (Shapes.ROOK, Colors.White)
b[0][1] = (Shapes.BISHOP, Colors.White)

Categories