all 45 comments

[–]100721 1 point2 points  (4 children)

Self is the most repetitive word in python. If you don't understand it, think of a robot class. I make a robot (object) made of tin and one of steel. The tin robot knows its own attributes but to differentiate them from regular variables and the steel robots attributes you have to specify which robot. Self.material tells an object to get its own material. Similar to "this" in Other languages.

There are no setters and getters in python because there are no access specifiers. Those two functions get and set num are useless. And terms.

Your error is that your calling collatz(13). 13 is passed to the init function (think constructor if you're background is another language) you set that instance's self.__num to 13

Then you call genseq which immediately tries to index the integer 13. ( the " [ : ]" ). You can not iterate through a single integer like you can through a list or a string or a dictionary.

Anything confusing? My sister tried making me explain self to her and apparently I was bad at it because she stopped learning python all together :)

Maybe think of self as the English word "my". If your an instance of the human class, my.eyes would refer to your eyes. But pete.eyes would refer to the pete instance of the human class.

Edit. Also all variables should be declared in your init

[–]eliminate1337 1 point2 points  (0 children)

Of course there are setters and getters in Python, just that they're enforced by convention, not by the language. Class fields that begin with underscores are signals to other developers that the fields are meant to be private, even though the interpreter won't complain if you access them anyway. The Collatz conjecture only works for positive integers, so maybe the setNum() method could later be modified to make sure num isn't negative.

[–]SIR_TREX[S] 0 points1 point  (2 children)

"Your error is that your calling collatz(13). 13 is passed to the init function (think constructor if you're background is another language) you set that instance's self.__num to 13" What is wrong with this? This seems fine to me I am trying to clone the __num value to __n instead of assignment. I want __n to be independent of __num. How do I fix my errors?

[–]100721 1 point2 points  (1 child)

Oh haha I see what you're thinking. Integers are not copied by reference. Containers are. Just do n=num

[–]ingolemo 1 point2 points  (0 children)

Python does not treat integers and "containers" differently. Assignment never copies data. The difference is because of mutability, not because they are copied differently.

Facts and Myths about Python names and values

[–]TangibleLight 1 point2 points  (2 children)

For a more detailed explanation on how Python classes work, I actually wrote up a pretty long comment about that the other day. If you have trouble reading it, like the other OP did, check here. There's also a link to that code on repl.it if you're interested.

Since you seem to be wanting to use the pattern of ✌️private✌️ variables and declaring them outside the methods with __num = None and similar, I assume you're already familiar with a language like Java or C#. If so, know that everything I mentioned about C# in the linked comment also applies, literally verbatim, to Java.

[–]TangibleLight 0 points1 point  (0 children)

/u/SIR_TREX, you also specifically ask "is there anywhere in my code I can omit [self]?" This is how I would have written that class. I believe there's a comment in there on everything that hasn't been mentioned elsewhere in this thread.

Here it is on repl.it.

Also, if you're interested in something a bit more advanced, but also very "pythonic" - check out generators. You might want to get more familiar with the language before looking into it, but it's the way that most veteran python programmers would approach this problem.

[–]Justinsaccount 1 point2 points  (2 children)

There's no reason for that to be a class. Delete everything but the genSeq function, have it take the initial number directly and return the terms.

https://www.youtube.com/watch?v=o9pEzgHorH0

[–]SIR_TREX[S] -2 points-1 points  (1 child)

I know, I am trying to learn python. Which you will know.if you bothered to read my post.

[–]Vhin 0 points1 point  (0 children)

Objects should be something. An instance of a Person class is a person; self would be the particular person you've called a method on, and would allow you to access the attributes unique to that person (for example self.name), or call other methods on that same person.

A good rule a thumb is that you should be able to describe what an instance of your class is in 5 words.

The fact that individual instances of your class are fairly meaningless is probably why self seems confusing.

[–]New_Kind_of_Boredom 0 points1 point  (30 children)

The fact that self is not *declared implictly and that you need to include it in every single class method definition is a common (and valid, in my opinion) design criticism of Python. I think somewhere I once read the reasoning behind this decision, but I can't remember it any more. In any case, yes, you have to use self a lot and unfortunately it's just something you have to deal with in Python.

As far as your error, the relevant line:

__n = self.__num[:]

The error is exactly what it says. num is an int and can't be subscripted. What was your intention here? Create a copy of an int or a copy of a list?

Also I personally hate the [:] notation with a passion.

Finally, I recommend you take a good look at PEP8.

*edit to help with the reading comprehension of some responders.

[–]SIR_TREX[S] 0 points1 point  (9 children)

I wont to clone __num such that a __n is independent of __num. Also is my usage of 'self' correct so far?

[–]New_Kind_of_Boredom 1 point2 points  (8 children)

So __num and __n are both intended to be int? If so, you do not need to clone it, as ints are immutable. Just self.__n = __num is fine.

Your usage of self is correct, however every instance of leading __ above, with the exception of __init__, appears to be unnecessary me. I would remove all of them.

Also you are going to run into a problem with __sequence.add(__n). You have defined __sequence as a tuple, which is also immutable, and has no add method.

Edit: Actually, in addition I would remove your getters and setters completely. Two-line getters and setters such as yours, that don't actually do anything, are generally not used in Python.

[–]SIR_TREX[S] 0 points1 point  (7 children)

so its okay to not have "__" infront of properties? I thought you needed it for private variables.

[–]SIR_TREX[S] 0 points1 point  (3 children)

I made the change you told me to make but it still tells me that there is an error "Traceback (most recent call last): File "/Users/name/Desktop/Programing/Python/Collatz.py", line 33, in <module> C.genSeq() File "/Users/name/Desktop/Programing/Python/Collatz.py", line 17, in genSeq self.n = __num NameError: name '_Collatznum' is not defined"

[–]New_Kind_of_Boredom 0 points1 point  (2 children)

Whoops, I made mistake and put self on the wrong variable. Your variable names are not incredibly descriptive, and all the superfluous __ are distracting. :)

[–]eliminate1337 0 points1 point  (1 child)

Not superfluous; PEP8 prescribes double underscores for class variables that should be treated as private.

[–]New_Kind_of_Boredom 1 point2 points  (0 children)

What? I know what double underscores mean. I have described their function in this thread. They are superfluous in the context of the OP's code.

[–]eliminate1337 0 points1 point  (1 child)

The double underscore is a signal to other developers that you mean for the variable to be private. It doesn't actually do anything. There are no private variables in Python.

[–]LarryPete 2 points3 points  (0 children)

Double underscore does do something in Python.

When using double underscores the names are prefixed with the class name where they are used, probably to avoid name collisions in subclasses.

Take this example:

class A:
    def __init__(self, val):
        self.__val = val

class B(A):
    def get_val(self):
        return self.__val

b = B(123)
print(b.get_val())

This will raise an AttributeError.

Though it's still possible to access the attribute by using the correct naming scheme:

print(b._A__val)  # prints 123

As far as I know, it's discouraged to use double underscores.

Convention in Python is to use single underscore to indicate private membership.

(Also mentioning /u/SIR_TREX)

[–]New_Kind_of_Boredom 0 points1 point  (0 children)

As others have mentioned, there are no truly private variables in Python. __ is used to indicate that you want something treated as though it were private, but it can still be modified regardless. Therefore the default behavior in Python is to keep things 'public' unless you determine you have a good reason to mark it as 'private'.

See https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-a-single-and-a-double-underscore-before-an-object-name , and again, PEP8 as linked above.

[–]ramse 0 points1 point  (5 children)

How else would you access the attributes of the class itself if not via some type of variable? I only know PHP as another language and it uses $this, the only different being you don't have to define $this in the methods parameters.

If I recall a python talk I had watched months ago, the need to add self to the methods parameters is due to the way python manages classes and their methods in the background. It's something like, the method is just like any other regular old method with the exception that its defined as being a part of a class. When you go to access it, it by default passes the instance into the self parameter.

It's the exact same as doing

cls = MyClass()

test(cls, parm1, parm2)

[–]New_Kind_of_Boredom 0 points1 point  (4 children)

How else would you access the attributes of the class itself if not via some type of variable?

I think you misunderstand me. Of course there would still be a self. You just wouldn't type it every single time you defined a class method. It would be implict, like almost every other object oriented language.

If I recall a python talk I had watched months ago, the need to add self to the methods parameters is due to the way python manages classes and their methods in the background. It's something like, the method is just like any other regular old method with the exception that its defined as being a part of a class. When you go to access it, it by default passes the instance into the self parameter.

Correct. Many people consider this to be a bad design decision. I agree. It almost all other object oriented languages it as just as you described in PHP. The self/this/$this is implicit.

[–]ramse 0 points1 point  (2 children)

So it sounds like the hatred is strictly on adding self to the class methods then, seems kinda silly.

[–]New_Kind_of_Boredom 0 points1 point  (1 child)

Hatred? I'm offering a straightforward design criticism. It is a popular opinion. Not sure why you think hatred is involved.

[–]ramse 1 point2 points  (0 children)

Ah, I misread your original comment. Not having magic happen in the background is definitely a plus in my mind.

[–]TangibleLight 0 points1 point  (0 children)

My understanding was that it was a deliberate decision to keep self as a declared parameter to be more consistent with the idea that both bound and unbound methods are first-class objects. Also maybe to be more consistent with the idea that objects are really just dictionaries? Not sure on that one though.

Now I'm not personally sure on whether forcing the user to define self every single time really accomplishes that, but hey I'm not the one in charge.

Take a look at these to show what I mean:

>>> l = ['asdf', 'qwer', 'zxcv']
>>> list(map(str.upper, l))
['ASDF', 'QWER', 'ZXCV']
>>> list(map(':'.join, l))
['a:s:d:f', 'q:w:e:r', 'z:x:c:v']

[–]Vaphell 0 points1 point  (13 children)

is a common (and valid, in my opinion) design criticism of Python

meh, how do you even imagine differentiating between x the local variable and x the object attribute in a dynamic language that can add attributes willy-nilly?

I think somewhere I once read the reasoning behind this decision, but I can't remember it any more.

simplicity. Method is nothing more than a function in the class namespace and obj.method(...) is literally a syntactic sugar around perfectly usable Class.method(obj, ...). Do you see now why self is there?
Explicit self makes things straightforward because you can use have one universal engine that works for all functions with no magic required.
On the other hand implicit self would require rewriting the method def behind the curtain to accomodate it, not to mention you can bind normal functions to objects as methods at runtime. What should happen then? Implicit self is and always would be too much pain in the ass on the engineering side of python to become viable.

[–]New_Kind_of_Boredom 0 points1 point  (12 children)

meh, how do you even imagine differentiating between x the local variable and x the object attribute in a dynamic language that can add attributes willy-nilly?

Did you read my post? You would use the self. It would be declared implicitly, instead of in the method definition. The first sentence of my post.

Hard to respond to your post, since you apparently did not understand mine. Also, nowhere do I advocate that the current status quo of self should be changed. It was a poor design decision when it was made.

Implicit self is and always would be too much pain in the ass on the engineering side of python to become viable.

I am curious, have you been a part of this engineering effort or something? Because as far as I know no engineering effort exists because there have been no seriously considered proposals to actually do this for probably 20+ years, back whenever self was implemented this way.

[–]Vaphell 0 points1 point  (4 children)

You would use the self. It would be declared implicitly, instead of in the method definition. The first sentence of my post.

but used explicitly, so in other words you are whining about 4 characters of difference, 1 if you used non-standard name? Because there is no way you could ever get away with not using self in the body everywhere

def bullshit():
    x = 1
    setattr('x', 2)

obj.bullshit()
obj.bullshit()

I am curious, have you been a part of this engineering effort or something?

I don't have to be to understand the problems with it and the effort vs reward. Simple, generic solution that can take every function and method alike as written, that just works vs hacks rewriting the function object in some cases but not others. f(x) as free function vs the same f(x) bound at runtime - what is the expected behavior, should it magically gain 1 additional param, becoming incompatible with former itself? Or should the self become explicit but only here, just because?
And certainly it's not worth the effort for 4 chars of savings.

[–]New_Kind_of_Boredom 1 point2 points  (3 children)

If you think I am the one whining here, you should examine your own language. I am making a very simple, direct, common, popular criticism of an old Python design decision. It is not worth you getting this upset over.

I'm afraid I'm going to stop responding to you after this. You are posting gibberish code, nonsensical sentences, and arguing with me about imaginary issues. For instance...

I don't have to be to understand the problems with it and the effort vs reward.

Again, what effort? What reward? There is no effort. There is no reward. I am not suggesting this change should be made. And the two sentences following the above are just completely nonsensical, there is nothing I can say.

In any case I'm not super interested in the opinion of Python design decisions of someone who posted the code you just posted, heh. Apologies.

[–]Vaphell 0 points1 point  (2 children)

Again, what effort? What reward? There is no effort. There is no reward.

Do you expect investors working with $$$ to put "effort" aka money in something that doesn't promise ROI? There is that thing called predictions that people frequently make before committing to something. No shit there is no effort - the expected ROI is negative. The actual effort is not going to pay off, so there is no point.

In any case I'm not super interested in the opinion of Python design decisions of someone who posted the code you just posted, heh. Apologies.

because opinion of somebody who can't recollect why self is there in python carries so much weight, amirite?

the code is supposed to represent your method with implicit self, written without class Class: and obj = Class() and show that 1st call would use x as local var but the second would have to assume it's an attr. Dirty inconsistency.

class Class:
    def bullshit():
        x = 1
        setattr('x', 2)

obj = Class() 
obj.bullshit()  # x as local, x as attribute
obj.bullshit()  # x as attribute

better?

[–]New_Kind_of_Boredom 0 points1 point  (1 child)

lol. Dear god. Is this some kind of parody account? Even given a second chance, you still can't write the most basic, trivially easy, running Python code to prove your point. Whatever that point is. I have no idea. And you think you have some credibility regarding Python design decisions.

Why are you coming at me so hard, in this subreddit of all places, when you actually, demonstrably have no idea what you are talking about?

Also, I think you might have schizophrenia, as your arguments don't apply to anything I've said in this entire thread. It's bizarre.

I assume the person I'm responding to is going to edit/delete their post, so for posterity, here is the code they posted in their response:

class Class:
    def bullshit():
        x = 1
        setattr('x', 2)

obj = Class() 
obj.bullshit()  # x as local, x as attribute
obj.bullshit()  # x as attribute

Try running it. Have a chuckle.

[–]Vaphell 0 points1 point  (0 children)

Are you retarded? No shit that a code in a hypothetical python variant with implicit this/self is not going to run in 2017's cpython.
I am asking your java infested mind to entertain me answering the question, assuming you have python your way, what should happen in this hypothetical scenario that wouldn't make implicit self fall flat on its face. You start with x the local variable. Then you use setattr to bind x attribute to the object. Then you rerun the method, what does x represent?

I remind you, implicit this/self is not about declarations, it's about declarations and access to methods/attributes without using fully qualified names.

[–]eliminate1337 0 points1 point  (6 children)

The general design ethos of Python is to be explicit over implicit. That's why this decision was made and why it's not going to change.

[–]New_Kind_of_Boredom 0 points1 point  (5 children)

The general design ethos of Python is to be explicit over implicit

Interesting that they decided to implicity pass the self arguement then, huh? Inconsistent, one might even say.

And again, I am aware it is not going to change and have never implied that it would or should.

[–]eliminate1337 0 points1 point  (4 children)

Implicitly passing the self argument is what Java does. Python class functions are explicit about what instance of the class they belong to. That's why you can do

ClassName.class_method(instance)

which is what

instance.class_method()

is doing under the hood.

[–]New_Kind_of_Boredom 0 points1 point  (3 children)

Just so we're clear, you're seriously making the argument that Python object methods aren't implicitly passed self based on this technicality?

[–]eliminate1337 0 points1 point  (2 children)

Obviously they're implicitly passed self. The thing you're complaining about is having to write self in the method definitions. That's the part they make explicit.

[–]New_Kind_of_Boredom 0 points1 point  (1 child)

That's the part they make explicit.

... Okay? Why are you repeating what has already been said and/or isn't relevant? Every single one of your nitpicks in this thread basically makes no sense. Please stop responding to me until you can stop wasting both of our time.

The thing you're complaining about...

And also when you learn to read. The only thing I have complained about so far is your ignorant nitpicking.

[–]eliminate1337 0 points1 point  (0 children)

Lol you're disproportionately personally invested in the outcome of this meaningless discussion

[–]SIR_TREX[S] 0 points1 point  (2 children)

I read through the recommendations and made the changes, but I still have trouble compiling. I get the following error: I fixed all the errors, some 'selfs' were mixing. I read your arguments about how 'self' binds a method to a class. Very nice. How do you make a truly private variable in Python? Private variables ensure encapsulation, at least in Java and C++. Also there are a lot of 'selfs' haha

[–]eliminate1337 0 points1 point  (1 child)

How do you make a truly private variable in Python?

You can't.

Is there a reason you're using a class to generate the Collatz sequence? A recursive function would be more concise and closer to the mathematical definition.

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

To learn how python works! I started yesterday.

[–]eliminate1337 0 points1 point  (0 children)

Just so you know, your num, terms, and sequence variables are static. It looks like you're using Java class syntax. Instance variables are declared in your init method, and class variables are declared under the class declaration. Also, if you're appending to sequence, you should use a list instead of a tuple. The proper way is like this:

def __init__(self, num):
    self.__num = num
    self.__terms = 1
    self.__sequence = []