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