[HN Gopher] Fastcore: A library that extends Python with new fea... ___________________________________________________________________ Fastcore: A library that extends Python with new features Author : thenipper Score : 132 points Date : 2020-09-04 13:29 UTC (1 days ago) (HTM) web link (fastpages.fast.ai) (TXT) w3m dump (fastpages.fast.ai) | karlicoss wrote: | Nice work! It's often hard to communicate complexity and justify | the abstractions, but nevertheless it's a cool demonstration of | what's possible in Python. It's worth thinking about simplifying | code and DSLs, as long as you don't go too crazy. | | My personal concern would be the lack of typing annotations (IMO | very important to have in a 'standard library'), and even if they | were present I doubt something like `store_attr()` would be | typeable without a mypy plugin. | | Personally, I sometimes trade boilerplate and tolerate code | duplication for the sake of the code being transparent to static | analysis. | orf wrote: | I dislike some of these. Some are cool, like 'Self', but giant | "swiss army knife" libraries feel odd. | | > Avoid boilerplate when setting instance attributes | | dataclasses[1] | | > Type Dispatch | | functools.singledispatch works with type annotations[2] | | > A more useful __repr__ | | dataclasses[1] | | > A better pathlib.Path | | path_object.read_text()[3]. The pickle stuff is interesting, but | I don't see the value over just pickle.load(path_object). | Monkeypatching Path to add this fees odd and unpythonic. | | 1. https://docs.python.org/3/library/dataclasses.html | | 2. | https://docs.python.org/3/library/functools.html#functools.s... | | 3. | https://docs.python.org/3/library/pathlib.html#pathlib.Path.... | formerly_proven wrote: | Using pickle for "Path.save/load" feels like a shortcut to me | that is inappropriate for many circumstances, since loading a | pickle in Python literally means running code from that pickle. | It's basically eval(Path.read()). It's not the kind of trust | relationship that I would typically expect from a load/save | pair. | | > Wait! What's going on here? We just imported pathlib.Path - | why are we getting this new functionality? | | If you are writing a library and this is part of your expose, | think long and hard. | | > Path.ls | | Highly gimmicky, doesn't support globs. Arguments are "n_max, | file_type and file_exts", in that order. n_max seems largely | pointless for real programs and like a workaround for a poor | REPL for interactive use. The difference between the last two | arguments is that the first one also accepts mimetypes (does | this call "file" on every file it sees?). | | Arguably the signature of a "Path.ls" should rather look like | "Path.ls(glob='<star>', <star>, files=True, dirs=True)" and it | should probably not return a bunch of strings. | jph00 wrote: | Look closer. It doesn't return strings. | jph00 wrote: | I'm the author of fastcore. | | dataclasses is not very extensible or flexible. It's fine for | starting with, but it's not at all a replacement for store_attr | etc. | | At fast.ai we used dataclasses extensively for a couple of | years, but it just kept biting us. So eventually we switched to | these different approaches, which have worked much better for | us. | | singledispatch is nice enough too, but multiple dispatch with | typedispatch is fat more flexible and powerful. | | Just because something is in the stdlib, doesn't mean it's the | perfect solution to every problem, and that everyone should try | to hack their code to fit into those existing solutions. | nemetroid wrote: | > dataclasses is not very extensible or flexible. It's fine | for starting with, but it's not at all a replacement for | store_attr etc. | | > At fast.ai we used dataclasses extensively for a couple of | years, but it just kept biting us. | | What were the issues you had? | jph00 wrote: | The key issue is that it requires inheritance, but doesn't | actually support subclassing very well. | | Also it relies on python's type system, which is rather | limited. | | It's a very large module for what it does, and | understanding all the details of how it works in practice | is a big challenge. | Recursing wrote: | https://www.attrs.org/en/stable/why.html#data-classes | | The most used python library for these things is attrs, I | think it mostly provides support for slotted classes (more | memory efficient), "converters" (normalization), validation | and serialization | ghj wrote: | I didn't know about | functools.singledispatch/singledispatchmethod, that looks | really nice! | | For typing hinting, I've been annotating with @overload which | is just god awful ugly. And you still need to switch based on | instance type for the actual implementation. | | I will try this way instead! | | [1] https://www.python.org/dev/peps/pep-0484/#function-method- | ov... | pbsds wrote: | I agree on the monkeypatching of pathlib. It makes it difficult | for a reader to look up what the functions do. Providing a | different module, like `import nPathlib as Pathlib` would be a | lot more discoverable. | jph00 wrote: | Your coding environment really should be providing that basic | functionality for you. | ebg13 wrote: | > _functools.singledispatch works with type annotations[2]_ | | Only for the first argument. "Note that the dispatch happens on | the type of the first argument, create your function | accordingly". | | Making delegated kwargs transparent is 100% cool though and | addresses a huge problem with delegated interfaces. I'd use | that all the time. | | I agree with you about the swiss army thing. I wish it weren't | bundled with all this other stuff. | codegladiator wrote: | > Whenever I see a function that has the argument __kwargs, I | cringe a little | | I cringe a little when someone says a straight forward thing | should be replaced by magic middleware. | lacker wrote: | This library reminds me of fast.ai itself. It's cool how you can | do so many things with a few lines of code, and I was impressed | the first couple times I used it. Over time, I started to run | into problems when I wanted to do something beyond the initial | demo. Many parameters are undocumented, functions do something | automatically that's often nice but there's no clear way to undo | it, and side effects are scattered about. I would prefer code | that was slightly longer, but simpler and more pythonic. | fpgaminer wrote: | Love the fast.ai ecosystem. | | Most don't appreciate how critical it is for an ML researcher to | be able to play. The best research in fields like that require a | tight feedback loop, since we lack an intuition or logical | framework from which to reason about these systems. Instead we | have to throw shit at the wall, inspect what sticks, and repeat | 1000x. The vast majority of evolutionary leaps that I've seen in | ML and fields like it have been from "stupid" stuff no classic | researcher in their right mind would try. Instead it arises out | of a sense of curiosity and playing around. "I wonder what would | happen if we used only attention layers? Wouldn't that be silly?" | ... | | Tooling is a huge part of that. The cost of iterating needs to be | low. If you have to rebuild your entire training loop to try a | stupid idea, you're not going to try that idea. That's what makes | ecosystems like fast.ai so valuable. The whole thing is designed | for fast, cheap, highly malleable iteration. | | The design decisions required to achieve that have resulted in a | library with its fair share of sharp corners. It's a bit of a | holographic codebase, where functionality is splintered all | across the surface of it. The focus on Notebooks and code jamming | leave engineering traditionalists wanting. Etc. | | Don't get me wrong. When I write write most other code, I put my | engineering glasses on. I want code to be clear and transparent, | maintainable, idiomatic, etc. It's just that in ML play is more | critical. | | So it's important to look at fastai's codebase through that lens. | I disagree with commenters here criticizing the codebase as being | akin to what an inexperienced engineer would write. Instead it's | clear to me that the fastai developers have made numerous very | conscious decisions to break convention in support of their | goals. They've done that well. And I think it's all in support of | their "fast" ideal. | | Honestly if I were to lob real criticism at fastai, it would be | to say that it needs more documentation. I know, that's a weird | criticism given their use of literate programming and the courses | available. But ... for example, I have such a hard time with the | DataBlock API. I didn't come out of the courses with a good | understand of it and the docs are IMO too lacking to sufficiently | teach an intuition about it. I had a model where the "y" variable | is generated by the model itself. Was never able to figure out | the idiomatic way to express that in fastai. Had to fight the | DataBlock API and the training loop system tooth and nail to fit | it in. I'm sure there's a way to do it. It just wasn't apparent | to me. | | Of course, that's a _criticism_, not a complaint. The work of | Jeremy and co is just an incredible gift to the world. I don't | think it speaks ill to say the docs are lacking. That's true of | the vast majority of open source software. Documentation is plain | _hard_. And the courses, while they touch on the library a good | amount, are primarily focused on teaching ML concepts ... as they | should be. | | Hell, I bet they are aware of that and their switch to literate | programming is probably driven by it. It's probably just early in | that cycle and things will continue to get better. | | I hope it's clear this comment is more about love of the library | than a complaint about what is otherwise an amazing thing. | typon wrote: | This library reminds me a lot of the code I've seen from junior | developers trying to make things "cool" by removing a few | characters of typing in exchange for library abstractions that | create headaches down the line. I think features like this take | years to naturally evolve in a codebase, on an as needed basis. | And once that code base has evolved to reach something resembling | non idiomatic Python, it can be quite hard to integrate new devs | into the team. Such transitions into custom dsls or nifty tools | are inevitable for large code bases, but I try to minimize it as | much as possible, even when it hurts productivity. Long term | maintainability is more important to me. | digitallogic wrote: | > I try to minimize it as much as possible, even when it hurts | productivity. Long term maintainability is more important to | me. | | I don't think this needs to be an either/or choice in these | situations. You can have both if you make the make the | conscious decision to not fight your tools. Yes, sometimes you | have to be more verbose in one language than another, but the | productivity hit in that case always pales in comparison to the | hours, days, and in some cases I've seen, weeks, lost by | someone fighting their language/tools. | | My favorite example of this was a developer given a 2 week | feature implementation that ballooned to two months. They had | minimal experience C++, and they didn't like its looping | syntax. Rather than accept that frustration and write the code | in a syntax they disliked, they instead spent weeks writing a | "re-usable library that abstracts away looping semantics". | slaymaker1907 wrote: | I know what you are talking about in general, but most of the | stuff in this library seems to either add clarity or help | prevent errors. The problem of kwargs where you end up with a | bunch of confusion on documentation is definitely a real thing. | | Multiple dispatch is also a great thing as well. You don't | realize you need it until you try implementing something | unification algorithm. | | Compose is nice for reducing the mental overhead of reading | nested expressions. However, I do wish they took a line from | lodash and implemented flow instead (like compose but reversed | so the first argument is invoked first, then the output of that | is fed into the second, and so on). | | Syntactic sugar is not bad if it increases signal to noise when | reading code or if it prevents erroneous usage. | marmaduke wrote: | Ok but what's with the pre post meta init thing? Let's see a | junior run a debugger through that! Dropping one line of code | costs several stack frames in your debug session. | jph00 wrote: | It's a feature from the standard library. However it's only | normally available in dataclass. fastcore simply brings the | same functionality to other classes too. | hitekker wrote: | I have a feeling these Python enhancement libraries will become | ever more popular now that Guido has stepped down. | | I wonder what the vision of Python's steering committee is. | GhostVII wrote: | Lot of the features in this library seem to be targeted at | making things clearer, not just making your code as compact as | possible. It is a lot cleaner to use type dispatch rather than | have some switch case in your function to determine behavior. | And it is useful to know where the kwargs is being used rather | than have it be a black box. Having to store every parameter | from __init__ into self is an annoying pattern I find myself | almost always following, so it's nice to have a solution to | that too. | | Generally I prefer to use vanilla python as much as possible, | but I think there is value in having libraries like this, which | make things clearer and have less boilerplate without much | cost. Most of what I see would be pretty easy to replace with | regular python if you decided to move away from the library, | there aren't lots of wierd layers being added to your code. | giancarlostoro wrote: | I think the sweet spot is the approach taken by Kotlin for | making DSLs because it further removes ceremonial boilerplate | that Java loves to give you. I think Pythons as minimalist as | it needs to be... The best I do is rename imports that are long | if anything. I also define function pointers if I reuse the | same method call throughout a tree which helps to keep things | tight yet still readable. | wirthjason wrote: | I've seen this happen with senior devs too, but who come from a | background other than Python. | | There's a lot of value in deeply learning the internals of a | language so you can write good code in the target language | rather than developing some mashup of "features". | | Ironically the article begins with be premise of deeply | learning python but never touches on the advanced features that | were learned and applied to develop the library. | jph00 wrote: | The person that wrote the article doesn't work at fast.ai and | didn't write the library, so they don't have that | information. | hitekker wrote: | But aren't you one of the authors of this article? The | headline lists you as an author and you're a founding | researcher at Fast.ai. | jph00 wrote: | Oh so it does! Sorry I'll ask Hamel to change that - he's | just being generous with his credit. I didn't write a | single word of it! | | Sorry for the confusion. :) | mloncode wrote: | Sorry about that. Indeed, I felt that since he was the | author of the library and essential to me learning it I | felt the least I could do was to put his name on there. I | removed his name via | https://github.com/fastai/fastpages/pull/408 -- Sorry for | the confusion! | | Indeed, even though I learned a ton about python, I | didn't feel like what I had to say made for an | interesting blog article, and was a bit abstract. I was | equally excited about the library from and end user's | perspective and decided to blog about that instead. | wrkronmiller wrote: | There used to be a saying among web developers that you can | either use a framework or end up building a framework. | [deleted] | ayush--s wrote: | All sizable codebases eventually grow their own patterns & | utils that have similar abstractions. I'd rather spend my time | writing business logic than boilerplate. | bonoboTP wrote: | Too clever, too much magic. I remember I used to create such | things in my projects in my earlier days as a dev and was quite | proud of how compact things were and how much I understand my way | around the language that I was able to come up with it. But at | the end of the day, these things have a much higher price than it | seems at first. Sparing a few lines here and there is not worth | confusing your code's readers or yourself in a year. Standard | established "pythonic" solutions are preferable. | | Some are nice functions, I guess all of us have our collection of | utils that we carry around projects and it's certainly nice to | have some of them collected in an installable library. But I'd | prefer to have them separately in small, separately installable | modules, similar to "more_itertools". | | delegates: Maybe it's useful for auto-completion in notebooks. | | store_attr(): Too confusing. | | Avoiding subclassing boilerplate: don't, it's too confusing. Type | dispatch: perhaps, but I think isinstance is okay too. | | A better version of functools.partial: Ok, docstring is kept. | Could be even changed in the standard library. | | Composition of functions: Okay, could be an addition to functools | in the standard library. | | A more useful __repr__: Good. | | Monkey Patching With A Decorator: Please don't. | | A better pathlib.Path: I don't think loading pickle should be a | method of Path objects. I already dislike pathlib putting | read_text as a method of Path. Why not Path.read_jpeg_image()? | Path.save_mp4_video() etc. Also don't monkey patch Path please. | | Self: too confusing, little upside to it. It makes things look | like the function is being called, while actually only a lambda | is produced. Too much magic. | | in_notebook(), in_colab(), in_ipython: Useful. | | The L list: the numpy style indexing is nice, but you may as well | create a numpy array. | [deleted] | miguendes wrote: | > Wait! What's going on here? We just imported pathlib.Path - why | are we getting this new functionality? Thats because we imported | the fastcore.foundation module, which patches this module via the | @patch decorator discussed earlier. | | This is a recipe for disaster. Too much magic that makes it | harder to debug. Especially for junior developers or people less | experienced in python. | | I've seen fast.ai code and in terms of good practices it violates | a bunch for the sake of convention. A good example is the `from | module import *`. | jph00 wrote: | That's not a good example at all. | | Every fast.ai module defines __all__, and is carefully designed | to allow "import *" to be used safely. I'm not aware of any | other library that goes to this trouble. | kyran_adept wrote: | Not having _all_ is just part of the problem. With "import *" | you also unknowingly load and potentially overwrite symbols. | If you specify each symbol you use, it's very simple for even | the most basic linter to figure you are doing something | wrong. | jph00 wrote: | It's not unknowingly at all. | mkolodny wrote: | Allowing import \\* to be used safely in notebooks is one | thing. Using it in a library is very different. | | import \\* is convenient to use in a shell. But it makes code | more difficult to read. If code doesn't explicitly say where | variables were imported from, it takes extra time to figure | out where variables were imported from - especially if you're | reading code on GitHub. | jph00 wrote: | On GitHub you can click the symbol to see where it comes | from. Any decent editor should provide similar | functionality. | | Reading the import line to find where a symbol comes from | is really clunky. | orf wrote: | It's not reading the import line. It's reading | "requests.get(...)" instead of "get(...)" | greatgib wrote: | I hope that it will not look like a personal attack but, | honestly, without looking at fastai, your replies on this | comment thread does not let me think that the library is | of very good quality. | | I see there the typical pattern of the 'expert beginner' | developer. | | If you read yourself,you are saying that you know well | that it is better to rely on a specific platform (Github) | or editor to be able to resolve your mess than having | self descriptive/sufficient code... | | For the module using a library, when you do an 'import *' | it can easily create a very big mess. For example, as a | dev you see a piece of code and you don't necessarily | know where all the symbols come from and so the | associated dependencies. And so if you have to move this | piece of code to another place you can have a hard time | to ensure and fix imports on the other side to be sure | that it matches. | | I'm sorry if I'm not clear, but it is so wrong on so many | points in an obvious way that I don't even know what to | start with. | armitron wrote: | I didn't find a single thing that I liked here. | | Rather, I thought these syntactic layers made things worse rather | than better, in terms of clarity, understandability and ease of | writing simple, straightforward code. | [deleted] | LukeB42 wrote: | All libraries extend their language with new features. | | A lot of the proposed value-add seems like the authors aren't | aware the built-in `type()` can dynamically modify class | definitions. | | Getting rid of `hex(id(self))` in `__repr__` is regressive UX. | | @typedispatch seems like both a slow way of using 'isinstance()' | and a FOMO C++ virtual function bloat. | qayxc wrote: | What does typed dispatch have to do with virtual functions in | C++? This type of dispatch happens at compile-time in C++ and | has nothing to do with "bloat" or even virtual functions. | Galanwe wrote: | Not sure if this is an elaborate prank or a real attempts at | making Python more Java like. | | I stopped reading when the author suggests using | | class NewParent(ParentClass, metaclass=PrePostInitMeta): def | __pre_init__(self, _args,_ *kwargs): super().__init__() | hansvm wrote: | Some of this looks excellent. E.g. I occasionally add features | like the kwargs delegate in my own code, and there are plenty of | places in scipy where that would be an improvement. | | Other bits of it aren't drastically better than the standard | library. Their typeddispatch is undeniably useful, but | functools.singledispatch covers most use cases, and it'd be a | shame to pull in all of fastcore for a single feature that's | probably covered by another library (e.g. the multipledispatch | library). | | Some of this is horrifying. There's nothing wrong with the | PrePostInitMeta per se....but I guarantee that's going to be a | footgun down the line, and IMO if somebody isn't able to | comfortably write that metaclass themselves they probably | shouldn't be using it. | olejorgenb wrote: | @delegate would be very neat if IDEs understood it. | Unfortunately doesn't seem to be the case for pycharm. | hansvm wrote: | Agreed (though it should still work with tooling like Sphinx | and would definitely work in a REPL, notebook, or debugger). | | That touches on a slightly bigger issue too. IDEs only | approximate the language and usually fail miserably if you, | e.g., do anything nontrivial with PEP-263. They'll whine when | new language features like async or assignment expressions | come out, they have the damnedest time inferring the type of | inner functions, and so on. An IDE typically offers support | for a (hopefully useful) subset of your favorite language. | jph00 wrote: | PrePostInitMeta is just adding what's already in the stdlib | dataclasses, but making it available to other classes too. | hansvm wrote: | Agreed (mostly...it looks more powerful than dataclasses | afaict). It looks like it could have a ton of use cases. | | My concern is that it seems easy to get started, but | metaclass hackery is hard to get right if you do much of it. | Maybe that fear is unfounded; have you found that people tend | to use it responsibly? | | As a small side-note, on the surface I'm not seeing any | reason it couldn't be implemented with something more | composable like __init_subclass__, and that might be a nice | touch. | nemetroid wrote: | Dataclasses have __post_init__, but they don't have a | __pre_init__, do they? From what I can tell, PrePostInitMeta | adds a completely new __dunder__ method with pre_init. | rzimmerman wrote: | I actually think the "delegates" syntax for kwargs or something | like it is worth adding to the standard library. The rest feels | like it's either covered by dataclasses or not something I | personally want in python. Except pre_init and post_init instead | of calling super().__init__. But that's up there with if __name__ | == "__main__" for being an annoying idiosyncrasy that's too hard | to change. | ayush--s wrote: | There is functools.wraps in standard library for similar | "delegation" in decorators | linkdd wrote: | Monkeypatching anywhere except unittests is a nono for me. It | adds some black magic you need to know before reading the code. | | Am I reading the standard pathlib.Path or the monkeypatched one ? | If I have a bug with it, it comes from the standard library or | the patch introduced silently ? | | Remember the zen of Python: | | > Explicit is better than implicit | | And I would personally prefer a unification library ( | https://github.com/mrocklin/unification/ ) over the type dispatch | proposed here. It's just more powerful and closer to pattern | matching if that's really what you want. | BiteCode_dev wrote: | Same. | | But I think what they did with partial should be in the stdlib. | | In fact partial should also be rewritten in C et promoted to | built in. | | Right now it's 10 times slower than lambda, and you have to | know about and wish to import functools, yet still loose the | docstring. | | Shame for such a great feature. | wrmsr wrote: | As far as I can tell functools.partial has been implemented | in C since it was added sixteen years ago ( https://github.co | m/python/cpython/commit/9c323f8de4910dfc0ba... ), and it's | faster than lambda ( https://gist.github.com/wrmsr/1e13eda3ed | 78288679c010acbe6d2b... ). Regarding docstrings you can | access the underlying function via the __wrapped__ attribute, | and signature forwarding is too brittle and magical for | stdlib. | Alex3917 wrote: | > Monkeypatching anywhere except unittests is a nono for me. | | What do you think about adding pprint to builtins so that you | don't need to import it each time when debugging? (Or, | alternatively, so that you don't need to add it to the top of | every single file?) It seems kind of wrong, but the | alternatives are bad also. I'm not sure why Python didn't do | this themselves when they added breakpoint in 3.7. | kristjansson wrote: | Pdb already has pretty print built in? $ | python -m pdb ... (Pdb) help pp pp expression | Pretty-print the value of the expression. (Pdb) pp | ... | linkdd wrote: | The debug code you add doesn't get removed before going into | production? | orf wrote: | pprint is a standard library module which isn't necessarily | available everywhere. You can run python without the standard | library, but the moment you add it to the default builtins it | needs to become part of the language. | lacker wrote: | Monkeypatching in one application is maybe okay. You really | want pprint in builtins, fine, who is it really hurting? | | Monkeypatching in a library like fastcore that many other | people use is really bad. All sorts of bugs and | incompatibilities will happen down the road, as software | becomes dependent on your monkeypatch without anyone | realizing it. | xapata wrote: | Can you configure your debugger to include it? I'd rather do | that than modify production code to include a debugging tool. | kristjansson wrote: | Fastai/Fastcore are fascinating in their emphasis on interactive | computing in notebooks. I think that starting from the assumption | that users will be | | (a) primarily using the abstractions in this library | interactively | | (b) to do analysis, or experiment with many different | implementations of similar functions | | (c) in long-lived sessions where re-running to the same point may | be expensive in time or compute, or impossible due dependence on | cell execution order etc. | | makes their design choices make more sense to me. | | Lots of the functionality identified here sort of nice if you're | in a traditional environment, but imperative if you're in (or | writing for users in) a notebook environment. For example, the | emphasis on preserving propagating signature information in | function objects themselves makes sense if you're relying on | `inspect` to provide IDE-like autocompletion. The emphasis on | easy monkey-patching and psuedo-generics makes sense if you're | interactively working with classes in modules you don't control, | or can't cleanly reimport. | | Not only that, fastai/fastcore themselves are written in Jupyter | notebooks via their literate programming environment nbdev [1]! | | I don't know that there's a point here beyond a bit of begrudging | admiration for how far they've pushed the notebook platform. It | makes for a library (and a Python) that looks and feels just a | few degrees off-axis from much of the rest of the ecosystem... | | [1]: https://nbdev.fast.ai | vvladymyrov wrote: | I hope that fast.ai courses do not and will not use this library | - it would increase required effort to understand the code in | lessons. | tmabraham wrote: | This is the fastai library used: https://docs.fast.ai/ | | You don't directly use fastcore for most things, but fastai | underneath uses fastcore. If you want to extend fastai for | custom and advanced tasks, fastcore is actually very helpful to | use. | heavyset_go wrote: | I'm only really a fan of @typeddispatch and the @patch decorator. | They don't do anything weird and follow the standard Python | decorator pattern. | pryelluw wrote: | Longtime pythonista and co-organizer of PyATL here. I appreciate | the goals of the library and understand the points being made in | the code. There are certain things that python has acquired over | time that are not as nice as they could be. Or maybe we can say | that momentum to improve them reduces over time. | | One of these things is the __init__ method. It is not named in a | clear manner and can be verbose. The alternative proposed with | store_attr is close, but still falls to be descriptive. Ideally, | I'd just adopt the keyword "constructor" or "initialize" and have | it be synthathic sugar for __init__. I do like the fact that it | provides a shorter way to initialize things. That could be | adopted with no drawbacks as long as we keep named parameters. | | I congratulate and welcome such ideas. Ill invite the library | author(s) to join the python core team and discuss the ideas with | them. It can take time to get new things into a project like | python, but we cant grow a language by doing the same thing over | and over. Languages need to evolve (to a certain extent) over | time. ___________________________________________________________________ (page generated 2020-09-05 23:00 UTC)