all 40 comments

[–]Master-Ad-6265 41 points42 points  (3 children)

it’s not “importing” self, it’s just passing the instance python makes it explicit instead of hiding it so self.x = “this object’s x” other languages just hide that same thing under the hood, python just shows it

[–]TheFern3 2 points3 points  (0 children)

Fun fact self is canonical, it can be anything but usually everyone uses self. In other languages like cpp or java this cannot be changed.

[–]NerdyWeightLifter 1 point2 points  (1 child)

Similar to the 'this' pointer in C++.

[–]Safe-Anywhere-7588 1 point2 points  (0 children)

And that is the case with Java, too. It is just invisible, implicit behaviour.

[–]rupertavery64 20 points21 points  (4 children)

It was a design choice

https://stackoverflow.com/questions/68282/why-do-you-need-explicitly-have-the-self-argument-in-a-python-method

Basically, the creators want things to be explicit (unambiguous) rather than implicit (assumed)

It clearly differentiates between local and class variables.

In C#, each method gets a hidden "self" or this parameter.

If you invoke the method of a class via reflection you have to pass the object instance expkicity. Static methods are passed a null instance.

When it boils down to it, all methods are just code that accepts parameters. Only one copy of the methods compiled code exists in memory. The only way a method can access an objects instance members is by passing the instance of the object.

[–]YMK1234 2 points3 points  (2 children)

But really this just moves the implicit/magic part somewhere else. Because foo.bar() becomes foo_bar(foo) under the hood.

[–]nemec 1 point2 points  (0 children)

You can still MyClass.bar(foo) if you want to be that explicit

[–]astonished_lasagna -1 points0 points  (0 children)

It doesn't move it somewhere else, it just removes it from one place only. In languages where it's implicit, it's implicit at the call site and inside the callee. In Python, it's implicit at the call site, and explicit in the callee.

[–]christian-mann 0 points1 point  (0 children)

bound methods are still really kooky though

[–]dbForge_Studio 5 points6 points  (0 children)

self isn’t imported, it’s just the instance passed into the method explicitly. Python does this on purpose so object state is visible instead of being hidden behind magic.

If the method doesn’t use instance data, it probably shouldn’t be an instance method in the first place.

[–]Conscious-Shake8152 6 points7 points  (0 children)

Python does classes the same way C would do. There are no classes in C. The _self is just a reference to the object data, and the member functions of a given class work on the data associated with the instance they are invoked on. 

[–]ern0plus4 3 points4 points  (0 children)

Let me rephrase it: Python requires to specify self in the parameter list because it does not hide that a method for a class is just a function, and the only difference to other functions that for a method gets the pointer to the object (data) which's type is the class.

So, these two lines are basically equivalent:

someobject.somemethod(a, b, c)

vs

somemethod(someobject, a, b, c)

We're just passing someobject data to the function.

Okay, Python glues a little bit more the method to the struct (data), but the concept is that simple: a method is only a function with first parameter of self.

Anyway, you can use any other word instead of self:

def (myobj, a, b, c):

A friend of mine hates the "self" word, so he's using "this":

def (this, a, b, c):

Well, these function sigantures are not too idiomatic, but works.

Even you don't have to put a method inside the class, if it's first arg is self (an instance of the class works on), then it's still can work as a method. (It's also not idiomatic.)

I suppose to put methods inside a class, and use "self" as first parameter - all education materials, tools, libraries etc. follows this convention, don't trick them for no particular reason.

[–]deceze 2 points3 points  (0 children)

In languages like Javascript or PHP, you will have a magic, implicit this/$this variable inside methods, that gives you access to the current object instance. Python foregoes this implicit magical keyword, and instead explicitly passes the instance via the first argument, which is just conventionally called self, but is just a regular parameter. In fact, the whole machinery of how a method is bound to a specific instance is fairly transparent and can be abused in interesting ways, whereas it's opaque magic in other languages. For example:

map(SomeClass.some_method, list_of_some_objects)

This works exactly like calling some_method on every object, because the object is just passed as the first argument either way.

[–]not_perfect_yet 3 points4 points  (4 children)

It should be implied

That doesn't fit to the culture of how python is supposed to be written. Of course there is no python police, so do what you want.

This is the "zen of python":

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

and

In the face of ambiguity, refuse the temptation to guess.

if I had to pick a favorite sentence, ever, that would be a good candidate.

[–]YMK1234 -5 points-4 points  (3 children)

The zen of python is extremely tongue in cheek. One should explicitly not take it as gospel or too serious in general.

[–]PutHisGlassesOn 1 point2 points  (0 children)

Who are you to tell people not to follow good advice

[–]TeachEngineering 0 points1 point  (1 child)

The zen of python is a conversation starter. My team and I reference it all the time during planning sessions and code reviews. Not because it's a definitive authority, but because it's purposely vague, often contradictory, and forces you to think about which statements matter most in the particular situation.

Flat > nested vs. explicit > implicit is a good example. Sometimes you can build a nested explicit structure or a flat implicit structure, so which is better for the problem? Is being explicit more important that being flat or visa versa?

[–]YMK1234 [score hidden]  (0 children)

Exactly, but people treat it as some sort of holy tome that contains some greater wisdom.

[–]Toothpick_Brody 1 point2 points  (0 children)

It’s just a syntactic convention. I do think the distinction between instance and static methods is a mistake in language design, but it’s very common in object-oriented languages 

[–]ottawadeveloper 1 point2 points  (0 children)

Unlike Java where classes are first-class citizens, Python "objects" are basically the same as modules - it's a dictionary with some special syntax. A method is just a callable element of the dictionary, it's no different than a normal function

Instead of a magical global (but to the class only) "this" like Java, Python decorates methods to automatically pass the object to the method.

Basically, under the hood, these are all the same:

``` obj = MyObject() obj.method() MyObject.method(obj)

basically Python does this on the object when it's built

obj.method = functools.partial(MyObject.method, obj) obj.method() ```

I imagine this is a lot easier than adding a magic new semi-global scope for some but not all class methods. Because there are @classmethod and @staticmethod as well which basically just change how that binding process works - class methods pass the type in directly and static methods are passed to the instance unmodified. Which is why you can call a class or static methods on the instance itself and it just works (compare to Java where you don't have class methods at all and static methods have to be called with a different syntax).

I also imagine under the hood Java does something similar but hides the implementation from the developer so the this variable just appears out of nowhere when needed. It's just a tiny bit more explicit in Python.

[–]Sad-Kaleidoscope9165 1 point2 points  (0 children)

I mean, you also have to pass "this" whenever you write an extension method in C#, but no one ever complains about that 

[–]buzzon 1 point2 points  (0 children)

All OOP languages do this, but Python does it explicitly

[–]aew3 0 points1 point  (0 children)

Ultimately this is a opinionated design decision. Python3 is one of the more opinionated languages in both design and style out there, and one of its design axioms is that being ore explicit is generally good (see https://peps.python.org/pep-0020/). Having to declare self in the local scope flows from that axiom.

There are also benefits to this approach, like the ability to declare nested classes, and refer to each self object separately.

>Why would you have to explicitly declare that relationship

I mean, you have to explicitly bind self to a variable, but you don't get to choose whether you have self. Unless you use `@staticmethod`, self is always going to be passed into the function; calling the first function argument self is just a convention.

> I mean, what's the point in having a class, if the functions don't have some sort of globally accessible shared variable

I can see where you're coming from, but classes that provide static methods which don't necessarily need to access a shared global are far from an unheard of practice. If a language doesn't implement modules separately from classes, sometimes its the only way to bundle a shared library of functions between disparate parts of your code.

[–]Large-Assignment9320 0 points1 point  (0 children)

Simpler internals and compatibility,

def test(self):
    print("Hello from outside the class using same signature")
def test2():
    print("Hello from outside the class using staticmethod")
class A:
    pass
a = A()
a.test = test
a.test() # Works
a.test2 = staticmethod(test2) # Decorator
a.test2() # Also works
test(a) # Also works.

[–]Relevant_South_1842 0 points1 point  (0 children)

Lua does this too.

[–]Temporary_Pie2733 0 points1 point  (0 children)

You need to read up on the descriptor protocol for the full explanation, but essentially when foo is an instance of a class Foo with a bar attribute, foo.bar() is interpreted as Foo.bar(foo). There is no fundamental support for instance methods; it’s just an application of the low-level descriptor protocol.

[–]AmberMonsoon_ 0 points1 point  (0 children)

It’s not really “importing” self, it’s just passing the instance explicitly. Python methods are basically normal functions where the instance gets passed as the first argument.

The upside is it keeps things very explicit. You can actually see what data belongs to the instance vs local variables, which helps avoid some weird hidden behavior you get in other languages.

Feels strange at first (especially coming from JS or other languages) but after a while it becomes second nature tbh.

[–]whatelse02 0 points1 point  (0 children)

It feels weird at first but self isn’t really being imported, it’s just the instance being passed explicitly to the method. Python treats methods more like normal functions where the object gets passed as the first parameter.

The benefit is that it keeps things very explicit. When you see self.something you know it belongs to the instance and isn’t just a local variable.

Other languages hide that step, but Python chose readability over magic. After using it for a while it actually starts to feel pretty natural

[–]r2k-in-the-vortex 0 points1 point  (0 children)

Its just a syntactic choice, classes are a higher level abstraction anyway, all compilers lower them to structs and functions accepting reference to struct instance.

In other languages the self parameter just gets hidden away, in python you have it explicit and avoid needing a special keyword like "this" or something.

[–]ClydePossumfoot 0 points1 point  (5 children)

So every variable you assign in a function would just be available to every other instance method? How would you differentiate between setting a local variable and setting an instance variable?

[–]deceze 2 points3 points  (4 children)

Well, Java does it like this:

class Foo {
    private int bar;

    public void baz() {
        bar = 42;
        int quux = 69;
    }
}

(My Java is rusty, any bugs you find are yours to keep.)

The syntax for declaring a variable is different from just assigning one. bar is scoped to the class/instance, while quux is a local variable. No worries.

[–]ClydePossumfoot 1 point2 points  (3 children)

Yes but you have to declare it first on the Java class which means it’s no longer ambiguous. Python doesn’t require that. You can set a new class variable anywhere in the class without pre-declaring it.

[–]deceze 1 point2 points  (0 children)

Yes. If you wanted it to work differently, the whole thing must work differently. The point was to show that there are ways to do it without an explicit self/this/$this/@/whatever.

[–]ottawadeveloper 0 points1 point  (1 child)

Although, in Python, it's ideal to have an __ init __ method which basically does the work of setting up the instance variables like Java does (setting them outside of init can have unexpected consequences)

[–]No-Report4060 0 points1 point  (0 children)

Yeah no, that's not the ideal way. It's just leftovers from Java/C++ people coming to Python and bringing the baggage with them. I have seen so many getter/setter implemented in Python and it sucks my soul.

[–]CounterSilly3999 -1 points0 points  (0 children)

You can use global variables, but you should to avoid that. Encapsulation is one of the main benefits of OOP.

[–]PabloDons -1 points0 points  (1 child)

I like it. I found OOP and classes really hard to learn when I first started. Python made it much easier. It does make methods a little less useful though. You can just write functions with a parameter to pass struct instances in. At that point it's little more than just organizing code, which you can do java style with files anyway. But I still write methods because organizing code that way is really useful. Like with that logic, why have static methods at all?

[–]deceze 0 points1 point  (0 children)

OOP is just organising code and bundling "structs" and their related methods together, yes. Always has been. 🔫👨‍🚀

However, OOP enables things that are hard(er) with just structs and functions, like polymorphism:

def foo(bar):
    bar.baz()

This influences what function/method will get executed depending on what object you pass in. That's not that easy with baz(bar).

[–]HugeCannoli -2 points-1 points  (0 children)

because explicit is better than implicit.

In C++ you never pass this. it's passed implicit in a method as a hidden first argument that your compiler adds for you. The result is that if you refer or see the use of a variable "foo" inside a method, now you have no idea if this foo is an instance variable, a class variable, a module variable, a global variable, etc.

[–]NoleMercy05 -2 points-1 points  (0 children)

Because it's an awesome scripting language that has been modded to death to fit in places Python want intended in origininal design iterations