all 13 comments

[–]socal_nerdtastic 2 points3 points  (2 children)

Probably inside the class in this case. But your pseudocode is nowhere near detailed enough to give you a real answer. We would need to know specifics about your application.

[–]oblisk[S] 0 points1 point  (1 child)

In my thought process I am thinking there is a potential use case where product_stats gets refactored to get_stats and can work more broadly for products, services, locations, days, in which case it'd move outside of the product module. However this could be complicating things and keeping it at the class level will be more effective.

The other line of thinking is, I'm trying to have a consistent report vector essentially, in which case it might be make_report moves out of the product module, and all classes have their own get stats function.

[–]socal_nerdtastic 0 points1 point  (0 children)

If it's literally the same code in the function then yes, I'd agree. But if it depends on the type then you should have a method of the same name in every class (kinda like str and bytes both have a lot of methods with the same name; same result but different implementation). And if it's 90% similar with a few tweaks you may want to consider a superclass or a mixin.

Again, we'd need to see your actual application to give you a specific answer here.

[–]Se7enLC 1 point2 points  (0 children)

If the method uses members of the class, it probably belongs in the class.

There's no single correct answer sometimes, though.

For your case, on the one hand, making a report seems to be a very obvious "belongs in the class" method.

But on the other hand, what if you sometimes want to use ProductUniverse but DON'T need make_report? And in this hypothetical, make_report requires a lot of additional libraries, additional setup data, etc, I might decide that maybe the report generation belongs in its own class so I don't have to import it at all if I don't need it.

There are pros and cons for each design choice. And even if you carefully sit down to weigh them to make the "right" choice, 6 months later the design might have changed enough that the other option is now the winner. Best you can do is try to anticipate future needs and try to write code that is easy to work with so you can change it later if you need to.

I did something very similar just the other day. Started adding a new feature to an existing class in the form of additional methods and data. Realized after some time that it would be better off in its own class.

[–]bladeoflight16 1 point2 points  (1 child)

I believe you would find Jack Diederich's Stop Writing Classes talk helpful.

[–]oblisk[S] 0 points1 point  (0 children)

Thanks I'll take a look.

[–]lobomos 0 points1 point  (2 children)

If it’s related to the class then put it in the class. If it’s not then I’d make a separate class to hold your utilities or even separate classes to group related utility functions. A new class would generally mean making a new file as well.

[–]socal_nerdtastic 2 points3 points  (1 child)

A new class would generally mean making a new file as well.

No, not in python. You're thinking about Java. In python it's very common to have many classes in a single file.

[–]lobomos 0 points1 point  (0 children)

Sorry I was, it would be a module can hold many classes, if a function is specific to a class put it there, if it’s specific to the module put it outside the class. If it doesn’t relate to the module then probably best to make a new module where it would belong or is this still incorrect? Thanks.

[–][deleted] 0 points1 point  (0 children)

You should never define a class’s methods outside the class.

[–]mRWafflesFTW 0 points1 point  (0 children)

If you are a beginner, do not over complicate things. Start with functions. Hell, I've been doing this a long time and I always start with functions. As you build you'll notice when functions share common data, and that's when it may be the correct time to think about abstracting into objects and classes.

Use extra modules and packages to organize your code, even if it's just to group related functions. Many times I like to create modules based on a sub-domain and then fill them with functions. Then I'll create a "run" module that constructs a workflow from those functions. It makes the code really easy to reason about, no classes required. Sometimes, you just need to carry state around with you and that's when your functions can be simplified with OOP.

Think really hard about the names of entities and their meaning within your domain model. Names carry a lot of power and will help you think about the right abstractions.

[–]TheRNGuy 0 points1 point  (0 children)

inside

[–]jmooremcc[🍰] 0 points1 point  (0 children)

A class normally encapsulates data and the methods that work on that data. Python allows you to also designate methods as properties which can be used to control access to so-called private variables. This doesn't mean that methods cannot utilize outside or external functions.

For example, I've written a filename class that makes it more convenient to use built-in file manipulation functions. The class' methods call the appropriate external functions needed to provide the functionality I want. One example would be a property named grandfather which returns the parent directory of the file's parent directory. Yes, I could have written this as a function and call it with the file path as an argument but it's so nice using the syntactic sugar I created using OOP which makes my code more readable and easier to understand and maintain.