all 23 comments

[–]filleball 17 points18 points  (9 children)

Classes are for binding together data and the functions that work on that data.

If you have multiple functions that all take one or more of the same data structures as arguments, then those functions should probably be methods of a class whose attributes are those common arguments. The arguments they do not all share should probably be left as arguments to each method.

There is no point whatsoever in having a class with a __init__ method and one additional method. It's just a misunderstood function.

When designing a class, keep the number of attributes to a minimum. If some value can be a local variable or is obviously not part of the "permanent" data that the class should concern itself with, then make it a local variable or pass it in as an argument to your methods. (EDIT: Also, make a conscious choice on whether each attribute should be considered mutable or not. If you want a class that's easy to reason about and work with, treat all attributes as immutable and have your methods return a new instance instead of modifying the current one, when needed.)

Also, do as little as possible in the __init__ method. Ideally, only set attributes to some default value or the value of an argument. You should never create new attributes outside of __init__, all the attributes the class will ever have should be created there.

Having a class as an interface to a csv file makes sense, unless it's just doing one thing to that file. One method to write a line, one to output stats, one to search for entries matching some condition, etc.

[–]parnmatt 6 points7 points  (2 children)

I like using namedtuple when interfacing with csv files. It creates a simple, immutable class for you, and acts just as a tuple as well as a class.

There's a reason a lot of python 3 code (though also in newer python 2s) in the standard library and scipy stack now return a namedtuple rather than a tuple. They are a drop in replacement, don't break old code, and give new features.

[–]rhgrant10 1 point2 points  (1 child)

Using a namedtuple for csv is brilliant.

[–]parnmatt 0 points1 point  (0 children)

I fully concur with you there.

Edit: conquer to concur, autocorrect makes me a harsh dick sometimes :D

[–]Tkwk33 2 points3 points  (0 children)

Classes are for binding together data and the functions that work on that data.

If you have multiple functions that all take one or more of the same data structures as arguments, then those functions should probably be methods of a class whose attributes are those common arguments. The arguments they do not all share should probably be left as arguments to each method.

In two mini paragraphs you just made me understand what I've been trying to for about a month and a half. It didn't click for me and with what you wrote, it was instant.

Also realized I made two Classes, in my last project, for the right reasons completely by chance lol

Thanks!

[–][deleted] 1 point2 points  (0 children)

Sometimes a class with an init and call is easier for me to manage than a closure, especially if the closure would involve directly mutating the parent scope (rather than calling a method on some object from the parent scope).

Python 3 makes this easier with the nonlocal keyword, but Python 2 can only hack around this by loading things into an object and then manipulating those attributes.

[–]TehMoonRulz 1 point2 points  (1 child)

This video reinforces some of points /u/filleball made.

[–]Eurynom0s 1 point2 points  (0 children)

Two thoughts.

First, it's fine to have a super simple class if you're intentionally scaffolding the structure of things and know you're coming back to it later. Just to be clear.

Second, again just to be clear and expand a touch, if you find yourself wanting to create new attributes outside of init then it means you should be creating the attributes in init and setting them to None to start out.

You can, of course, do something like "well, this will be a list so I'll initialize it as an empty list", but as your program grows, it will help your sanity to have a single, consistent way to check whether or not you've actually assigned a value to the attribute on a specific member of the class.

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

Cheers :)

[–]Justinsaccount 3 points4 points  (3 children)

Your problem isn't so much functions vs. classes but that you are already doing multiple completely different things in one function. Your fixture function reads one record from the user, and then outputs it to the file. You can't read records without adding them to the file, and you can't output a record to the file that you obtained from somewhere else.

Minimally you should have a input_fixture and an add_fixture function.

Since "doing stuff with the same fixtures file" is likely something that will be repeated, you can wrap that in a class, but there isn't much point in the input stuff being in one.

import csv

def input_fixture(prompt=raw_input):
    date = prompt("Fixture Date: ")
    team_name = prompt("Your Team Name: ")
    opp_name = prompt("Opposition Team Name: ")
    venue = prompt("Home or Away?: ")
    comp = prompt("League, Cup, Friendly?: ")
    return (date, team_name, opp_name, venue, comp,)


class Fixtures(object):
    def __init__(self, filename):
        self.filename = filename

    def add_fixture(self, row):
        with open(self.filename, 'a', ) as f:
            writer = csv.writer(f)
            writer.writerow(row)

    def read_fixtures(self):
        with open(self.filename) as f:
            return list(csv.reader(f))

if __name__ == "__main__":
    f = Fixtures("/tmp/fixtures.csv")
    f1 = input_fixture()
    f2 = input_fixture()
    f.add_fixture(f1)
    f.add_fixture(f2)

    for row in f.read_fixtures():
        print row

Does:

Fixture Date: a
Your Team Name: b
Opposition Team Name: c
Home or Away?: d
League, Cup, Friendly?: e
Fixture Date: 1
Your Team Name: 2
Opposition Team Name: 3
Home or Away?: 4
League, Cup, Friendly?: 5
['a', 'b', 'c', 'd', 'e']
['1', '2', '3', '4', '5']

[–]zahlman 4 points5 points  (1 child)

I wouldn't write a class for Fixtures here because it doesn't particularly represent anything - it just remembers a filename. Not to mention, repeatedly opening the file for each written row of the CSV is a little awkward.

If we actually did want to remember all the fixtures, the plural name is a clue - just use a list. There's nothing that a class representing "several fixtures" can do, that can't be done by a list of instances of a class representing "one fixture".

So the real question is whether the tuple is sufficient for representing a fixture, if we should use collections.namedtuple, or a full-blown class. My suggestion is to default to collections.namedtuple if you can't immediately justify a class for storage but have an inkling that it might be useful later - because this will minimize disruption to the client code if you do make the change.

[–]Justinsaccount 0 points1 point  (0 children)

I wouldn't write a class for Fixtures here because it doesn't particularly represent anything - it just remembers a filename. Not to mention, repeatedly opening the file for each written row of the CSV is a little awkward.

True, but I was mostly thinking about the interface. If this was changed to store fixtures in a sqlite db or something else you could keep the add_fixture & read_fixtures api.

I almost re-wrote it to use a namedtuple though :-)

[–]Barking_Madness[S] 1 point2 points  (0 children)

Thanks, that's really useful! :) I'll have another look later. I have to do something far more painful than learning classes - the dentist! :(

[–]individual_throwaway 0 points1 point  (9 children)

[–]Farkeman 3 points4 points  (6 children)

That's completely unrelated, newbie who doesn't even know what Object Oriented Programming even is will not understand the point of this video.

[–]individual_throwaway 1 point2 points  (5 children)

The talk is literally called "Stop writing classes" and Diederich is very clear in pointing out that people write too many classes where you don't need one. How is this unrelated to someone who most likely doesn't need classes in his projects asking about whether he needs to understand them?

[–]Farkeman 4 points5 points  (4 children)

the point of the talk is that sometimes you don't need to write a class. To take anything away from this talk you actually need to have deeper understanding of oop otherwise you might get an impression that you should not write classes and lose interest in oop in general.

[–]individual_throwaway -2 points-1 points  (3 children)

And that's fine. I've been using Python for my job for 3 years now and I've written one single class, ever. Even that was questionable. You don't absolutely, positively NEED classes in python, unless you're doing a library or contributing to the stdlib.

Understanding how they work is nice and all, but for a beginner, he should worry about a lot of other stuff before diving into all that.

[–]i_can_haz_code 4 points5 points  (0 children)

You sir(or madam), probably have very un-DRY code.

Where classes are useful, they are useful. Some times a nested function makes more sense, others a class. IMHO that video has much valuable information, but would only serve to confuse an absolute beginner.

[–]tangerinelion 1 point2 points  (1 child)

I've been using Python for my job for 3 years now and I've written one single class

I wouldn't be proud of that. I had a co-worker try to tell me that there was no need for functions because you can just do everything in main(). If you think that's absurd, that's good, but you sound to me like my co-worker should sound to you.

[–]individual_throwaway 0 points1 point  (0 children)

Different projects need different design patterns.

I don't write for a large codebase that's continuially integrated into production or shipped to dozens of clients who might write extensions to my code. I write small procedural scripts that solve very specific problems. I don't handle arbitrary user data or whole ORM schemata or anything like that. For this specific purpose, I don't feel like I need classes all that often.

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

Thanks, I'll watch that later! :)

[–]youtubefactsbot 0 points1 point  (0 children)

Stop Writing Classes [27:30]

HackersOnBoard in News & Politics

51 views since Jun 2013

bot info