What's the Pythonic way to initialize, set and get my custom object's attributes, by name?
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?
djcmm476
Updated on July 09, 2022Comments
-
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 about 11 yearsThis 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 about 11 yearsOnly 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 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 about 11 yearsThat's great, thanks! Quick follow up question though, how do I change the values after creating an instance of Particle?
-
Admin about 11 yearsYeah, 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 about 11 yearsOut of interest, why pretend to have properties, when actually having properties is so easy?
-
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 about 11 yearsAh, crap, I'll change that. I will need to edit them a bit afterwards (my bad!).
-
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 about 11 years@delnan How would I go about making, for example, the above acceleration property using the method you're talking about?
-
Admin about 11 yearsNah, 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 about 11 years@delnan That's true. I'm still not used to using
@property
. I'll update the answer. -
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 about 11 years@Incredidave Updated the post to demo assignment and show you a little black magic
-
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 about 11 yearsedit: (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.)