2

Sometimes I need to change the name of a Python class attribute that is being already extensively used in the rest of the code.

The problem is that for various reasons I may miss some places where the old name appears in an assignment statement such as class_instance.old_attribute_name = something. For example:

class theClass:
    def __init__(self):
        self.new_attribute_name = 0

o = theClass()
o.new_attribute_name += 3
if o.new_attribute_name > 3 or o.new_attribute_name < 4:
    o.old_attribute_name = 7
do_stuff_with(o.new_attribute_name)

The problem is that this can be difficult to spot, will rise no error and just create a useless attribute. I considered using __slot__, but feels like forcing my deep-seated C/C++ mindset on Python.

So I would like to ask, what am I doing wrong here? What will I lose if I try (somehow) to prevent attribute creation outside of instantiation? What is the pythonic way to handle stray attribute assignments?

3 Answers 3

2

You can make the old attribute name a property

class theClass(object):
    def __init__(self):
        self.new_attribute_name = 0

    @property
    def old_attribute_name(self):
        print "Tried to access old_attribute_name"
        return self.new_attribute_name

    @old_attribute_name.setter
    def old_attribute_name(self, value):
        print "Tried to set old_attribute_name"
        return self.new_attribute_name
Sign up to request clarification or add additional context in comments.

2 Comments

I would note that I would do this (personally, I'd throw an exception rather than just printing) to debug, to ensure the old code has been dealt with, then remove it once that is done.
Ideally you'd use "warnings.warn" with "DeprecationWarning" to be able control whether access to the old name throws an exception or merely prints a warning to standard output.
0

Instead of trying to find all the places you need to change with search-and-replace, you could instead try a "refactoring" tool.

What refactoring tools do you use for Python?

3 Comments

Note that due to Python's dynamic nature refactoring tools cannot catch all possible ways of attribute access, and hence likely miss names that are used in polymorphic code, or accessed dynamically (i.e. getattr()).
@lunaryorn, Indeed. But it doesn't make such tools entirely worthless. A great deal of Python code exists that isn't very dynamic
@gnibbler Didn't say any different. Rope is a good and important tool, but just keep in mind that it might miss occurrences when refactoring. Double check the sources afterwards, and have good test coverage before starting.
0

You can do this with property. It will block both getting and setting of the old attribute name.

class A(object):
    @property
    def old_name(self):
        raise NotImplementedError()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.