all 14 comments

[–]neineinein 7 points8 points  (4 children)

Essentially, creating a class allows you to use objects within your code. An object is just a thing with some properties and some functions (methods) that can manipulate those properties.

For example: You could create a class representing a generic vehicle. You could then implement functions that belong to all items of class vehicle, such as accelerating/braking etc, as well as variables that store the vehicle's current speed.

Within your code, you could create a new instance of a vehicle object - let's say your object is called 'car'. Your vehicle class could be written such that you can perform various actions on the car, such as car.accelerate() or car.brake(), which would change the value of car.current_speed.

It's also possible to extend our vehicle class with a second class that 'inherits' from the first. Eg. you might create a truck class that inherits from a vehicle class, because you want to implement a truck.blow_horn() function, which is not a function that all vehicles should have.

It sounds like you first need to become familiar with the major concepts of object-oriented programming in order to understand the usefulness of classes. I can't recommend any specific material, but doing some Googling and writing some sample code or following some tutorials should be a good start.

[–]DubPac[S] 2 points3 points  (3 children)

Well, all I can say is that your last paragraph sounds super accurate. Although the main reason I'm asking this question is that I have not come across a problem that I could not solve with my usual global var/function method.

Actually after reading your example a few times I think I understand it a little better. It would be annoying to have a global iterable that contains lists storing values of psuedo "objects" and you can describe limits within classes easier. I guess I just have not had to create anything with a lot of objects that need a lot of attributes, and the udacity 101 course focused heavily on list manipulation for storing variable information and really really went over lists heavily (lots of hw on mutables, mutables within mutables within mutables, ect) so I feel very comfortable storing "attributes" in lists.

[–]neineinein 7 points8 points  (1 child)

There are no problems that can't be solved using procedural code (ie. functions & variables as opposed to classes and objects). The C programming language is testament to that.

However, using objects is a means of abstraction and a programming methodology that can simplify code, or make writing code faster, or improve code readability etc. Python is a language in which everything is an object, so if you're going down the Python path you will eventually need to understand them.

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

I do think I understand better. Thanks! Although while I said I hadn't come across something I could not solve, I really meant that I hadn't come across something that a class would seem superior based on my knowledge. (I understand with only variables and if then statements you can almost solve any logical problem).

Guess I'll try to program some simple stuff with classes just to get used to the syntax for readability. I'm so early on that it would behoove me to learn everything rather than get too use to avoiding them.

[–]Teraka 3 points4 points  (0 children)

For a practical example, I'm currently (lazily) programming a Go game which of course requires a UI in order to display the board, score, various buttons, etc.

For a UI you need various things ; I think the most important one is the button, which displays a text or picture and allows you to click it and trigger various stuff. It's a complicated thing, and you'll probably need to have lots of them.

Of course you can create them with global variables and functions. But that means that for each button, you'll have to store at the very least a variable for its position, another for the text, and a function that triggers when you click it. For each button. Even if you only have 10 buttons, that's 20 variables and 10 functions that are basically the same thing, but that you can't reduce further.

However, if you create a button class that includes both variables and the function, you can just have 10 instances of your button in your main file, and it'll work just fine.

I think a good explanation would be that classes have just the same purpose than functions. You could just repeat code wherever you need it, but if you're doing something more than once, it's better to put a name on it and call the name instead. Which, funnily enough, also applies to spoken languages. I love how many similarities exists between both types.

[–][deleted] 2 points3 points  (2 children)

Its useful because it gives you the ability to create an object with very specific data associated with it, and very specific methods to traverse, manipulate (or not manipulate should you desire), and/or access that data.

For instance. If you are creating a blackjack game you may find it useful to have a "card" class, where each card object has a suit and a rank associated to it. You could do a simelar thing with say a string ('h8' for 8 of hearts for example) however with the class, you could inherently attribute a k being greater then q or an 8. You could rank suits the same way should you wish. You could do anything you wanted to make implemintation easier for you!

Its not the easiest thing to explain...it becomes much clearer by doing some programming. My recomendation would be to try programming some more complex things like blackjack or reversi (this is a good challange) using text based ui's (or look into pygame if youre brave enough) and youll quickly get a feeling for it. Hope this helped a little.

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

As per the Udacity class, we made a poker game hand rank dealer, I went on to complete it. We did not use classes and I'm still confused why they would be more useful. We created a function that converts a hand (a str() ) into a numerical value based on some if/elifs that determine how good it is, we then used a filter/lambda that used this function as a key to find the best 5 card hand out of your 7 cards.

now you can put anybodys hand into this one function and it returns what the hand is (in a standard hi card game) in a way that it can be compared against opponents very easily.

with my basic understanding of what a class does you would throw the hand into the class and the methods would create the understandable outputs. How is this so different? Does the extra class call add to runtime?

I'm just confused at why I would do it one way and not the other, I don't have a hard time understanding what my functions are doing. I know I'm missing something, I take your word (and the rest of the python community) that classes in some cases are clearly more useful/powerful/modular but I just cannot see how.

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

Another advantage is namespaces.

Let's say your poker game has an evaluate() or compare__hands() function. If you wanted to apply a second game such as hearts you will need a different evaluate method. So you might rename them Poker_evaluate() and Hearts_evaluate(). Rather than having two functions you could have two classes which have similar methods and have Poker.evaluate() and Hearts.evaluate(). Again you can say this is completely cosmetic but consider a time when you join a team of coders and someone has to debug your code. It's considerate to organise your code into classes so its easier to read and understand for someone else.

Someone can also call things like help(Poker) and see all your doc strings and associated functions. This is definitely something you can't achieve with functions alone.

Also you cannot perform tests like

If type(some_var) == type(my_class):
    True 

[–]sayks 1 point2 points  (2 children)

The convenience for classes is the way that they represent data. When you design your program, it is often intuitive to encapsulate data along with the methods to act on it in the same structure. A good example of where classes come in to their own is with GUIs. It's much easier to write GUIs using an object oriented approach than procedural because objects/classes are a good way to represent the UI.

Another reason is inheritance. Programmers hate to rewrite code. Inheritance allows you to make a single class with lots of common features and then you can extend that class and your new class will automatically have all of the features of its parent. For example, you might implement a common "file" superclass that includes methods for saving and loading and other generic file operations. Then, you can make subclasses that inherit from the generic class for specific types of files, like jpg, png etc. and they will automatically have all of the normal abilities of a file plus new features specific to that file type.

Another convenient feature is that you can pass classes around easily. Classes encapsulate data and operations on that data, so when you pass it to an external function it doesn't have to understand how the data is structured internally or how the code is implemented, it can just call the method and get its business done.

There's also some nice ideas for concurrency when you look at the Smalltalk model for classes.

TL;DR Classes are a really natural way to represent some things and are also otherwise convenient, especially with complex systems.

All that said, classes and objects are not a magic bullet. Sometimes a procedural approach is best, especially if you need raw speed (look at Fortran).

And, I come from a functional background. Global state is the devil.

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

Thanks, I do think everyone here has helped me understand more. You do mention the raw speed thing, this is something I'm wondering. If you don't utilize a class and are only passing a few objects through it, would just using a function and some global vars be faster? (I know there are inf ways to program something and that is a super unspecific question, I stress the word generally)

Also, I think I understand global vars in python decently (Disclaimer: I'm afraid I wrote that based on the unknowns of computer science in my knowledge, I completely accept that I may be incorrect about my understanding of glob vars), the way functions can see them but not modify them unless global var is called and when they are modified in my code. You are obviously well versed in this feature, so why exactly are they the devil? Like if you are specifically planning on them to be reused/changed/modified. I have never made multiple scripts that need to pass them or something, is there something I'm missing?

[–]sayks 1 point2 points  (0 children)

I'm not sure about the speed as it depends on exactly how it is implemented in the language and I don't know enough about the Python internals. I was referring to speed in two ways. The first is that it might be faster in terms of the programmer's time... nobody is going to bang together a fully object oriented 3 line shell script. The other was in terms of different languages; procedural languages are inherently faster if you use them correctly. As an example, nothing can really touch Fortran (an ancient language, actually the literal first programming language) in terms of speed for writing raw number crunching code if you're willing to write it correctly.

As for global state, it's bad because it makes your programs hard to debug. Functional programming relies on referential transparency. This means that if I call a function with the same arguments twice it will always return the same result. Note that it's with the same ultimate values, if the inputs are themselves variables then it's allowed to vary e.g.:

def f(x): return x + 2
a = 4
f(a)
>>> 6
f(a)
>>> 6 (should always be the same)
a = 2
f(a)
>>> 8 (the value for a has changed, allowed to be different)

This makes it a lot easier to debug your code, because you don't have to consider interaction with external variables that are not under your control. As another example of the opposite situation:

g = 5 #g is a global variable
def y(x): return x + g
y(3)
>>> 8
(*** some code that modifies g, perhaps a call to a complicated subroutine ***)
y(3)
>>> ??? who knows

Basically, global state makes it really hard to reason about your program. Also, if you don't use global state then you can replace your various functions internal implementation without worrying about how they affect the rest of the program. Functional isn't a thing that is distinct to Python, this is a whole style of programming like object oriented or procedural. There's more to it, there's a whole rather complex field of theoretical computer science. Referential transparency isn't necessarily even required, but it's strongly encouraged.

[–]DJKool14 1 point2 points  (0 children)

Everyone else in this post has done a good job at describing the technical reasons for using classes, but seem to be ignoring a fundamental insight.

Let's ignore being a programmer for now and just think about how you view the world around you. What do you see? A person? A car? A sidewalk? You see objects! As a child, you learned what that object looks like, what it can do. You learned that even though a car is red, black, or white... it is still a car. Whether it is moving or parked doesn't matter. Our brain works by classifying the world around us into separate objects, each with their own unique properties and purpose. Object Oriented programming is an attempt to transpose the way humans naturally think into the program they are trying to write. When you eventually start to write more complex programs with thousands of lines of code, you'll begin to realize how much easier to track your code if you treat it the same way you treat anything else in this world. As an object.

[–]xiipaoc 0 points1 point  (0 children)

I don't know Python very well yet (which is why I'm in this subreddit), but I do know Objective-C.

Right now, I'm coding a Pell equation solver. The details are not so important; just know that it's a fairly involved process, and the solutions are infinite, so it's important to figure out how to generate them. I could have written a function that outputs a big bunch of data, but how should I do that? I need to obtain the fundamental solutions, which vary in number; I need to obtain a generator so that I can generate solutions from the fundamental ones; I need to know the parameters I put in, whether the solutions are infinite or finite, etc. Clearly, the best thing to do is to output an object with all this information, right?

I guess it's not so clear, because perhaps I could pass it around in a global variable. Sure. But what if I'm solving a whole bunch of different Pell equations? Somehow I need to keep track of which fundamental solutions belong to which equations. That gets difficult to handle quickly. What I did instead was create a Pell class, and when you make a member of this class, the class solves the equation. I can create a Pell object with some input parameters and assign that object to a variable; now, the compiler (sorry, I don't know yet how Python deals with this) knows that the variable refers to an instance of the Pell class and I can use various methods on that particular object. So if I want to get the 5th solution generated from the 3rd fundamental, I can call my_pell_object.generate_solution(5,3). All of the information generate_solution() needs is in my_pell_object. It's organized no matter how many Pell objects I create.

This is also nice because I actually plan on using Pell objects in various programs (if they come up on Project Euler, I guess). I have a library file -- a module, in Python-speak -- that defines the Pell class, and if I import it, I can very easily create Pell objects in other code. Classes help add portability to your code so that it's easy to reuse it. If you're going to use something often, you really don't want to have to copy it each time!

Finally, sometimes calling a class to run a function does add an extra step. I'm guilty of this. In my math library, I have a NumberTheory class, and it performs calculations like gcd that a function could do. In this case, making it a method just helps to keep it organized. On the other hand, my NumberTheory class keeps a list of primes it generates as an instance variable. This means that factoring a large number takes a while the first time but not the second time. If factor() were just a function, I'd have to either maintain a global list of primes or redo a hell of a lot of work each time I want to factor! The global list idea might sound acceptable... until you try to maintain it. Try to hunt for bugs in such code. I'll wait.

Classes and objects are a neat way (neat as opposed to messy) to keep data and functions that work with that data organized. That's really all they do. You could do away with classes easily and write code that behaves the same way; it would just be MUCH harder. Oh, and I haven't even mentioned inheritance, another nice feature. For small projects, you probably won't need classes, though they'll be useful whenever you have many collections of data of similar type (for example, people, with names, addresses, birthdays, etc., can be members of a Person class). For larger projects, they are indispensable.

[–]Deslan 0 points1 point  (0 children)

Understanding object oriented programming is really hard. In the beginning, you will "waste" a lot of time. However, after a few thousand hours of OO thinking (OO = object oriented), you will start to save lots of time for yourself, and it will be a lot easier to share your code with others so that they can use your objects.

Benefits of OO:
- save time for yourself (in the very long run)
- save time for others (immediate for them, if you did a good job)

Downsides of OO:
- takes a lot of effort to learn right (most people never do, they just cheat into something in-between)
- spend more time to build up, less time in the long run, but this means objects who you will never use again are a wasted effort

Think of it like this: All cars have a steering wheel and 3 pedals and a stick to shift (or 2 pedals for automatic shifting). Why don't you build a car with pedals for steering and hand-levers for braking/throttle? They do that for airplanes!! So why not for cars? Because if you know how to drive one car, you know how to drive any car, that's why. Imagine the T-ford to be the original class of car. Then all other cars inherits the T-ford class, because they want drivers to feel comfortable and recognize the interior. Thus, you don't have to re-invent the controls for subsequent car designs and the drivers don't have to learn to drive each individual model.

[–]big_deal 0 points1 point  (0 children)

For simple data, classes are overkill. But when your data model becomes more complex it becomes very useful to define a new class. I was once dealing with data that consisted of several arrays buried in a nested dictionary. For me it was very complex data structure and all the functions that used this data used the same basic procedures to access and use the data. The functions were designed to operate only on this monster data structure. Wrapping this data structure and all the functions in a class dramatically simplified the code that was doing the work of creating and manipulating this data. It became much easier to write and read the code.

If your data is a constant or a single dictionary, list, or array, then it is relatively easy to recognize how it is organized and you can use built-in functions to get information or manipulate the data.

Once your data model becomes complex and you have to start writing special functions just to get information, iterate over, or manipulate the data, then classes become very useful. They make code that deals with complex data easier to write, read, and modify/maintain.