I wrote something pretty fun today. I got sick of writing __repr__ for functions, so I made a decorator that does it for me!Python code:
|
|
# ? Mar 10, 2017 02:02 |
|
|
# ? May 15, 2024 04:34 |
|
Nice! Here's mine:Python code:
|
# ? Mar 10, 2017 02:39 |
That's the way I tried to do it at first, but it wasn't inherited properly through subclassing, which bugged me. You get the name (and signature) of the base decorated class. E.G: Python code:
Eela6 fucked around with this message at 04:35 on Mar 10, 2017 |
|
# ? Mar 10, 2017 04:31 |
|
Ah, I see. I tried to fix it by replacing cls with type(self) in __init__ and __repr__, but you can't get it to work with an overridden __init__ without using __new__. Nice solution. Edit: although, as long as proper subclass hygiene is used and the new init starts with a super().__init__ call, it should work. SurgicalOntologist fucked around with this message at 04:49 on Mar 10, 2017 |
# ? Mar 10, 2017 04:46 |
|
Dominoes posted:You're catching the TypeError before it occurs; ie once you've gotten thing.foo, you have no more error checking, and 10 doesn't have any keys. I figured that might be the reason. I guess the interpreter looks to see if I have a 'thing.foo' and it finds it and returns it, and for all purposes the try part has succeeded (well it technically did succeed)? Dominoes posted:@property makes methods look like properties; I think they're for writing Java-style code. I wouldn't use them, since they mask that calculations are being run. Oh okay. This made me reconsider about using properties to begin with. It just seems a bit weird that Python is "a consenting adults language" where nothing is private and everything can be accessed and used, yet @property exists to seemingly make things read-only. Dominoes posted:I'm not sure this is a good idea - you're trying to treat it as two different types of objects based on context. Here's a snippet that does what you ask, although as a function rather than a class. Thanks for the effort but that wasn't what I was trying to accomplish. I was thinking more on the lines of having a default answer/response with the option to transparently get a more detailed/specific answer. Like for example Belgium is also called België, Belgique, or Belgien depending on the language. These are official names that their government recognizes since they speak all of those languages listed, and not "unofficial" names that have been translated into other languages (like London and Londres for Spanish and some other languages). I don't see any harm or why it's a bad idea to be able to do this: code:
If it's not possible to do this then it's whatever, it's not a big deal. But making name a method isn't the answer I'm looking for. Boris Galerkin fucked around with this message at 08:38 on Mar 10, 2017 |
# ? Mar 10, 2017 08:36 |
Why not just have two attributes? country.name being the default, and country.name_in_lang being a dictionary that holds the other names? I think you're overthinking this.
|
|
# ? Mar 10, 2017 09:04 |
|
Boris Galerkin posted:Oh okay. This made me reconsider about using properties to begin with. It just seems a bit weird that Python is "a consenting adults language" where nothing is private and everything can be accessed and used, yet @property exists to seemingly make things read-only. You can make things read/write with properties, like @property, def whatever(self), @whatever.setter, def whatever(self, arg). But it's usually somewhat bad form to write something like that from the start. In most cases you would only do that for something that started out as a simple attribute and later needed to become more complicated without breaking user code (so seeing lots of @properties is often kind of symptom of something not being as well architected as it might have been). Boris Galerkin posted:I don't see any harm or why it's a bad idea to be able to do this: I'm skeptical you can really construct a good argument for why jumping through hoops writing possibly buggy code that's irrelevant to the end functionality to enable this weird polymorphic construction, the semantics of which are basically foreign to python, is a big improvement on just typing (). But if you have such an argument then lets hear it.
|
# ? Mar 10, 2017 09:04 |
|
Because you write code to do things for you, not the other way around. Here's my lovely jumping through the hoops example: https://repl.it/GP2U/0 code:
I can understand if this isn't something that exists in Python. I can understand that this isn't "pythonic." But I want to understand why it's a bad idea to do this? I mean ignore the fact that I defined Name inside the init or whatever. I have no idea what __repr__ does but from a quick search it seems to be the thing that gets called when I just type the name of the class. Typing "country.name_in_german" sounds like more of a hoop, and honestly making it a method and having to call "country.name()" is just ugly when 99% of the times I just need the default value. Plus the () implies function so isn't it semantically wrong? I'm not computing anything, I'm just getting something that already exists. e: nevermind this only half works. __repr__ returns an actual Name object so I can't do things like "country.name+country.name['de']". Sad. Boris Galerkin fucked around with this message at 09:23 on Mar 10, 2017 |
# ? Mar 10, 2017 09:15 |
|
code:
On the other hand, what you want to do is actually easy for trivial usage, so here is a way to implement this very, very, very bad localization mechanism (that probably still has some problems but it doesn't matter because you shouldn't do it anyway): code:
breaks fucked around with this message at 11:16 on Mar 10, 2017 |
# ? Mar 10, 2017 10:37 |
|
Boris Galerkin posted:e: nevermind this only half works. __repr__ returns an actual Name object so I can't do things like "country.name+country.name['de']". Sad. __repr__ only gets called to turn your object into a string, so "country.name+country.name['de']" doesn't call __repr__ at all. This is also the essence of why what you want is a bad idea. What type of thing is "country.name"? It can't be a string, because you can't index a string with ['de'], but it needs to behave like a string almost all the time. This means that it needs to be some kind of nearly-a-string object that behaves like the string "Belgium" except in some very special circumstances, and making an object like that will surprise people. That's what you've built with Name, except __repr__ only covers behaving like a string when you print it, and not when do other string things like concatenating or slicing. If you want to do something like this in a simple and not-surprising way then use a function. It's not semantically wrong for it to be a function because it's a thing that behaves differently depending on what arguments you pass it. If you're really upset about typing country.name() instead of country.name you can do this: code:
|
# ? Mar 10, 2017 10:57 |
|
Boris Galerkin posted:Because you write code to do things for you, not the other way around. Here's my lovely jumping through the hoops example: What you're asking for is for .name to sometimes be a function call if you provide an argument, or a string if you don't call it like a function. That's only going to make your code obtuse and difficult to understand. The code that breaks wrote in the first part of his post looks great and does what you want, but you have to type () when you want to get the default name, which is fine
|
# ? Mar 10, 2017 11:07 |
|
Why don't you just use a localization library like Babel?
|
# ? Mar 10, 2017 14:00 |
|
Because it was just an example. e: And also because I come from a procedural/imperative programming background (my first language was Fortran back when it was still FORTRAN [77]) and I've never learned anything else other than modern versions of Fortran and MATLAB so honestly I have no clue what the point of objects are or when and why I should use them. I just think it's pretty neat to be able to do: code:
Instead of code:
But honestly the only reason I think the first one is neat is because it looks better to me. I really wasn't joking when I said I liked "foo.thing" better than "foo.thing()" because it looks better without the parenthesis (but mostly because I don't think it's semantically correct to call a function to return a value that I've already computed). Boris Galerkin fucked around with this message at 17:49 on Mar 10, 2017 |
# ? Mar 10, 2017 17:35 |
|
Boris Galerkin posted:(but mostly because I don't think it's semantically correct to call a function to return a value that I've already computed). This is a pretty weird thing to think.
|
# ? Mar 10, 2017 19:38 |
|
My first Flask application is almost done. Hopefully one last question. I've setup Flask-Admin and it works well by routing all traffic (even non logged in users) from /admin to the admin panel. However, /admin is not a route in my views.py file. I thought I could just do something like:code:
|
# ? Mar 10, 2017 20:03 |
|
Flask admin views have the is_accessible and inacessible_callback methods to control who it lets access and how it should behave when an unauthorized user tries to access their pages. For example: Python code:
|
# ? Mar 10, 2017 20:14 |
|
Not to pick at an old scab or anything but in the old thread there was a bit of back-and-forth over _ as a "discard me" variable name and whether or not that was better than something more explicit. So, although it's not Python, it's worth noting that C# 7 specifically outlines _ as a "discard" variable with their new use-case for out variables (the very end of the "Out Variables" section). I thought that was interesting.
|
# ? Mar 10, 2017 21:14 |
Boris Galerkin posted:Because it was just an example. I too came from MATLAB, where you can call a zero-argument function without the parentheses. The reason why you can't (well, shouldn't) in python is because Python has functions as first class objects. That means you can put functions into containers, have functions with extra attributes (that could be functions themselves), all sorts of weird stuff. This is powerful, but it means you need a way to refer to the function itself as an object. When you use the parentheses you are referring to the action of the function. When you don't use the parentheses you refer to the function itself. This is a crucial distinction! Here's an example that might help. IN: Python code:
code:
Other languages do not have this philosophy. I am of the opinion it is one of the best things about Python, but you may disagree. That's OK; just be warned the majority of the community will not be on your side. The Zen Of Python posted:Explicit is better than implicit. Eela6 fucked around with this message at 22:00 on Mar 10, 2017 |
|
# ? Mar 10, 2017 21:48 |
|
Boris Galerkin posted:Because it was just an example. Your points on the first codeblock are very good, and indeed that does look better and work better and it makes sense. But then consider this: code:
code:
quote:(but mostly because I don't think it's semantically correct to call a function to return a value that I've already computed) That's called a get method, those are common in object-oriented languages but in Python you don't have to use them.
|
# ? Mar 11, 2017 04:11 |
|
Boris Galerkin posted:(but mostly because I don't think it's semantically correct to call a function to return a value that I've already computed). There are plenty of examples of situations where "calling a function to return a value already computed" is normal and accepted*, so I think you're going to have to accept that this viewpoint is highly idiosyncratic. Coming up with an attribute of your object that behaves in some cases like a function and in other cases like the return value of the same function is pretty far from idiomatic, so you're going to have to accept that if you do that, just about anyone who needs to read or understand your code is going to have trouble doing so. That's slightly dependent on the language background of the individual but I think it would apply for most languages in common use. If I see ob.f() in one place and then ob.f somewhere else, I'm naturally going to think that the use of ob.f is to refer to the method itself (as Eela6 says) rather than to invoke it; I'll then be surprised to learn that's not what's happening. You should not in general see invocation of functions as an expense. * Aside from concepts like getter methods, consider the case of an object with an attribute that's time-consuming to calculate. In this case, it wouldn't be unusual to cache the latest calculated value for the attribute and also have a flag variable that indicates whether the stored value is stale. You then would add a method to allow the user of the object to fetch the value of the attribute. If the "stale" flag is set then the attribute is computed and then the computed value is stored and returned; if it's not, then the stored value is returned as-is.
|
# ? Mar 11, 2017 16:29 |
|
Boris Galerkin posted:so honestly I have no clue what the point of objects are or when and why I should use them. The point of an object is to package up the knowledge and responsibilities of parts of your program into little packages that are easy for human beings to understand and reason about. If you were programming a first-person shooter game*, you might have a "player" object, "enemy" objects, "projectile" objects and so forth. Then instead of keeping track of enemies' health in some array of health values or something, you can access an individual enemy's health through that enemy object. If the enemy takes damage, you call a method enemy.take_damage(amount), which would take care of things like checking whether the enemy is now dead, whether it should change its behaviour now that it has less health, and so on. A lot of the benefits of this are already realised through the use of functions, which is an even more fundamental way to make programs easier to understand, but there are additional benefits that come from strongly associating data (the enemy's health) with the code that needs to care about it (the method take_damage()). A lot of usages of classes are more abstract than that, but the key idea is always making it easier for people to reason about your code and dividing up the responsibilities of your program. * not that I would choose to try to do that in Python, mind you.
|
# ? Mar 11, 2017 16:40 |
|
Boris Galerkin posted:Because it was just an example. I agree that property accesses are more "pleasant" to type and look at than function calls. Anyway, do you ever split your code into different files for reasons other than language-mandated reasons? The general reason you'd do that is one of the general reasons you'd use objects. Of course, OOP is full of stupid ideas as well. It's a good idea to become familiar with different paradigms like OOP, functional, etc so you don't end up just using what you know and missing out on better ways to solve problems. You talking about your background makes me think you might like learning Elm, as it's completely different from what you'res used to for completely different purposes, and it'll really expand your mind about what you can do with Python as you can implement a lot of the same functional ideas in Python.
|
# ? Mar 11, 2017 17:36 |
Elm is a neat language! I'm not sure if I love it but there are a lot of interesting ideas there.
|
|
# ? Mar 11, 2017 18:03 |
|
I'm an utter neophyte, not just with python, but with programming in general so please bear with me. I'm working through a beginner-oriented book and he's going through lists and sorting. At first he shows how to display a list in reverse order:code:
code:
code:
|
# ? Mar 12, 2017 02:54 |
|
You need to tell sorted what it's sorting. In your last example, how does it know it's supposed to be sorting the list of cars? You should probably also get used to looking up the documentation for functions you are using. Even if you don't understand everything its a good habit to get into because because a lot of these types of questions have answers that live in the documentation.
|
# ? Mar 12, 2017 02:59 |
Whenever you call a function, it does some action, then returns an object. The function sorted() takes an iterable* and returns a sorted list of the contents. This is a new list; not the old one. list.sort(), on the other hand, is a method of a list (a special kind of function, attached to an object), that sorts it without making a new copy. To remind programmers of the difference, it returns None. Try this code:
*An iterable is an abstraction of anything that can give you a 'flow' of objects, one at a time. Tuples, lists, sets, and dictionaries are all iterable. For now, all you need to know is anything that supports code:
|
|
# ? Mar 12, 2017 04:14 |
|
There's two subtly different things going on there that you probably haven't noticed Different types of object have different functions you can invoke on an instance of that object, called methods. It's like a button you can press on an object you created. So in your first example, you create a list object and then call that list's sort() method by using the dot notation - cars.sort(). You're explicitly acting on the cars list by pushing its button In your second version you're using a standalone function called sorted(), which works sort of like a service - it does something useful, but you have to give it the object it's going to work with. Which makes sense - what are you sorting? You need to provide a list object as a parameter so it can do its thing, like sorted(cars). Your broken version didn't do that, so you weren't actually telling it what to sort Without complicating stuff talking about self, those are the two different ways you'll work with objects - either calling methods on the object or passing them into a function, so get used to seeing it! Knowing that lists have a sort() method that reorders your list elements in-place, or that the sorted() function takes a list and spits out a new list without changing the original one, those require familiarity by reading the documentation. So like someone said, get used to looking stuff up to see how it works - it'll also tell you what the required and optional parameters are so you can see what's possible. Definitely get familiar with Python's basic types and all the stuff you can do with them, refer to the docs often! Here's a bunch of built-in functions - these are the things where you need to pass in any objects the function will be working with e- beaten by my own lost post bug baka kaba fucked around with this message at 04:58 on Mar 12, 2017 |
# ? Mar 12, 2017 04:50 |
|
I was at an interview and one guy kept grilling on me for saying that I would use celery as a backend for a restful flask service that needed queueing bits, because celery drops tasks stochastically. Any ideas where he got that from, or any links like that? A cursory google doesn't help I found a 2-year-old HN dealie with the comments stomping on the project generally, are those complaints still true nowadays? edit: lol more stomping 3 years ago lols curufinor fucked around with this message at 06:09 on Mar 12, 2017 |
# ? Mar 12, 2017 05:56 |
|
Thanks very much, guys! This is good stuff to work with.
|
# ? Mar 12, 2017 05:57 |
|
QuarkJets posted:Your points on the first codeblock are very good, and indeed that does look better and work better and it makes sense. But then consider this: For reasons that I can't seem to articulate, this example doesn't make sense to me as something I would do. In my mind it's pretty clear that "rotate" is a function that does the rotation. It's a function, so I would be 100% fine with calling it like a function, eg old_tensor.rotate(). code:
Thermopyle posted:Anyway, do you ever split your code into different files for reasons other than language-mandated reasons? The general reason you'd do that is one of the general reasons you'd use objects. Yep of course. I split my code/functions into separate files/modules in a way that makes sense (e.g., functions that act on tensors go in tensors.py). I'm just having a hard time seeing the practical difference between these two though: code:
code:
quote:You talking about your background makes me think you might like learning Elm, as it's completely different from what you'res used to for completely different purposes, and it'll really expand your mind about what you can do with Python as you can implement a lot of the same functional ideas in Python. Neat, I'll check it out. e: quote:Of course, OOP is full of stupid ideas as well. It's a good idea to become familiar with different paradigms like OOP, functional, etc so you don't end up just using what you know and missing out on better ways to solve problems. Yep this is what I'm trying to do as well. I'm not making any claims about one way being better or whatever. I'm just drawing from experience: this is how I learned to do things, this is how I've always done things. I had to pick up Python to work on a project, and I'm honestly trying my best to learn how to do things "properly" with Python instead of trying to shoehorn in how I'd do things with C. So basically all of my questions are probably a mixture of "how do I do this in Python" and "why do I need to do it like this in OOP". I try to keep the OOP specific things out of here though. Boris Galerkin fucked around with this message at 12:37 on Mar 12, 2017 |
# ? Mar 12, 2017 12:29 |
|
Boris Galerkin posted:
Yup, they both do the same thing and the decision to use one implementation vs the other is going to come down to some combination of personal preference, conforming to some preexisting style guide, and specific project details (for instance if you're writing high-performance computing code then a functional form is often better, since it's easier to port that to C/Fortran or to compile it with Numba, but if you're interacting with Java for some god-awful reason then Java is classes-only)
|
# ? Mar 12, 2017 12:38 |
|
Boris Galerkin posted:For reasons that I can't seem to articulate, this example doesn't make sense to me as something I would do. In my mind it's pretty clear that "rotate" is a function that does the rotation. It's a function, so I would be 100% fine with calling it like a function, eg old_tensor.rotate(). I might be missing something, but are these meant to return the same value? Or do multiple calls to rotate() stack additional rotations, and the .rotated property just returns the last calculated one (meaning you're keeping internal state about how many rotations have been applied)? If you're not maintaining state, and you just want that extra property to avoid recalculating the rotated version of the tensor every time you want to access it, you can just have one method and lazily calculate it - have a result variable (initially set to None), and when you call rotate(), check if the result is empty and calculate it if necessary, then return it. Just a single method, no need to worry about whether it's already been called or not, and you can change the implementation in the class (like calculating rotations in init or allowing optional rotation matrix parameters in the rotate() call, with multiple cached values) without the callers needing to care. Newer pythons give you a free LRU cache decorator if you want instant no-worries memoization of results. This is one of the things OOP gives you, you can encapsulate state and behaviour and wall it off behind the interface - so long as the interface stays consistent, nothing outside of the class needs to know anything about how it works. You can treat it as a black box
|
# ? Mar 12, 2017 13:58 |
|
Boris Galerkin posted:Yep of course. I split my code/functions into separate files/modules in a way that makes sense (e.g., functions that act on tensors go in tensors.py). I'm just having a hard time seeing the practical difference between these two though: You'll often see classes used in python to lump logically-related code together, so in just that sense you can see them as another unit of subdivision. You have packages (directories with a __init__.py) file, modules (.py files), and classes, all that help you organize code. That being said, classes are more than just a way to group logically-related code together. It's hard to describe a slam-dunk case for objects because everything you can do with objects you can do with functions. Objects are for helping you reason about your code, they don't make your code able to do new things. I think the best you can do is understand how objects work and be aware of them. Try to use them even when you don't think you need them. It'll help you get a feel for them so that when you do encounter problems that would benefit from an OOP approach, you'll know to use them. There's a not-entirely-unjustified school of thought in python-land that too many developers pull out classes unnecessarily.
|
# ? Mar 12, 2017 18:23 |
Thermopyle posted:There's a not-entirely-unjustified school of thought in python-land that too many developers pull out classes unnecessarily. I am of this opinion. This is a good video on the subject: [video type=""]https://m.youtube.com/watch?v=o9pEzgHorH0[/video] Classes are useful when they make your code easier to reason about. Too many classes are often a signal of code without forethought.
|
|
# ? Mar 12, 2017 20:44 |
|
I tried writing a hella OOP version of a thing in python like I might in javaish C#, and it took me far too long to realize that I was typing out the same stuff over and over again when none of it is enforced or anything; might as well just use them for the constructors. Python's OOP seems more useful when you do something like rust's traits with it.
|
# ? Mar 12, 2017 21:07 |
|
Objects are nice if you're defining something that can be thought of as a datatype, or if you're using a collection of similar items.
|
# ? Mar 12, 2017 21:09 |
|
This code code:
code:
|
# ? Mar 12, 2017 21:21 |
|
huhu posted:This code Check the documentation for python 3's exec(): https://docs.python.org/3/library/functions.html#exec "This function supports dynamic execution of Python code. object must be either a string or a code object. If it is a string, the string is parsed as a suite of Python statements which is then executed (unless a syntax error occurs)." So the problem is that you're passing the string "/home/huhu/.virtualenvs/wv_venv/bin/activate_this.py'" to the exec() function, which is just a path and not really python code, hence the syntax error.
|
# ? Mar 12, 2017 21:54 |
Dominoes posted:Objects are nice if you're defining something that can be thought of as a datatype, or if you're using a collection of similar items. I prefer to use namedtuples for this personally. E: which, I suppose, is actually a class, but people tend to treat them differently in their mental model of how things work.
|
|
# ? Mar 13, 2017 00:03 |
|
|
# ? May 15, 2024 04:34 |
|
namedtuple unless it's mutable, or would benefit from methods.
|
# ? Mar 13, 2017 00:05 |