0

Let us assume I have a basic object with a handful of self-relevant points of data.

class A(object):
    def __init__(self, x, y, width, length):
        self.x = x
        self.y = x
        self.width = x
        self.length = x

And so we go on to instantiate several A objects and shove them into a list, as programmers are wont to do.

Now let us assume that these objects need to be checked for a particular state every so often, but we needn't check them on every pass, because their state doesn't change particularly quickly. So a checking method is written somewhere:

def check_for_ticks(object_queue):
    for obj in object_queue:
        if obj.checked == 0 and has_ticks(obj):
            do_stuff(obj)
        obj.checked -= 1

Ah, but wait - it wasn't designed with obj.checked attribute! Well no big deal, Python is kind and lets you add attributes whenever, so we change the method a bit.

def check_for_ticks(object_queue):
    for obj in object_queue:
        try:
            obj.checked =- 1
        except AttributeError:
            obj.checked = 0
        if obj.checked == 0 and has_ticks(obj):
            do_stuff(obj)

This works, but it gives me pause. My thoughts are mixed, because while it's a functional attribute to give an object and it solves a problem, the attribute isn't really used by the object. A will probably never modify its own self.checked attribute, and it isn't really an attribute that it 'needs to know about' - it's just incredibly convenient to give it that attribute in passing.

But -- what if there are multiple methods that might want to flag an object? Surely one does not create the class with every attribute that some other method might maybe want to flag it for?

Should I be giving objects new attributes in this way? If I should not, what is the better alternative to just giving them new attributes?

  • If that flag attribute is used solely by that function, then it might be a better idea to create a dict mapping objects to their 'checked' value. – tobias_k Feb 27 '14 at 21:34
0

I've seen examples where that works well, but it's mostly for PODs that are dynamically populated by other code, say as a result of a REST or database query.

Usually, when you want to reach into another object's data, that's a sign your responsibilities are in the wrong classes, or could use some rearchitecting.

My first thought in your particular case is to create a separate queue for unchecked objects, and modify whatever code enables has_ticks to also put the object into the unchecked object queue. That would have the side benefit of not having to cycle through every single element even when most or all of them don't need checking.

Another option is tobias_k's comment about creating a dict in the object queue that maps the object to a checked value.

Another option is in the internal representation of the queue, store an [A, checked] as each list element instead of just A.

Another possible approach is the Decorator Pattern, by which you create a wrapper that adds the functionality you want. Then you can wrap it when you put it into the queue and unwrap when you dequeue it. The decorator has the advantage that you can move a lot of the functionality of your check_for_ticks function into your CheckedA object, or other functionality that really belongs with the element objects instead of the queue. The wrapper class might look like:

class CheckedA(A):
    def __init__(self, wrappedA):
        self.wrappedA = wrappedA
        self.checked = 0

    def check_for_ticks(self):
        if self.checked == 0 and has_ticks(self.wrappedA):
            do_stuff(self.wrappedA)
        self.checked -= 1

Another option is just calling do_stuff directly whenever a tick is added, if your requirements allow for it.

Creating an attribute from outside the class adds coupling, and even worse, that coupling is invisible to anyone reading the source code of the class. You have no protection against someone else doing the same thing and using the same name in an incompatible manner. You have lots of other options before you need to resort to that kind of solution.

| improve this answer | |
  • Decorators are the hotness, for sure. I have a handful of wrappers in this particular project and it hadn't occurred to me to use one in this way. I like this. – user112358 Feb 27 '14 at 22:26
0

One method is to create a companion class that has the checked attribute in it with the primary object using the Delegate pattern. However, that means that your lists need to be lists of companion objects and not the primary objects.

In practice, adding a flag or state attribute isn't necessarily a big deal. However, it tends not to scale well.

The method you are using is possible in Python and a couple of other interpreted languages. It makes me feel icky inside, so I understand your discomfort.

| improve this answer | |
0

Having a "checked" member of your object directly couples your object and algortihm. Sometimes this is acceptable, because there is a natural coupling between them. In the case of a garbage collection algorithm, most have a few flags on each object because there are a fixed set of operations that will occur on the object.

If you are looking for a way to do the same thing without coupling, consider using a set object. Python's sets are fast (they use hashes), so generally it is safe to do it

checked = set()
...
if obj not in checked:
    checked += obj

In python, this is actually just as fast as having an attribute on the object. In a strongly typed language like C++, it is likely that the attribute would be faster, but I have found few cases in real life application where that speed difference mattered enough.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy