Skip to main content
Commonmark migration
Source Link

Problem

#Problem I’mI’m working on a Python project whose main class is a bit “God Object”. There are so friggin’ many attributes and methods!

I want to refactor the class.

So Far…

##So Far… ForFor the first step, I want to do something relatively simple; but when I tried the most straightforward approach, it broke some tests and existing examples.

Basically, the class has a loooong list of attributes—but I can clearly look over them and think, “These 5 attributes are related…These 8 are also related…and then there’s the rest.”

getattr

I basically just wanted to group the related attributes into a dict-like helper class. I had a feeling __getattr__ would be ideal for the job. So I moved the attributes to a separate class, and, sure enough, __getattr__ worked its magic perfectly well…

At first.

But then I tried running one of the examples. The example subclass tries to set one of these attributes directly (at the class level). But since the attribute was no longer “physically located” in the parent class, I got an error saying that the attribute did not exist.

@property

I then read up about the @property decorator. But then I also read that it creates problems for subclasses that want to do self.x = blah when x is a property of the parent class.

#Desired

Desired

  • Have all client code continue to work using self.whatever, even if the parent’s whatever property is not “physically located” in the class (or instance) itself.
  • Group related attributes into dict-like containers.
  • Reduce the extreme noisiness of the code in the main class.

For example, I don’t simply want to change this:

larry = 2
curly = 'abcd'
moe   = self.doh()

Into this:

larry = something_else('larry')
curly = something_else('curly')
moe   = yet_another_thing.moe()

…because that’s still noisy. Although that successfully makes a simply attribute into something that can manage the data, the original had 3 variables and the tweaked version still has 3 variables.

However, I would be fine with something like this:

stooges = Stooges()

And if a lookup for self.larry fails, something would check stooges and see if larry is there. (But it must also work if a subclass tries to do larry = 'blah' at the class level.)

#Summary

Summary

  • Want to replace related groups of attributes in a parent class with a single attribute that stores all the data elsewhere
  • Want to work with existing client code that uses (e.g.) larry = 'blah' at the class level
  • Want to continue to allow subclasses to extend, override, and modify these refactored attributes without knowing anything has changed

Is this possible? Or am I barking up the wrong tree?

#Problem I’m working on a Python project whose main class is a bit “God Object”. There are so friggin’ many attributes and methods!

I want to refactor the class.

##So Far… For the first step, I want to do something relatively simple; but when I tried the most straightforward approach, it broke some tests and existing examples.

Basically, the class has a loooong list of attributes—but I can clearly look over them and think, “These 5 attributes are related…These 8 are also related…and then there’s the rest.”

getattr

I basically just wanted to group the related attributes into a dict-like helper class. I had a feeling __getattr__ would be ideal for the job. So I moved the attributes to a separate class, and, sure enough, __getattr__ worked its magic perfectly well…

At first.

But then I tried running one of the examples. The example subclass tries to set one of these attributes directly (at the class level). But since the attribute was no longer “physically located” in the parent class, I got an error saying that the attribute did not exist.

@property

I then read up about the @property decorator. But then I also read that it creates problems for subclasses that want to do self.x = blah when x is a property of the parent class.

#Desired

  • Have all client code continue to work using self.whatever, even if the parent’s whatever property is not “physically located” in the class (or instance) itself.
  • Group related attributes into dict-like containers.
  • Reduce the extreme noisiness of the code in the main class.

For example, I don’t simply want to change this:

larry = 2
curly = 'abcd'
moe   = self.doh()

Into this:

larry = something_else('larry')
curly = something_else('curly')
moe   = yet_another_thing.moe()

…because that’s still noisy. Although that successfully makes a simply attribute into something that can manage the data, the original had 3 variables and the tweaked version still has 3 variables.

However, I would be fine with something like this:

stooges = Stooges()

And if a lookup for self.larry fails, something would check stooges and see if larry is there. (But it must also work if a subclass tries to do larry = 'blah' at the class level.)

#Summary

  • Want to replace related groups of attributes in a parent class with a single attribute that stores all the data elsewhere
  • Want to work with existing client code that uses (e.g.) larry = 'blah' at the class level
  • Want to continue to allow subclasses to extend, override, and modify these refactored attributes without knowing anything has changed

Is this possible? Or am I barking up the wrong tree?

Problem

I’m working on a Python project whose main class is a bit “God Object”. There are so friggin’ many attributes and methods!

I want to refactor the class.

So Far…

For the first step, I want to do something relatively simple; but when I tried the most straightforward approach, it broke some tests and existing examples.

Basically, the class has a loooong list of attributes—but I can clearly look over them and think, “These 5 attributes are related…These 8 are also related…and then there’s the rest.”

getattr

I basically just wanted to group the related attributes into a dict-like helper class. I had a feeling __getattr__ would be ideal for the job. So I moved the attributes to a separate class, and, sure enough, __getattr__ worked its magic perfectly well…

At first.

But then I tried running one of the examples. The example subclass tries to set one of these attributes directly (at the class level). But since the attribute was no longer “physically located” in the parent class, I got an error saying that the attribute did not exist.

@property

I then read up about the @property decorator. But then I also read that it creates problems for subclasses that want to do self.x = blah when x is a property of the parent class.

Desired

  • Have all client code continue to work using self.whatever, even if the parent’s whatever property is not “physically located” in the class (or instance) itself.
  • Group related attributes into dict-like containers.
  • Reduce the extreme noisiness of the code in the main class.

For example, I don’t simply want to change this:

larry = 2
curly = 'abcd'
moe   = self.doh()

Into this:

larry = something_else('larry')
curly = something_else('curly')
moe   = yet_another_thing.moe()

…because that’s still noisy. Although that successfully makes a simply attribute into something that can manage the data, the original had 3 variables and the tweaked version still has 3 variables.

However, I would be fine with something like this:

stooges = Stooges()

And if a lookup for self.larry fails, something would check stooges and see if larry is there. (But it must also work if a subclass tries to do larry = 'blah' at the class level.)

Summary

  • Want to replace related groups of attributes in a parent class with a single attribute that stores all the data elsewhere
  • Want to work with existing client code that uses (e.g.) larry = 'blah' at the class level
  • Want to continue to allow subclasses to extend, override, and modify these refactored attributes without knowing anything has changed

Is this possible? Or am I barking up the wrong tree?

Tweeted twitter.com/#!/StackProgrammer/status/185061789636112384
Source Link
Zearin
  • 209
  • 2
  • 10

How to refactor a Python “god class”?

#Problem I’m working on a Python project whose main class is a bit “God Object”. There are so friggin’ many attributes and methods!

I want to refactor the class.

##So Far… For the first step, I want to do something relatively simple; but when I tried the most straightforward approach, it broke some tests and existing examples.

Basically, the class has a loooong list of attributes—but I can clearly look over them and think, “These 5 attributes are related…These 8 are also related…and then there’s the rest.”

getattr

I basically just wanted to group the related attributes into a dict-like helper class. I had a feeling __getattr__ would be ideal for the job. So I moved the attributes to a separate class, and, sure enough, __getattr__ worked its magic perfectly well…

At first.

But then I tried running one of the examples. The example subclass tries to set one of these attributes directly (at the class level). But since the attribute was no longer “physically located” in the parent class, I got an error saying that the attribute did not exist.

@property

I then read up about the @property decorator. But then I also read that it creates problems for subclasses that want to do self.x = blah when x is a property of the parent class.

#Desired

  • Have all client code continue to work using self.whatever, even if the parent’s whatever property is not “physically located” in the class (or instance) itself.
  • Group related attributes into dict-like containers.
  • Reduce the extreme noisiness of the code in the main class.

For example, I don’t simply want to change this:

larry = 2
curly = 'abcd'
moe   = self.doh()

Into this:

larry = something_else('larry')
curly = something_else('curly')
moe   = yet_another_thing.moe()

…because that’s still noisy. Although that successfully makes a simply attribute into something that can manage the data, the original had 3 variables and the tweaked version still has 3 variables.

However, I would be fine with something like this:

stooges = Stooges()

And if a lookup for self.larry fails, something would check stooges and see if larry is there. (But it must also work if a subclass tries to do larry = 'blah' at the class level.)

#Summary

  • Want to replace related groups of attributes in a parent class with a single attribute that stores all the data elsewhere
  • Want to work with existing client code that uses (e.g.) larry = 'blah' at the class level
  • Want to continue to allow subclasses to extend, override, and modify these refactored attributes without knowing anything has changed

Is this possible? Or am I barking up the wrong tree?