Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the Pythonic way to initialize, set and get my custom object's attributes, by name?

I'm quite new to Python and I need to make declare my own data structure, I'm a bit confused on how to do this though. I currently have:

class Particle:

    def __init__(self, mass, position, velocity, force):

        self.mass = mass
        self.position, self.velocity, self.force = position, velocity, force

    def __getitem__(self, mass):
        return self.mass

    def __getitem__(self, position):
        return self.position

    def __getitem__(self, velocity):
        return self.velocity

    def __getitem__(self, force):
        return self.force

This isn't working, however, when I try to define an instance of the class with:

 p1 = Particle(mass, position, velocity, force)

Every value just ends up as a (0.0, 0.0) (which is the value for velocity and force).

Could someone explain where I'm going wrong, all I need from the data structure is to be able to pull the data out of it, nothing else. (edit: actually, sorry, I will have to change them a bit later on)

Thanks

like image 369
djcmm476 Avatar asked Mar 07 '13 21:03

djcmm476


3 Answers

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.

like image 143
David Marx Avatar answered Oct 12 '22 10:10

David Marx


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
like image 39
Waleed Khan Avatar answered Oct 12 '22 11:10

Waleed Khan


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
like image 24
Jon Clements Avatar answered Oct 12 '22 10:10

Jon Clements