I recently discovered Python's property
built-in, which disguises class method getters and setters as a class's property. I'm now being tempted to use it in ways that I'm pretty sure are inappropriate.
Using the property
keyword is clearly the right thing to do if class A
has a property _x
whose allowable values you want to restrict; i.e., it would replace the getX()
and setX()
construction one might write in C++.
But where else is it appropriate to make a function a property? For example, if you have
class Vertex(object):
de开发者_JAVA技巧f __init__(self):
self.x = 0.0
self.y = 1.0
class Polygon(object):
def __init__(self, list_of_vertices):
self.vertices = list_of_vertices
def get_vertex_positions(self):
return zip( *( (v.x,v.y) for v in self.vertices ) )
is it appropriate to add
vertex_positions = property( get_vertex_positions )
?
Is it ever ok to make a generator look like a property? Imagine if a change in our code meant that we no longer stored Polygon.vertices
the same way. Would it then be ok to add this to Polygon
?
@property
def vertices(self):
for v in self._new_v_thing:
yield v.calculate_equivalent_vertex()
When you have a normal attribute and getting and/or setting it makes sense for a class's user, expose the attribute directly. One big reason that public members are anathema in some languages is that if you need to do something more complex later you would need an API change; in Python you can just define a property.
If you are using something you should abstract as attribute access, use property. If you want to make external state (your plot or website or something) aware of the change or if you are wrapping some library that uses members directly, properties might be the way to go.
If something isn't attribute-y, don't make it a property. There's no harm in making a method, and it can be advantageous: what it does is more obvious, you can pass around some bound method if you need, you can add keyword arguments without an API change.
It's hard to imagine a situation where I would use a generator function as a property. The only way to have a normal attribute that would behave at all similarly would require quite a lot of complexity, so that case isn't very reminiscent of attribute access.
You point out you can use
property
for restricting access to some internal attribute_x
. This can be true, but keep in mindIf you are going to do things like sanitize input for security or something important, explicit is better than implicit. You don't want to feel like code just-works when it comes to such things, because then you'll run into code that doesn't.
Sometimes people use
property
to implement read-only attributes. It's usually better just to have a normal attribute and realize you can't stop a user from doing something dumb and unsupported.
Nitpicking you might find interesting:
property
isn't a keyword; it's a normal name you can rebind. This is sort of interesting sinceproperty
isn't a syntax thing or anything: it's a normal class you could implement yourself in pure Python. It uses the same mechanism that makes methods work in Python—descriptors.You describe what
property
does as "disguises class method getters and setters", which isn't quite the case. The things thatproperty
take are just normal functions, and needn't actually be defined in your class at all;property
will passself
for you. Functions don't actually become methods until you look them up, when Python creates method objects on-the-fly. During the class definition, they are just functions. When you have a normal method it's called an "instance method"; in Python "class method" refers to another special thing sort of like properties that changes what happens when an attribute is looked up.
There is an obvious limitation in the use of properties: it does not accept any argument, and it will never do.
So you must be sure that the function you are transforming into a property will never be refactored into a function with, for example, extra default arguments.
精彩评论