OK, I asked a similar question before but was too confusing because of my lack of correct terminology. This is my second bite at the apple.
I want to create an object whose __init__ will save the name assigned to the object in a list.
kinda like this:
class Object():
def __init__(self, something):
self.something = something
(now how do I save the xxx, xx, and x names I create below?)
xxx = Object(something)
xx = Object(something)
x = Object(something)
I want a global total_objects (or whatever) that contains [xxx, xx, x]
Sorry for the crummy formatting. I hope my question is still clear.
such as:
total_objects = [xxx, xx, x]
Also, please let me know if my approach is sloppy and there's a better way, but I don't want to have to save the 'x' names in the code itself. Such as total_objects.append(xxx) total_objects.append(xx) etc. I want it to be automatic.
You can't do exactly this in Python, because there's nothing requiring an object to be assigned to a specific name, so the initializer doesn't get passed such info.
For instance, the following lines are all valid Python:
x = Object()
y = x
Object()
[Object() for i in xrange(5)]
x = [Object() for i in xrange(5)]
If you want to keep track of the instances of the object, you can do that, but that's separate from the names that reference those instances:
class Object(object):
my_instances = []
def __init__(self):
my_instances.append(self)
Then Object.my_instances would contain a list of the instances:
[<__main__.Object instance at 0x012BA760>, ...]
However this may not be what you want.
lis = []
class Object():
def __init__(self, var):
self.something = var
lis.append(self) #here self is the reference to the instance being created and you can save it in a list to access it later
xxx = Object('123')
xx = Object('12')
x = Object('1')
for x in lis:
print(x.something)
output:
123
12
1
Related
I'm developing a programming language in Python where you can program a simulation of simple machines. I have written a function that takes some input, parses it, and finds out what the first word is.
Now, for the first word insert, I need to take the next words obj, name, x, and y.
obj: what type of simple machine it is
name: what you want to call the object
x: X coordinate on the graph
y: Y coordinate on the graph
I have already made a function nextword that iterates through the rest of the code and defines each variable as those words, so with the following code:
insert pulley JohnThePulley 3 4
It sees first word is insert, and calls my insert function.
Then, it sets obj to pulley, name to JohnThePulley, and so on.
However, now I need to make an object in the daughter class pulley, under the mother class simple_machines, that has the name JohnThePulley, etc.
The situation I'm in is that for the first word insert, for example, I don't know at all what the next word will be, from all the choices of daughter classes that they can call. I need to create the specified object along with the provided name, the provided X coordinate and the provided Y coordinate.
I have tried doing simple formatting in python using '{}'.format(name) or .format(obj), but those don't work.
# Insert function
def insert(code):
c = 4
syntax = np.array([obj, name, x, y])
nextword(parser.code_array, syntax, c)
objc += 1
return
# Nextword function, code_array[0] is insert, syntax is an array that
# contains all the variables that need to be defined for any function
def nextword(code_array, syntax, c):
assert len(code_array) == c + 1, "Too Many Words!"
for m in range(0, c):
syntax[m] = code_array[m + 1]
return
# Mother Class simple_machines with properties
class simple_machines:
def __init__(self, obj, name, x, y, coords):
self.obj = (
obj
) # what type of obj, in this case, pulley
self.name = name # name, JohnThePulley
self.x = x # 3 in this case
self.y = y # 4 in this case
self.coords = (x, y) # (3,4) in this case
return
# Pulley Class, here so I can later define special properties for a pulley
class pulley(simple_machines):
def __init__(self, name, x, y):
super(simple_machines, self).__init__()
return
# Code that I tried
def insert(code):
c = 4
syntax = np.array([obj, name, x, y])
nextword(parser.code_array, syntax, c)
"{}".format(name) = "{}".format(obj)(
name, x, y
) # this is what my
# instantiation would look like, formatting an object with name, then
# calling a class formatted with obj, and inserting their input of
# name,x,y as the properties
return
I expect an object in pulley to be created with the name JohnThePulley, and the coordinates X = 3 and Y = 4. What I'd like to result in, in simpler terms, is an object called name in a class called obj with the attributes name.x, name.y, etc
However, I get errors like:
NameError: name 'obj' is not defined
or:
SyntaxError: can't assign to function call
The first one apparently means that the word obj isn't being assigned, but the second one apparently means that I can't format a function name or format a variable name and define it as a function (even though I'm instantiating it as a class).
What am I doing wrong? How can I fix this?
name 'obj' is not defined is because obj is defined in another function. You have to use MYOBJECT.obj, not obj alone, and also keep a reference to MYOBJECT.
'{}'.format(obj)(name,x,y) doesn't mean anything, '{}'.format(obj) is a string and isn't callable.
SyntaxError: can't assign to function call is the actual problem you seem to be interested in. You could do globals()['{}'.format(name)] = stuff but it doesn't work for local variables and objects (and your linter is not going to like it).
If you want to do the same for objects you can use setattr(MYOBJECT, '{}'.format(name), '{}'.format(obj))
All of the solutions above are in technical terms considered "ugly" and what you're probably looking for is a dictionary, while it isn't OOP, dictionaries are used behind the scenes to handle exactly what you want to do with objects. An object without methods is essentially a just dictionary.
mydico = dict()
mydico[name] = obj
Also, if name is a string, then '{}'.format(name) is equivalent to name.
So I'm new to working with classes in python, but this project Euler(q 81) I have is done using classes just to be a bit more tricky? I guess?
I can get the values of a (2n+1 * 2n+1) grid, but I can't work with them to append to another list or even write to a file.
def minSum(matrix):
file = open("pleasedeargodwork.txt", "w")
newList = []
for x in maxtrix.grids:
for y in x:
newList.append(y)
print y,
file.write(y,)
print newList
>>> 1 7 2 5 6 2 9 2 5
>>> TypeError: must be string or read-only character buffer, not instance
>>> <matrix.Supplies instance at 0x0240E9B8>
^^ I would like this last line to give me the values, rather than the instance, but how?
My matrix class looks something like this:
class Matrix:
def __init__(self, grids):
self.size = len(grids) / 2
self.grids = [[Supplies(s) for s in row] for row in grids]
class Supplies:
def __init__(self, supp):
if isinstance(supp, list):
self.value = supp[0]
"Matrix" is the class name, "matrix" is the filename and an argument given to my class minSum to be able to access this file.
If you need to see any more of the matrix file let me know.
Thanks.
Looks like you have another error when you try to write an instance to the text file but here's a way to print the values instead of the instance:
The __repr__ method lets you define what the object looks like when it is printed.
Add a __repr__ method to the Supplies class like so:
class Supplies:
def __init__(self, supp):
if isinstance(supp, list):
self.value = supp[0]
def __repr__(self):
return str(self.value)
Whenever you print a Supplies instance, Python will print its value attribute instead. Note that value is not guaranteed to be defined in the Supplies class so you might want to either initialize it or check before you attempt to convert it to a string in the __repr__ method.
Edit
If you want newList to contain the values of each Supplies instance you could just append the value instead of the instance:
newList.append(y.value)
instead of:
newList.append(y)
I want to create instance objects automatically as I explained in the following:
Class MyClass:
def __init__(self,x):
self.x = x
list = ["A","B"]
I want to create the following but automatically, means to loop through the list and create identical object for each element:
A = MyClass(text)
B = MyClass(text)
e.g. like the following which doesn't work:
# this doesn't work but explains more what I need
for i in list:
i = MyClass(text)
Thanks to all of your help!
In general, you can't and shouldn't shove things into your namespace like that. It's better to store those instances in a dict or a list
Class MyClass:
def __init__(self,x):
self.x = x
lst = ["A","B"] # don't use list as an identifier
myclasses = {k: MyClass(text) for k in lst}
Now your instances are
myclasses['A'], myclasses['B'] etc.
If you really want to create a handful of variables in your namespace:
A, B = (MyClass(text) for x in range(2))
note that this means you need to be explicit. You can't get the A,B from a file or user input etc.
Don't be tempted to use exec to pull this off. It's probably the wrong way to go about solving your problem. Tell us why you think you need to do it instead.
I am a quit new python programer and just for curiosity I want to know how I can reach to the name of instance which is made in the body of main,in the methods of my class . I want to know whether there is a built-in method for classes or I should manage it myself. by the way, I don't want to use lists or Dictionaries. a sample code is following:
class Vec2D(object):
def __init__(self,X, Y):
self.x=X
self.y=Y
print "X coordinate is ",self.x # I want to add it here
print "Y coordinate is ",self.y # and here
if __name__ == '__main__':
mypoint1 = Vec2D(0,1)
mypoint2 = Vec2D(1,2)
It could be considered as a reporting issue...
You can't. A value has no way to know what variable refers to it.
The reason is quite simple; you can have multiple variables refer to the same value:
mypoint3 = mypoint1
Now what name does the instance have?
Well, for starters, you couldn't print the name in __init__() because the object is still being constructed and hasn't been assigned one yet. Even if it were, there's no built-in way to find out what it is in Python.
However it is possible to search for the object after construction in the module's global namespace, which allows you to do things like this:
class Vec2D(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
my_name = '<unknown>'
namespace = globals().copy()
for name,obj in namespace.items():
if obj is self:
my_name = name
break
return "\n".join(["{!r}:",
" X coordinate is {}",
" Y coordinate is {}"]).format(my_name, self.x, self.y)
if __name__ == '__main__':
mypoint1 = Vec2D(0,1)
mypoint2 = Vec2D(1,2)
print mypoint1
print mypoint2
Output:
'mypoint1':
X coordinate is 0
Y coordinate is 1
'mypoint2':
X coordinate is 1
Y coordinate is 2
However this isn't foolproof because if there are two names for the same object, the for search loop will stop as soon as it finds one of them. It could be modified to find them all, I suppose...
As #MartijnPieters said, these's no way to get the variable name of an instance. The names are not kept after interpreting.
But if you do have the special need, I think there're at least 2 approaches for you.
Let's say you have an instance MyInstance of class MyClass, then
str(MyInstance) will give you a string like <__main__.MyClass instance at 0x1044b6f80>, it uniquely indicates MyInstanceduring the runtime. You might want to use it as the name of the instance.
Explicitly define a "name" in the construction of the class, like:
class MyClass:
def __init__(self, name):
self.name = name
. Afterwards you can always get the name by:
MyInstance = MyClass("Instance1")
print MyInstance.name
I am developing a simple application which hava a file Constants.py containing all configuration, it is like this
x = y
during execution of program , the value of y changes , I want value of x o get updated too , automatically, this can be reffered as binding, how can I achieve this
In Python variable names point at values. x=y tells Python that the variable name x should point at the value that y is currently pointing at.
When you change y, then the variable name y points at a new value, while the variable name x still points at the old value.
You can not achieve what you want with plain variable names.
I like KennyTM's suggestion to define x as a function since it makes explicit that the value of x requires running some code (the lookup of the value of y).
However, if you want to maintain a uniform syntax (making all the constants accessible in the same way), then you could use a class with properties (attributes which call getter and setter functions):
Constants.py:
class BunchOConstants(object):
def __init__(self, **kwds):
self.__dict__.update(kwds)
#property
def x(self):
return self.y
#x.setter
def x(self,val):
self.y=val
const=BunchOConstants(y=10,z='foo')
Your script.py:
import Constants
const=Constants.const
print(const.y)
# 10
print(const.x)
# 10
Here you change the "constant" y:
const.y='bar'
And the "constant" x is changed too:
print(const.x)
# bar
You can change x also,
const.x='foo'
and y too gets changed:
print(const.y)
# foo
If you change the value (object) itself, then all references to it will be updated:
>>> a = []
>>> b = a # b refers to the same object a is refering right now
>>> a.append('foo')
>>> print b
['foo']
However, if you make the name point to some other object, then other names will still reference whatever they were referencing before:
>>> a = 15
>>> print b
['foo']
That's how python works. Names are just references to objects. You can make a name reference the same object another name is referencing, but you can't make a name reference another name. Name attribution using the = operator (a = 15) changes what a refers to, so it can't affect other names.
if your configuration values are inside a class, you could do something like this:
>>> class A(object):
... a = 4
... #property
... def b(self):
... return self.a
...
then, every time you access b, it will return the value of a.
There is a simple solution you can do. Just define a property and ask for the fget value you defined.
For example:
a = 7
#property
def b():
return a
if you ask for b, you will get something like this <property object at 0x1150418> but if you do b.fget(), you will obtain the value 7
Now try this:
a = 9
b.fget() # this will give you 9. The current value of a
You don't need to have a class with this way, otherwise, I think you will need it.