|
haruspicy posted:Whoever in here said that they didn’t really get Python until reading Fluent Python goddamn is that ever true, just picked it up Well that's a hell of an endorsement, gonna pick it up.
|
# ? Apr 11, 2023 05:48 |
|
|
# ? May 15, 2024 01:55 |
|
I've been banging my head against the wall here for a while... I'm trying to look through some stock market minute data. The data I have includes extended hours, and I want to get only minutes where the market is open. There's a module pandas_market_calendars that provides a function, I'm currently trying to get it set up like so:Python code:
Also, dealing with timestamps/time zones is one of the most infuriating programming things I've encountered probably ever. e: Figured it out... sort of. The calendar schedule class was rejecting the first few timestamps with ValueError because the min time in the schedule is actually the first open time on the date given as min in the schedule creation, and the minimum in the aapl data was pre-market. So even though giving `histidx.min()` should have - in my mind - set the schedule to include the pre-market times, the schedule did not include them. This was raising a ValueError though, not a TypeError. Changing the market_open_fn code to this worked: Python code:
Colonel Taint fucked around with this message at 16:57 on Apr 11, 2023 |
# ? Apr 11, 2023 14:16 |
|
I'll also give Fluent Python a great endorsement. I read it when I was a late beginner and felt like it made me an intermediate just by how it connected so many dots. It was something I referenced often and still would if I were doing python full time. If anyone knows the same type of book for JS/TS I'm all ears!
|
# ? Apr 11, 2023 16:52 |
|
If you want .apply() to act on every row in that series you’ll need to do .apply(…, axis=1).
|
# ? Apr 11, 2023 17:30 |
|
DoctorTristan posted:If you want .apply() to act on every row in that series you’ll need to do .apply(…, axis=1). The apply is running on a series, not a dataframe. Still have no idea about the original error, but I was able to get it down to about half a second while using no apply: Python code:
I think I'm pretty happy with this as the general form though. Half a second still seems like kind of a lot, but it's good enough for my use/massive improvement from 2 minutes. I don't see a way to do it without a loop or apply.
|
# ? Apr 11, 2023 20:35 |
|
a dingus posted:I'll also give Fluent Python a great endorsement. I read it when I was a late beginner and felt like it made me an intermediate just by how it connected so many dots. It was something I referenced often and still would if I were doing python full time. https://github.com/getify/You-Dont-Know-JS Not the same but a maybe interesting book about JS.
|
# ? Apr 11, 2023 23:32 |
|
Apply is a low performance method, it's essentially the same as writing a big for loop. Vectorization is going to work a lot better, that's basically what you get with loc iirc
|
# ? Apr 12, 2023 01:15 |
|
FISHMANPET posted:I'm writing a Python module, and I've gotten myself stuck into some circular dependencies. I've found some "basic" stuff about fixing that, but I seem to have gotten myself into a deeper pickle. Basically, I have a User class, and that User class has methods that will return a Group. And I have a Group class that has methods that will return a User. And I'm trying to define these in separate files, otherwise this is gonna be some massive 2000 line single-file module. I've finally just "thrown in the towel" so to speak and stopped importing at the top of the file, and instead am importing only when a function is called, but that doesn't feel great either. It mostly doesn't fall apart because duck typing avoids most of the times types need to refer to each other. Type hints have increasingly less bad hacks bolted on to work around it as Python versions increase For the rest of the situations, local imports like you're doing are the typical workaround. You shouldn't muck up your design to accommodate Python weirdness (unless the design actually has something wrong with it)
|
# ? Apr 12, 2023 02:55 |
|
haruspicy posted:Whoever in here said that they didn’t really get Python until reading Fluent Python goddamn is that ever true, just picked it up
|
# ? Apr 13, 2023 23:02 |
|
FISHMANPET posted:I'm writing a Python module, and I've gotten myself stuck into some circular dependencies. I've found some "basic" stuff about fixing that, but I seem to have gotten myself into a deeper pickle. Basically, I have a User class, and that User class has methods that will return a Group. And I have a Group class that has methods that will return a User. And I'm trying to define these in separate files, otherwise this is gonna be some massive 2000 line single-file module. I've finally just "thrown in the towel" so to speak and stopped importing at the top of the file, and instead am importing only when a function is called, but that doesn't feel great either. Foxfire_ posted:For the rest of the situations, local imports like you're doing are the typical workaround. I usually do the local import like Foxfire_ suggests, especially if they can be constrained to a single method that 'converts' between the two types. The other option is, instead of having group.py 'from user import User', just do 'import user' and then refer to user.User when it's needed. That way you're not referencing any module members at the top level and avoid the circular import problem.
|
# ? Apr 14, 2023 15:33 |
|
I still don't understand why a User class would have to have methods that return a Group, so until then:QuarkJets posted:You need to clean up this data model. If a Group contains Users, then a User does not need to call Group methods. Code that needs to interact with Group and User simultaneously (for instance, "given a User belonging to some Group, call a Group method") goes into a third module that imports from users and groups.
|
# ? Apr 14, 2023 15:50 |
|
Zoracle Zed posted:I usually do the local import like Foxfire_ suggests, especially if they can be constrained to a single method that 'converts' between the two types. The other option is, instead of having group.py 'from user import User', just do 'import user' and then refer to user.User when it's needed. That way you're not referencing any module members at the top level and avoid the circular import problem. Using locally-scoped imports sweeps the problem under the rug, you should use top-level imports and structure your import hierarchy to avoid circular imports
|
# ? Apr 14, 2023 16:13 |
|
Sometimes there are legitimate reasons to model your data that way. Don't contort your data into some totally bullshit shape just to avoid a circular import. That said, this particular shape (Groups and Users, where Groups contain Users and a User can be in many Groups) probably shouldn't be modelled that way. One pretty good way to do it would be to have Groups containing Users, and then a third component that supports looking up all the Groups for a particular User.
|
# ? Apr 14, 2023 16:44 |
|
A simple tree hierarchy is never a "totally bullshit" shape, whereas a circular hierarchy often is
|
# ? Apr 14, 2023 21:19 |
|
A User object has a get_groups() method that will return all the Groups the User is a member of. A Group has a get_members() method that will return all Users of the Group. So a User object has no Group property, and a Group has no User property, but they each have methods that will call the constructor for the opposite object. I've gotten things pretty well cleaned up with a combination of doing local imports and importing TYPE_CHECKING to enable my type annotations without needing full imports at the root of the file.
|
# ? Apr 14, 2023 21:55 |
|
QuarkJets posted:A simple tree hierarchy is never a "totally bullshit" shape, whereas a circular hierarchy often is If your data is modelled as a tree, being able to step from a child to its direct parent is incredibly useful, but requires a circular reference.
|
# ? Apr 15, 2023 00:19 |
|
FISHMANPET posted:A User object has a get_groups() method that will return all the Groups the User is a member of. Do Users need to know what Groups they are a member of? If not, get_groups can take a User argument and go into a third container-of-Groups class (which it seems like you'll need or want anyway). FISHMANPET posted:... they each have methods that will call the constructor for the opposite object. Do you really need a User to be able to construct a Group? And if so, can't you do it with, for example, a @classmethod constructor in Group? Not to harp on this if you have specific needs to do it circularly, but: Jabor posted:If your data is modelled as a tree, being able to step from a child to its direct parent is incredibly useful, but requires a circular reference. FISHMANPET appears to be describing an N:N relationship, where I can see there might be some convenience in having two-way links but if there's a need to do things to Users depending on what Groups they're in, the logic should probably go in the appropriate Group (or third) class rather than in the User class.
|
# ? Apr 15, 2023 01:04 |
|
Jabor posted:If your data is modelled as a tree, being able to step from a child to its direct parent is incredibly useful, but requires a circular reference. I don't think that's true - for instance the Qt data model permits directly stepping to a parent (via a parent property that basically all Qt classes have), but the codebase doesn't tend to have circular references. In C++ this requires a generic class that all classes with parentage inherit from (in Qt that class is QObject), in Python you can either define a similar class that manages parent/child linkage or just not use type annotations and allow parent to be dynamically typed
|
# ? Apr 15, 2023 01:35 |
|
QuarkJets posted:I don't think that's true - for instance the Qt data model permits directly stepping to a parent (via a parent property that basically all Qt classes have), but the codebase doesn't tend to have circular references. In C++ this requires a generic class that all classes with parentage inherit from (in Qt that class is QObject), in Python you can either define a similar class that manages parent/child linkage or just not use type annotations and allow parent to be dynamically typed Both of those are worse than just having the circular reference.
|
# ? Apr 15, 2023 01:50 |
|
Jabor posted:Both of those are worse than just having the circular reference. If a User can belong to multiple Groups then the only type annotation that you need is probably `list` anyway - User doesn't need to see any Group code at all
|
# ? Apr 15, 2023 06:41 |
|
For various reasons well ok, job interview, I need to start learning about data structures and algorithms and all that outer-space leetcode stuff. Any recommendations on where to start? Mind you, I suppose that's more of a "computer science" question than a "python" question, but I'll eventually have to implement this stuff in python anyways so eh.
|
# ? Apr 15, 2023 06:48 |
|
QuarkJets posted:If a User can belong to multiple Groups then the only type annotation that you need is probably `list` anyway - User doesn't need to see any Group code at all what? you'd still want it as list[Group].
|
# ? Apr 15, 2023 19:42 |
|
Zoracle Zed posted:what? you'd still want it as list[Group]. Nah that's unnecessary and making the code structure worse
|
# ? Apr 15, 2023 20:01 |
|
Seventh Arrow posted:For various reasons well ok, job interview, I need to start learning about data structures and algorithms and all that outer-space leetcode stuff. Any recommendations on where to start? Well you already mentioned leetcode. Cracking the Coding Interview is also often recommended.
|
# ? Apr 15, 2023 20:27 |
|
Thank you, but I guess what I meant was any resources where I can learn the underlying concepts behind data structures and algorithms. I don't want to blindly hack away at leetcode problems. Granted, googling solutions to leetcode problems might help me gather a knowledge base about these kinds of concepts, but I was hoping for something more structured. I actually might hire a tutor on fiverr, so I will think about this a bit further.
|
# ? Apr 15, 2023 20:45 |
|
QuarkJets posted:Nah that's unnecessary and making the code structure worse Wait, expand on this: Type hinting is making the code worse? Because this was explicitly the example I was thinking of when reading earlier. Like sure, you can just not have it hinted and have a docstring or something saying 'oh this returns a List of Groups' but I find this kind of a strongly odd statement to make. I think it's totally fair to say that like, you shouldn't have deeply connected circular code, but if what we're talking about is basically just type hinting for parent/child/etc that's pretty reasonable IMO.
|
# ? Apr 15, 2023 21:44 |
|
Falcon2001 posted:Wait, expand on this: Type hinting is making the code worse? Not the type hinting specifically; in this example User and Group are in separate files, and Group already imports from user.py, so having User import from group.py introduces a circular dependency. That makes the code structure worse. If they were in the same file then this'd be okay but not great, because it'd be somewhat brittle e: You can use the special TYPE_CHECKING variable so that the circular import only exists while typechecking, but that makes the code kind of ugly imo QuarkJets fucked around with this message at 22:16 on Apr 15, 2023 |
# ? Apr 15, 2023 22:04 |
|
Can you define what "brittle" means to you and why you think it's bad? It's totally okay to have a "package" of closely-related files that depend on each other. You shouldn't feel like you need to combine them all into a single file just because you think mutual dependencies feel icky.
|
# ? Apr 16, 2023 01:39 |
|
Jabor posted:Can you define what "brittle" means to you and why you think it's bad? It means that the code is not resilient. Brittle code is easier to accidentally break when you're later trying to maintain it or add features to it. Circular dependencies are a known anti-pattern in software design because they create brittle code and should be avoided. You don't have to take my word for it, either; Google's style guide describes circular imports for the sake of type-checking as a code smell and using locally-scoped imports for the sake of permitting a circular dependency creates a PEP8 violation.
|
# ? Apr 16, 2023 04:30 |
|
Can you give an example of how having the return value properly typed as a List[Group] instead of a List[Any] makes your code "easier to accidentally break when you're later trying to maintain it"?
|
# ? Apr 16, 2023 06:39 |
|
Jabor posted:Can you give an example of how having the return value properly typed as a List[Group] instead of a List[Any] makes your code "easier to accidentally break when you're later trying to maintain it"? The typehinting is not a problem, the circular import is. The OP has already demonstrated one issue that it can cause, the code raises an exception when you implement the imports in one way but not in another. Now the code has been modified around preserving this circular hierarchy, throwing away PEP8 while creating code that sounds pretty brittle to me: FISHMANPET posted:A User object has a get_groups() method that will return all the Groups the User is a member of. A Group has a get_members() method that will return all Users of the Group. So a User object has no Group property, and a Group has no User property, but they each have methods that will call the constructor for the opposite object.
|
# ? Apr 16, 2023 08:09 |
|
just to clarify, since this is also something i've been scratching my head over but never had time/energy to research properly because i am a bad developer, but: you're saying a better implementation would be something like: Python code:
Python code:
|
# ? Apr 16, 2023 11:51 |
|
In my opinion, typing list instead of List[Group] just to avoid the circular import is probably the worst possible solution. If you believe the circular relationship is a smell (which I'm on the fence about), well that hasn't been addressed, and you've basically given up on having your code well-typed. I find the recommendation to do that or List[Any] baffling, even if it comes from Google. What I might do is something like this. Python code:
On the other hand, I'm partial to the argument that this is just a workaround and there's nothing wrong with the circular dependency (other than the fact that it's not allowed). Probably the actual best approach in these situations is to put them in the same file. And if the response is "that file would be too big!" then for sure the classes are too big and should be split. Maybe user.py and group.py is not actually the best way to split the logic into modules/classes. Especially with Protocols you can split different aspects of your objects' behaviors among classes rather than having big monster classes. So, my response when a colleague asks for help with a circular dependency problem is almost always "make your classes small enough that you are comfortable putting them together". If they are so tightly coupled, it makes sense that they be in the same module. Edit: I think the answer to my above question about typing the classmethod output is something like Python code:
Oh wait, that just abstracts the User part, not the Group part. Well, maybe useful, but I'm still not sure how to enforce that a subclass's get_groups_by_item can only return a list of itself rather than of a parent class. Edit2: Ok I googled it, the answer is to use typing on cls. Getting complicated but maybe... Python code:
SurgicalOntologist fucked around with this message at 13:03 on Apr 16, 2023 |
# ? Apr 16, 2023 12:39 |
|
boofhead posted:just to clarify, since this is also something i've been scratching my head over but never had time/energy to research properly because i am a bad developer, but: I'm thinking about this post: FISHMANPET posted:A User object has a get_groups() method that will return all the Groups the User is a member of. A Group has a get_members() method that will return all Users of the Group. So a User object has no Group property, and a Group has no User property, but they each have methods that will call the constructor for the opposite object. The multiple local imports are a problem imo. A User should not be calling the constructor of Group, this is prone to issues and is a pain to refactor; when you look at this in terms of technical debt it's actually just worse than having both classes in the same file. Having every User keep track of its groups as an attribute or property would be a bit better, and then you could just slap the TYPE_CHECKING variable at the type of 1 of the files without having to resort to local imports. Note that User cannot create a Group here, but its list of parents is fully typed. Python code:
What are some alternatives? Presumably these classes don't just exist in a vacuum, you could create an interface or a mediator that tracks the linkage between instances of these classes instead of using a 2-way coupling in the class definitions. QuarkJets fucked around with this message at 20:41 on Apr 16, 2023 |
# ? Apr 16, 2023 20:39 |
|
QuarkJets posted:I'm thinking about this post: FWIW: This example is about how I would have approached it; I guess I misunderstood some of the distinctions here.
|
# ? Apr 16, 2023 22:02 |
|
I also want to clarify the terminology a little, I wonder if that's a source of confusion; when I see "local import" I think "an import statement inside of a function or method, instead of at the top of a file".
|
# ? Apr 16, 2023 23:37 |
|
Mutual dependencies are common, and something any more-than-toy language has to deal with. Python's solution for them is to combine - assume that most code is inside a function made by a def or lambda and - the language doesn't resolve names in functions until they actually execute. Until then, they are just saved strings Those two combine to make an ersatz two-pass parser that mostly avoids the programmer having to think about it or deal with forward declarations, but is still very easy to implement (which is important because at that time, Python is still Guido van Rossum's one-man hobby project). Python import statements are much closer to dumb C textual #includes than they are to imports in something like Java/C#/Rust. In code like Python code:
- At (1), start constructing a new class object. It isn't accessible from anywhere yet, trying to access Foo will give a NameError - At (2), start defining a new function object. It isn't accessible from anywhere yet either - At (4), in the function's code, save that it's going to call "bar" (that literal string) on some_bar_instance. Bar doesn't exist at all yet, let alone exist with a bar member - At (5), finish the function object being constructed. Save a reference to it in the class object under construction's attributes table under the "foo" string key - At (8), finish the class object being constructed. Save a reference to it in this module's attributes table under the "Foo" string key. Lookups for Foo will succeed after this point The interpreter doesn't care that names inside functions don't point to anything at the time they were defined, it's only an error if they are still invalid at the time they are run. This mostly works as well as real two-pass parsing, except for all the times it doesn't and the programmer has to work around it. One situation where it doesn't work at all is type hint annotations, because those are code not hidden inside a function. They run during definition of the class/function and names in them need to exist at that point. Mutual reference or self referencing names won't. The language has gotten a few hacks layered on top to deal with that: - typing.TYPE_HINTING lets code do different things depending on who is consuming it - If an annotation evaluates to a string, somebody using that annotation is supposed to eval() it to get the actual value. So you can do def Foo() -> "SomeTypeThatDoesntExistYet". - PEP563 changed the language so that instead of evaluating annotation code, the interpreter replaces them with a string that, when eval()-ed, will return the original annotation. Basically it automates that string wrapping from the earlier hack. You enable this with from __future__ import annotations. This was added in Python 3.7 and supposed to become default in Python 3.10, but was delayed because the PEP649 hack seemed potentially better - PEP649 is a proposed change to use a hidden function to delay evaluation of annotations until the first time somebody access the __annotations__ object. It's better because it avoids some breaking changes to the names that are available to annotation code If you're using Python 3.7+ and not doing anything fancy, you should probably be from __future__ import annotations instead of testing typing.TYPE_CHECKING
|
# ? Apr 16, 2023 23:52 |
|
So it looks like it will be a while before I can nail live coding tests. I had one today to take the following list:code:
This tangled mess was my initial answer: code:
I corrected it as best as I could: code:
Good thing they didn't ask a leetcode-style question. Oh well, I'm improving!
|
# ? Apr 18, 2023 22:05 |
|
I just can't help myself...Python code:
|
# ? Apr 18, 2023 22:24 |
|
|
# ? May 15, 2024 01:55 |
|
ahh i always forget to use filter and all the extra QOL poo poo in python i, too, couldnt help myself Python code:
boofhead fucked around with this message at 07:53 on Apr 19, 2023 |
# ? Apr 19, 2023 07:37 |