What's the Pythonic way to initialize, set and get my custom object's attributes, by name?
First off, you should understand that __getitem__
is syntactic sugar. It's nice to have, but if you don't need it, don't use it. __getitem__
and __setitem__
are basically if you want to be able to access items from your object using bracket notation like:
p= Particle(foo)
bar = p[0]
if you don't need to this, don't worry about it.
Now, onto everything else. It looks like you've got the main characteristics you want your object to carry around in your __init__
definition, which is fine. Now you need to actually bind those values onto your object using self
:
class Particle:
def __init__(self, mass, position, velocity, force):
self.mass = mass
self.position = position
self.velocity = velocity
self.force = force
That's really it. You can now access these values using dot notation, like so:
mass,pos,vel,f = 0,0,0,0 # just for readability
p = Particle(mass,pos,vel,f)
print p.mass, p.position, p.velocity, p.force
One of the nice things we get out of this is that if we ask python what p
is, it will tell you that it is an instance of the Particle
type, like so:
in [1]: p
out[1]: <__main__.Particle instance at 0x03E1fE68>
In theory, when you work with objects like this you want there to be a "layer of abstraction" between the user and the data such that they don't access or manipulate the data directly. To do this, you create functions (like you tried to do with __getitem__
) to mediate interactions between the user and the data through class methods. This is nice, but often not necessary.
In your simpler case, to update the values of these attributes, you can just do it directly the same way we accessed them, with dot notation:
in [2]: p.mass
out[2]: 0
in [3]: p.mass = 2
in [4]: p.mass
out[4]: 2
You might have figured this out already, but there's nothing magical about the __init__
function, or even the class
definition (where you would/should generally be defining most of your class's attributes and methods). Certain kinds of objects are pretty permissive about allowing you to add attributes whenever/wherever you want. This can be convenient, but it's generally very hacky and not good practice. I'm not suggesting that you do this, just showing you that it's possible.
in [5]: p.newattr ='foobar!'
in [6]: p.newattr
out[6]: 'foobar!'
Weird right? If this makes your skin crawl... well, maybe it should. But it is possible, and who am I to say what you can and can't do. So that's a taste of how classes work.
class Particle:
def __init__(self, mass, position, velocity, force):
self.mass = mass
self.position = position
self.velocity = velocity
self.force = force
particle = Particle(1, 2, 3, 4)
print(particle.mass) # 1
If you want to pretend your class has properties, you can use the @property
decorator:
class Particle:
def __init__(self, mass, position, velocity, force):
self.mass = mass
self.position = position
self.velocity = velocity
self.force = force
@property
def acceleration(self):
return self.force / self.mass
particle = Particle(2, 3, 3, 8)
print(particle.acceleration) # 4.0
Seems like collections.namedtuple
is what you're after:
from collections import namedtuple
Particle = namedtuple('Particle', 'mass position velocity force')
p = Particle(1, 2, 3, 4)
print p.velocity