4 ms·
Coming from C++ it feels really weird that you can simply assign instance.new_name = value from anywhere without properly declaring it beforehand. You also neve
by std_throwaway 8y ago
Coming from C++ it feels really weird that you can simply assign instance.new_name = value from anywhere without properly declaring it beforehand. You also never really know what you get or if somebody modified your instance members from the outside.
- gtaylor 8y agoIf you run a linter, the cases where you are doing this outside of __init__ will usually be pointed out. You can silence the warning/error on a case by case basis if you really need to do it.
- craigds 8y agoWhich linter does that? flake8 doesn't AFAIK.
- a_bored_husky 8y agoPylint does: http://pylint-messages.wikidot.com/messages:w0201 http://pylint-messages.wikidot.com/messages:w0201
- kstrauser 8y agopylint does.
- mixmastamyk 8y agoDoesn't happen maliciously in practice, also can be very handy when you need to attach a little extra data for the ride. If you need extra assurance there are techniques to make the instance "very" read-only.
- goatlover 8y agoJS & PHP let you do this as well. One advantage is that you don't have to adhere to a rigid class structure and be forced to refactor or create a new class every-time you need add a new property or method. And sometimes you want a property/method for just that particular instance, and not all members. As with most things, there are trade-offs.
- weberc2 8y ago> One advantage is that you don't have to adhere to a rigid class structure and be forced to refactor or create a new class every-time you need add a new property or method. I wouldn't qualify this as an advantage; it encourages bad code and it precludes a lot of good tooling (including tooling which would automate the sort of refactoring you'd like to avoid).
- goatlover 8y agoWell this sort of argument has been going on for several decades between the dynamic and static proponents.
- weberc2 8y agoThe gradual typing movement is a concession from the dynamic community that there is indeed value in formalism. BTW, I'm a professional Python developer.
- BerislavLopac 8y agoJust like introduction of generics and interfaces to static languages is a concession that there is value in "informalism" (if that's a word). Basically, there are values in both. There is no silver bullet, these are all different tools in our belt, and some work better in some situations and others in others -- hammers and screwdrivers. One thing I love about Python is that it allows a lot of different tools and methods, allowing you to select what works in a given situation. Many of those tools are far from perfect, but they get the job done in a very satisfying manner, more often than not.
- weberc2 8y ago> Just like introduction of generics and interfaces to static languages is a concession that there is value in "informalism" (if that's a word). You have it exactly backwards. Generics and interfaces are commitments to formalism and the promises of static typing. Before that there was ‘void’, the canonical dynamic type. ‘void’ (or ‘Object’ in Java and other static OOPs) became less common, not more. If there is value in dynamic types, I’ve scarcely seen it, (and I use Python every day). I’m told that dynamic typing really shines through Clojure and other lisps, but I haven’t gotten to that level yet. > One thing I love about Python is that it allows a lot of different tools and methods, allowing you to select what works in a given situation. Many of those tools are far from perfect, but they get the job done in a very satisfying manner, more often than not. This is a nice property when you want to play around with a new paradigm without learning a new syntax and toolchain, but when you’re working on a team, agreeing about the paradigm and features and style quickly becomes tedious.
- BerislavLopac 8y agoI can only imagine how weird it must seem that you can override methods of instance objects and even classes, or even replace a whole class of an instance with another. >>> class Foo: ... def bar(self): ... print('foo') ... >>> class Baz: ... def bar(self): ... print('baz') ... >>> f = Foo() >>> f <__main__.Foo object at 0x7fa311e7a278> >>> f.bar() foo >>> f.__class__ = Baz >>> f <__main__.Baz object at 0x7fa311e7a278> >>> f.bar() baz
- alkonaut 8y agoDoes that work even if the types had fields? What about it the fields had a different total size? What if Baz had no parameterless constructor (I.e only had a contractor that guaranteed arg > 0 for example)? Is this like an unsafe pointer cast where “you are responsible, and it will likely blow up spectacularly if you don’t know what you are doing” or is it something safer that will magically work e.g with types of different size?
- existencebox 8y agoInline: - Does that work even if the types had fields? Yup! - What about it the fields had a different total size? Totally fine! - What if Baz had no parameterless constructor (I.e only had a contractor that guaranteed arg > 0 for example)? Then you throw an exception when you call the constructor. - Is this like an unsafe pointer cast where “you are responsible, and it will likely blow up spectacularly if you don’t know what you are doing” or is it something safer that will magically work e.g with types of different size? Mostly the former, but if you're coming from a strongly typed compiled language, it may feel like a bit of the latter too, since if you don't run into any obvious runtime incompatibilities, it'll all "just seem to work" even if the underlying classes are 200% different. (Disclaimer, I've been using python for ~decade now but am still always nervous to speak authoritatively about it, since I work with peers who are FAR deeper in the actual implementation than I am, and I run the risk of being subtlety incorrect.)
- alkonaut 8y ago