8 ms·
Python 3 seems like a bit of a missed opportunity. Since they were introducing breaking changes in the first place, why didn't they go bigger? E.g. make the OOP
by erokar 7y ago
Python 3 seems like a bit of a missed opportunity. Since they were introducing breaking changes in the first place, why didn't they go bigger? E.g. make the OOP seem less tacked on, immutable data structures, clean up inconsistencies in the standard library?
- chungy 7y agoCan you describe how OOP feels tacked on? One of the major changes in Python 3 is that new-style classes are the only style of classes.
- CoolGuySteve 7y agoI myself, speaking for my self and only my self find that, in regards to myself, the redundant self keyword, in my self's opinion, is somewhat selfish and easy for my self to accidentally omit. Self.
- zabzonk 7y agoTo be pedantic "self" is not a keyword.
- WorldMaker 7y agoWorse than that not being a keyword, `self` isn't special at all, it's a naming convention that can be freely broken. Python codebases using `this` instead of `self` exist. Codebases that mix the two depending on who wrote which method in a class exist. I believe I saw `it` used once somewhere as the name for that parameter. I'm sure there are codebases with even crazier horrors for first argument names in class methods out there in the depths of corporate machines.
- timw4mail 7y agoMy experience with Python is a little lacking, but doesn't the self keyword mean the difference between an instance method, and a static method? Rust does the same thing - with self, it's an instance method, without, it's a static method.
- dfinninger 7y agoPython has an "@staticmethod" decorator you can put on a function inside of a class definition. Then you don't need to pass "self" as a first arg. https://www.geeksforgeeks.org/class-method-vs-static-method-python/ https://www.geeksforgeeks.org/class-method-vs-static-method-...
- int_19h 7y ago"self" is not a keyword in Python, just a convention. Any function inside a class declaration becomes an instance method, with its first argument becoming the explicit receiver. You have to use @staticmethod to prevent that (or @classmethod to get the class as the first argument, instead of the instance). Furthermore, this behavior is not parse-time, but runtime. The "def" statement that defines a function produces a plain function object, regardless of whether it's inside a class or not. Once the class finishes defining, the function is still a function - which is why C.f gives you a plain instance that can be called by passing "self" explicitly as an argument. However, Python allows objects to provide special behavior for themselves whenever they're retrieved via a member of some class - that is, when you write something like x.y, after y is retrieved from x, it gets the opportunity to peek at x, and substitute itself with something else. Function objects in Python (here I mean specifically the type of objects created with "def" and "lambda", not just any callable) use this feature to convert themselves to bound methods. So, when you say x.f, after retrieving f, f itself is asked if it wants to substitute something else in its place - and it returns a new callable object m, such that m(y) calls f(x, y). That's what makes x.f(y) work.
- enragedcacti 7y agoI personally really like the self keyword after spending some time reading code in Java where `this` is optional. Having to reference self makes it more clear where data is coming from and makes navigating an unfamiliar code base much easier. I'm a fan of forcing devs to acknowledge when they are accessing or manipulating mutable object state. Separate from that, I think that would be a much bigger breaking change than you think. __setattr__ and __setattribute__ means that self.y doesn't necessarily refer to a traditional attribute so without self you could end up with either: 1. `x = y` where the expression `y` executes code or 2. `x = y` where `x = ???` and `x = self.y` where `x = self.__setattr__('y')`. That said, I do think the language could use something to reduce the size of __init__() since self.arg1 = arg1 self.arg2 = arg2 self.arg3 = arg3 ... can get pretty verbose
- dfinninger 7y agoTo your last point, check out Dataclasses[1]. @dataclass class Foo: arg1: str arg2: int arg3: int = 5 # default value I use them a lot in my 3.7+ projects. It helps reduce the boilerplate for typical classes. (Where for me, typical classes are a 1:1 mapping of inputs to attributes) And if you need to compute some values at object initialization, then they have a __post_init__() hook you can use [2]. [1] https://docs.python.org/3/library/dataclasses.html https://docs.python.org/3/library/dataclasses.html [2] https://docs.python.org/3/library/dataclasses.html#post-init-processing https://docs.python.org/3/library/dataclasses.html#post-init...
- coldtea 7y ago>Having to reference self makes it more clear where data is coming from and makes navigating an unfamiliar code base much easier. I don't understand this. Aside from people seeing an OOP for the first time in their life, are they getting confused about where "this" comes from? How would an implicit "self" a la "this" make it any less understandable where the data come from? How is passing self making "navigating an unfamiliar code base much easier"? Aside from total newbs who see an OO codebase with an implicit instance variable for the first time?
- 7y ago
- btown 7y agoSelf lets you do really cool things though. For instance, you can monkey-patch with `def override_method(arg_that_will_get_self, *args): pass; Class.method = override_method` after Class is defined. Python lets you have all the dynamism of Ruby without letting you go too crazy with DSLs - which is the perfect balance IMO.
- dragonwriter 7y agoPython doesn't have a self keyword, redundant or otherwise. In fact, that's a key difference between Python and many other class-based OO languages. I'm not sure whether that (and the associated need to make the receiver an explicit parameter—conventionally, though this is not required, named “self” in instance methods—in method definitions) is your problem, or if your problem is that (unlike some, but fewer than the previous difference, OO languages) you can't omit explicitly naming receiver in references to its own instance variables in an instance methods, making instance variable reference syntactically distinct from local variable references.
- erokar 7y agoThe nuisance of having to add self as parameter to every class method, no way of enforcing private methods and the mix between methods on objects and functions in the standard library. OO feels more integrated in e.g. Ruby. About some of the design decisions in Guido's own words: http://python-history.blogspot.com/2009/02/adding-support-for-user-defined-classes.html http://python-history.blogspot.com/2009/02/adding-support-fo...
- viraptor 7y agoYou know that double underscore is basically making a method private, right? You can work around it to access the method anyway, but you can do that as well with Ruby.
- sweeneyrod 7y agoThe first two of those are explicit design decisions: "explicit is better than implicit" and "we're all consenting adults" respectively.
- erokar 7y agoMost things in a language are explicit design decisions. Doesn't automatically make them good decisions. Actually Python is one of my favorite programming languages, probably the language with the closest mapping to how I naturally think about a problem. I really like it. But I'm also willing to admit it has some warts, as does any language.
- ForHackernews 7y agoPython has warts, but IMHO it's weird to identify valid design choices, with pros and cons on each side, as "warts". If I were listing Python warts, I'd point to things like single-element tuples (1,), the `datetime` support (timezone-naive datetimes are an ambiguous disaster), or the cpython Global Interpreter Lock.
- mixmastamyk 7y ago
- dragonwriter 7y agoI think for some people having the receiver as an explicit parameter of methods rather than references through a special syntactic variable bothers some people and makes it look to them like a procedural language playing OO, though I personally think it's the most clear representation of what every class-based OO language actually does operationally, since methods are attached to a class and take a reference to the instance on which they are invoked.
- AnimalMuppet 7y agoIt may in fact be what every class-based OO language actually does operationally. But having the OO language do that for you is, to me, one of the lines that separates them from "a procedural language playing OO".
- dragonwriter 7y agoTo me, it makes sense for a class-based OO language with first-class functions and (unlike, e.g., Java) available direct external access to data members to do what Python does because it reinforces the distinction between function members and methods. Perhaps more importantly, it makes even more sense in a language like Python where classes are (unlike many, especially statically-typed, class-based OO languages) first class objects to do what Python does, because of the relation of methods to classes. It also, to me. makes unbound/bound methods slightly more intuitive. Now, I too was initially thrown by it because I'd used a bunch of OO languages that did it the other way first, and for quite a long time.
- int_19h 7y agoHow would you describe OO languages which only have multimethods, then? Say, Dylan?
- AnimalMuppet 7y agoDon't know enough to say.
- kzrdude 7y agoModern Python lacks coherent design: How do you define enums? with a superclass. How do you define data classes? With a class decorator. And then there's metaclasses too.
- joshuamorton 7y agoEnums are technically defined with a metaclass, as are abstract base classes and most other weird special classes (but in all cases you access the metaclass by subclassing something). Dataclasses are the one exception, and they do this for pragmatic reasons: multiple metaclasses are tricky. So a decorator allows the existence of an abstract dataclass, for example.