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

26,526

Solution 1

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.

Solution 2

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

Solution 3

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

Solution 4

you can just put this class definition ahead before you use it. If you want to declare it, check this site: http://www.diveintopython.net/getting_to_know_python/declaring_functions.html

By the way, your question is similar to this post: Is it possible to forward-declare a function in Python? and also this post: Is it possible to use functions before declaring their body in python?

Share:
26,526
djcmm476
Author by

djcmm476

Updated on July 09, 2022

Comments

  • djcmm476
    djcmm476 almost 2 years

    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

  • djcmm476
    djcmm476 about 11 years
    This is great, thanks. I'm quite new to Python, and I was struggling to find anything decent to describe this. As usual with Python, the answer is simpler than I thought.
  • Admin
    Admin about 11 years
    Only if the attributes don't have to change ever during an object's lifetime, and you're fine with it being a sequence. The neatness of namedtuples also suffers a blow when you need to add methods, or something constructor-like (they're still useful, but require more careful handling and ugly code to make it work well).
  • Jon Clements
    Jon Clements about 11 years
    @delnan True, but I'm going by the OP's statement of all I need from the data structure is to be able to pull the data out of it, nothing else.
  • djcmm476
    djcmm476 about 11 years
    That's great, thanks! Quick follow up question though, how do I change the values after creating an instance of Particle?
  • Admin
    Admin about 11 years
    Yeah, and your answer is alright. It's just that I almost never see those limitations even hinted at, even when important, so I made a habit of mentioning them.
  • Admin
    Admin about 11 years
    Out of interest, why pretend to have properties, when actually having properties is so easy?
  • Waleed Khan
    Waleed Khan about 11 years
    @delnan Suppose a property is defined by a formula relying on two other properties. If you change one of them (like mass) you'd also have to update acceleration. That probably means buggy or messy code.
  • djcmm476
    djcmm476 about 11 years
    Ah, crap, I'll change that. I will need to edit them a bit afterwards (my bad!).
  • Admin
    Admin about 11 years
    @WaleedKhan I am a Python veteran. When I say "property", I mean the property builtin, preferably used as decorator. Which, as you may or may not know, do exactly that -- just in a better and prettier way.
  • djcmm476
    djcmm476 about 11 years
    @delnan How would I go about making, for example, the above acceleration property using the method you're talking about?
  • Admin
    Admin about 11 years
    Nah, that's just an awful way to write a dictionary. I am opposed to using the ability to add and remove attributes to objects without very strong reasons. It makes errors harder to spot (sometimes this thing has an attribute, sometimes it hasn't, depending on control flow).
  • Waleed Khan
    Waleed Khan about 11 years
    @delnan That's true. I'm still not used to using @property. I'll update the answer.
  • Admin
    Admin about 11 years
    @Incredidave Assignment, as with variables (there are some subtle differences, but most people get along for months without understanding them, so you should be fine ^^): p.mass = new value
  • David Marx
    David Marx about 11 years
    @Incredidave Updated the post to demo assignment and show you a little black magic
  • neilr8133
    neilr8133 about 11 years
    @delnan I agree in general, but for someone new to Python it's a simple solution and doesn't require an understanding of dictionaries, hashing, and the get() method. (It's also in the Python tutorial docs: docs.python.org/3/tutorial/classes.html#odds-and-ends)
  • neilr8133
    neilr8133 about 11 years
    edit: (insert: "get() method to specify a value if the attribute doesn't exist, or some other method to probe if it's been defined"). Personally, I'd rather see a full class with __init__ and proper get/set methods for all the properties, but in my (possibly incorrect) opinion, this met the OP's needs.)