I am attempting to access a attribute from an object I have created in a separate python file.
I have tried the following code:
print(self.GENOME[0][0].x)
where self.GENOME[0][0] is the object memory address.
However, I get
AttributeError: 'set' object has no attribute 'x'
agent.py:
import neuron
#Creates an array of custom shape (3,4,3) and assigns unique object
#address
for ii in range(len(_Topology)):
_Genome[ii] = [{neuron.Neuron()} for i in range(_Topology[ii]+1)]
#Calls object variable
print(self.GENOME[0][0].x)
neuron.py:
class Neuron:
def __init__(self):
self.x = 50
_Genome[ii] contains a list that contains a set of at least on Neuron instance. Simplifying, you can make it like this:
>>> a = [{Neuron()} for _ in [1,2]]
>>> a
[{<__main__.Neuron object at 0x0000000002CAFF28>}, {<__main__.Neuron object at 0x0000000002CAFF60>}]
>>> q = [a]
>>> q
[[{<__main__.Neuron object at 0x0000000002CAFF28>}, {<__main__.Neuron object at 0x0000000002CAFF60>}]]
>>>
If you print _Genome, it will look something like that - I'm assuming _Genome is list-like | q above should be analogous to _Genome.
Indexing into it looks like this
>>> q[0]
[{<__main__.Neuron object at 0x0000000002CAFF28>}, {<__main__.Neuron object at 0x0000000002CAFF60>}]
>>> type(q[0])
<class 'list'>
>>> q[0][0]
{<__main__.Neuron object at 0x0000000002CAFF28>}
>>> type(q[0][0])
<class 'set'>
>>>
Set behaviour is well documented - just like most of Python.
One way to access the contents of a set is with a for loop
>>> for thing in q[0][0]:
print(thing.x)
50
>>>
Another way to access the contents of a set is with the pop() method but this will remove an arbitrary item from the set. I don't think you really want this - you have no control over which item you get if there are more than one and the original set has one less item.
>>> x = [[{Neuron()},{Neuron}]]
>>> t = x[0][0].pop()
>>> t
<__main__.Neuron object at 0x0000000002C2F2E8>
>>> t.x
50
>>> x
[[set(), {<class '__main__.Neuron'>}]]
>>>
You could also make a list from the set and use indices to access the contents of the list.
>>> q
[[{<__main__.Neuron object at 0x0000000002CAFF28>}, {<__main__.Neuron object at 0x0000000002CAFF60>}]]
>>> z = list(q[0][0])
>>> z
[<__main__.Neuron object at 0x0000000002CAFF28>]
>>> z[0].x
50
>>>
All of that seems overly complicated and you would probably be better off changing the way you contain the Neuron instances. I have no idea if this is feasible for you. Just dispense with the set containing a single instance:
>>> a = [Neuron() for _ in [1,2]]
>>> a
[<__main__.Neuron object at 0x0000000002C2FDD8>, <__main__.Neuron object at 0x0000000002CD00B8>]
>>> q = [a]
>>> q[0][0]
<__main__.Neuron object at 0x0000000002C2FDD8>
>>> type(q[0][0])
<class '__main__.Neuron'>
>>> q[0][0].x
50
>>>
Related
Are the following declarations different?
l1=list
l2=list()
As I used type() function, following were the results!
type(l1)
<class 'type'>
type(l2)
<class 'list'>
l1 is l2
False
These probably shows that l1 and l2 are not the same. Why does l1 belongs to class type and not class list
l1 = list means assignment of list class in l1 variable.
l2=list() mreans calling list() function to create a list and assign the list to l2 variable.
When you are calling list, you get an instance of it class:
>> l = list()
>> l
[]
but when you assign list to another variable, you are completely transforming all List information to another variable and you can use them as you can use List, for example :
>> a = List
>> l1 = a() # same as l1 = List()
>> l1
[]
>> a
List
>> isinstance(l1, a)
True
>> isinstance(l1, List)
True
I hope this might helps you understand.
In Python, nothing gets called unless you ask for it to be called, with parentheses. Even if there are no arguments. Without the parentheses, you're just referring to the function, or method, or class, or whatever as a value. (This is different from some other languages, like Ruby or Perl.)
This may be a little more obvious with functions or methods:
>>> input
<function input>
>>> abs
<function abs>
>>> 'abc'.upper
<function str.upper>
… but it's exactly the same with classes:
>>> list
list
Those are all perfectly good values, which we can even store in a variable:
>>> abcupper = 'abc'.upper
When you call a function or method, you know what that does. When you call a class, that's how you construct an instance of the class.
Either way, you need the parentheses:
>>> abs(-2)
2
>>> list((1, 2, 3))
[1, 2, 3]
… even if there are no arguments:
>>> 'abc'.upper()
'ABC'
>>> list()
[]
… even if you're calling a method you stored in a variable earlier:
>>> abcupper()
'ABC'
Why does the following code change both variables:
>>> a = []
>>> b = a
>>> a.append(9)
>>> a
[9]
>>> b
[9]
>>>
But the del statement does not achieve the same effect?
>>> a = []
>>> b = a
>>> del(a)
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> b
[]
>>>
When you do:
a = b
What you're doing is assigning the label b to the same object that the label a is refering to.
When you do:
a.append(9)
You're adding 9 to the list object pointed to by both a and b. It's the same object, so they show the same result.
When you do:
del a
You're deleting the reference to the object, not the object itself. If it's the only reference, then the object will be garbage collected. But in your case, there's another reference - b - so the object continues to exist.
Instead of "variables", think in terms of names and objects.
>>> a = []
This makes an empty list object and binds the name a to it.
>>> b = a
This simply says that b is now a new name for the object named by a. We have
>>> a is b
True
del a means that we're forgetting the name a: it is no longer bound to an object.
>>> del a
>>> a
Traceback (most recent call last):
File "<ipython-input-8-60b725f10c9c>", line 1, in <module>
a
NameError: name 'a' is not defined
But that you're no longer calling that list object a, only b, doesn't affect the object itself in any way. Objects don't care, or even know about, what names you've given them. [One semi-exception is that if an object no longer has any references, it may -- or may not, no promises -- be garbage-collected.]
The append method works against the actual object, while del works against the reference i.e. variable name.
(I already answered the question in the other question of yours, so I'm going to use it here as well, with slight modifications:)
del does not delete objects; in fact in Python, it is not even possible to tell the interpreter/VM to remove an object from memory because Python is a garbage collected language (like Java, C#, Ruby, Haskell etc).
Instead, what del does when called on a variable (as opposed to a dictionary key or list item) like this:
del a
is that it only removes the local (or global) variable not what it points to (every variable in Python holds a pointer/reference to its contents not the content itself). In fact, since locals and globals are stored as a dictionary under the hood (see locals() and globals()), del a is equivalent to:
del locals()['a']
(or del globals()['a'] when applied to a global.)
so if you have:
a = []
b = a
you're making a list, storing a reference to it in a and then copying that reference into b without copying/touching the list object itself. Therefore these two calls affect one and the same object:
>>> a.append(1)
>>> b.append(2)
>>> a
[1, 2]
>>> b
[1, 2]
>>> a is b # would be False for 2 identical but different list objects
True
>>> id(a) == id(b)
True
(id returns the memory address of an object)
whereas deleting b is in no way related to touching what b points to:
>>> a = []
>>> b = a
>>> del b # a is still untouched and points to a list
>>> b
NameError: name 'b' is not defined
>>> a
[]
i have the problem where i set a variable but it creates a new one instead, i am not quite sure what is going on here. I have tried using global, setting the variables first and tried to use a tupple but just can't get it working. but this is the problem:
>>> variable = 1
>>> variableList = [variable]
>>> variableList[0] = 2
>>> print(variable)
1
as you can see it variable stays 1 although i set it to 2, is there a easy way to fix this?
Doing variableList = [variable] actually created a new reference(variableList[0]) to the object 1. And when you did variableList[0] = 2, it removed one reference from 1 and assigned variableList[0] to 2. So, using an assignment you can never modify other references.
>>> import sys
>>> variable = 1000
>>> sys.getrefcount(variable)
2
>>> variableList = [variable]
>>> sys.getrefcount(variable) # Reference count increased by 1
3
>>> variableList[0] = 2
>>> sys.getrefcount(variable) #Reference count decreased by 1
2
In fact even you've used +=, that too wouldn't have affected variable because you don't modify a immutable object, you simply assign a new object to that variable name.
>>> a = 100
>>> b = a
>>> b += 10 #This too only affects b
>>> a
100
>>> b
110
But, if variable points to a mutable object and you perform some in-place operation on that object from either variable or variableList[0], then you'll see that both of them have changed.
>>> a = []
>>> b = [a]
>>> b[0].append(1) #in-place operation on a mutable object affects all references
>>> a
[1]
>>> b
[[1]]
you don't set variable. you just change variableList content.
variableList[0] it's a variable like variable so the command variableList = [variable] just copy its value.
it is just like this:
>>> a = 1
>>> b = a
>>> b = 2
>>> print(a)
1
You're reassigning the 0th element of the list (not Array), to the Integer 2, you are not overwriting the variable variable.
>>> variable = 1
>>> variableList = [variable]
>>> variableList[0] = 2
>>> print(variable)
>>> 1
>>> print(variableList)
[2]
It suggest you also look up mutability, as it's important to note that integers are immutable:
The value of some objects can change. Objects whose value can change are said to be mutable; objects whose value is unchangeable once they are created are called immutable.
When you did :variableList = [variable]
you created the first element of veribleList and made its value to balue of variable but it dont makes this first element a varible you just coppied its value so when you change variableList[0] it has nothing to do with variable
I am working with a list of namedtuples. I would like to add a field to each named tuple after it has already been created. It seems I can do that by just referencing it as an attribute (as in namedtuple.attribute = 'foo'), but then it isn't added to the list of fields. Is there any reason why I shouldn't do it this way if I don't do anything with the fields list? Is there a better way to add a field?
>>> from collections import namedtuple
>>> result = namedtuple('Result',['x','y'])
>>> result.x = 5
>>> result.y = 6
>>> (result.x, result.y)
(5, 6)
>>> result.description = 'point'
>>> (result.x, result.y, result.description)
(5, 6, 'point')
>>> result._fields
('x', 'y')
What you do works because namedtuple(...) returns a new class. To actually get a Result object, you instantiate that class. So the correct way is:
Result = namedtuple('Result', ['x', 'y'])
result = Result(5, 6)
And you'll find that adding attributes to these objects does not work. So the reason you shouldn't do it is because it doesn't work. Only abusing the class objects works, and I hope I don't need to go into detail why this is a horrible, horrible idea.
Note that regardless of whether you can add attributes to namedtuples or not (and even if you list all attributes you need beforehand), you cannot change a namedtuple object after it's created. Tuples are immutable. So if you need to change objects after creation for any reason, in any way or shape, you can't use namedtuple. You're better off defining a custom class (some of the stuff namedtuple adds for you doesn't even make sense for mutable objects).
Notice that here you're modifying the type of the named tuples, not instances of that type. In this case, you'd probably want to create a new type with an additional field from the old one:
result = namedtuple('Result',result._fields+('point',))
e.g.:
>>> result = namedtuple('Result',['x','y'])
>>> result = namedtuple('Result',result._fields+('point',))
>>> result._fields
('x', 'y', 'point')
You can easily concatenate namedtuples, keeping in mind that they are immutable
from collections import namedtuple
T1 = namedtuple('T1', 'a,b')
T2 = namedtuple('T2', 'c,d')
t1 = T1(1,2)
t2 = T2(3,4)
def sum_nt_classes(*args):
return namedtuple('_', ' '.join(sum(map(lambda t:t._fields, args), ())))
def sum_nt_instances(*args):
return sum_nt_classes(*args)(*sum(args,()))
print sum_nt_classes(T1,T2)(5,6,7,8)
print sum_nt_instances(t1,t2)
You cannot add a new field to a namedtuple after defining it. Only way is to create a new template and creating new namedtuple instances.
Analysis
>>> from collections import namedtuple
>>> result = namedtuple('Result',['x','y'])
>>> result
<class '__main__.Result'>
result is not a tuple, but the class which creates tuples.
>>> result.x
<property object at 0x02B942A0>
You create a new tuple like this:
>>> p = result(1, 2)
>>> p
Result(x=1, y=2)
>>> p.x
1
Prints the value x in p.
>>> p.x = 5
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
p.x = 5
AttributeError: can't set attribute
This throws error because tuple is immutable.
>>> result.x = 5
>>> result
<class '__main__.Result'>
>>> result._fields
('x', 'y')
>>> p = result(1, 2)
>>> p
Result(x=1, y=2)
This doesn't change anything.
>>> result.description = 'point'
>>> result
<class '__main__.Result'>
>>> result._fields
('x', 'y')
This doesn't change anything either.
Solution
>>> result = namedtuple('Result', ['x','y'])
>>> p = result(1, 2)
>>> p
Result(x=1, y=2)
>>> # I need one more field
>>> result = namedtuple('Result',['x','y','z'])
>>> p1 = result(1, 2, 3)
>>> p1
Result(x=1, y=2, z=3)
>>> p
Result(x=1, y=2)
I don't know if the heading makes sense... but this is what I am trying to do using list
>>> x = 5
>>> l = [x]
>>> l
[5]
>>> x = 6
>>> l
[5] # I want l to automatically get updated and wish to see [6]
>>>
The same happens with dict, tuple. Is there a python object that can store the dynamic value of variable?
Thanks,
There's no way to get this to work due to how the assignment operator works in Python. x = WHATEVER will always rebind the local name x to WHATEVER, without modifying what previously x was previously bound to.(*)
You can work around this by replacing the integers with a container data type, such as single-element lists:
>>> x = [5]
>>> l = [x]
>>> l
[[5]]
>>> x[0] = 6
>>> l
[[6]]
but that's really a hack, and I wouldn't recommend it for anything but experimentation.
(*) Rebinding may actually modify previously bound objects when their reference count drops to zero, e.g. it may close files. You shouldn't rely on that, though.
A variable is a place to store data. A datastructure is a place to store data. Pick the one which meets your needs.
You can do it with the numpy module.
>>> from numpy import array
>>> a = array(5)
>>> a
array(5)
>>> l = [a]
>>> l
[array(5)]
>>> a.itemset(6)
>>> a
array(6)
>>> l
[array(6)]
Generally a 0-D numpy array can be treated as any regular value as shown below:
>>> a + 3
9
However, if you need to, you can access the underlying object as such:
>>> a.item()
6
Here's a kind of hacky method of dynamic access that isn't very extensible/flexible in its given form, but could be used as a basis for something better.
>>> a = 7
>>> class l:
def a_get(self):
global a
return a
def a_set(self, value):
global a
a = value
a = property(a_get, a_set)
>>> c = l()
>>> c.a
7
>>> a = 4
>>> c.a
4
>>> c.a = 6
>>> a
6