If you are curious on how the #python Garbage Collector is designed - I advise to check out the Pablo Golindo article.
The twelve-factor app is a methodology for building software-as-a-service apps. I guess it is a must have to be familiar with for a modern web aps developer.
12factor.net
The Twelve-Factor App
A methodology for building modern, scalable, maintainable software-as-a-service apps.
❤1
Consider the #python code on the attached image. How do you think, why do we see only the return from the finally block?
Well, the official documentation has us covered. It's as simple as:
If the try statement reaches a break, continue or return statement, the finally clause will execute just prior to the break, continue or return statement’s execution.
Well, the official documentation has us covered. It's as simple as:
If the try statement reaches a break, continue or return statement, the finally clause will execute just prior to the break, continue or return statement’s execution.
👍2
One of my favorite tricks in #python which really enhances the classes understanding - is the imitation of Java/JavaScript like increment operator.
Take a look at the code on the attached photo.
So, the increment operator "++" adds one to the number. This is an inplace operation in Javas. In my simple example it is not, but using the idea I show it is pretty manageable.
How it works: I create two secondary classes and inherit from the usual integer. I make a pos dunder for both. Which stands for positive unary operation: https://docs.python.org/3/reference/datamodel.html#object.__pos__ and is activated each time there is a plus before the object in the code, but without the second object to use the add instead.
So, if a plus sign appears before my Int object - the pos dunder method is fired. And just returns the _Second_Plus_Int. This way we are protected from adding a value if the plus sign is single. But the _Second_Plus_Int also checks for signs before it. And if it found something - well, it's at least the second plus in a row, time to increment the value.
As the prints show - those classes swap while using plusses to activate the pos dunder one by one.
Take a look at the code on the attached photo.
So, the increment operator "++" adds one to the number. This is an inplace operation in Javas. In my simple example it is not, but using the idea I show it is pretty manageable.
How it works: I create two secondary classes and inherit from the usual integer. I make a pos dunder for both. Which stands for positive unary operation: https://docs.python.org/3/reference/datamodel.html#object.__pos__ and is activated each time there is a plus before the object in the code, but without the second object to use the add instead.
So, if a plus sign appears before my Int object - the pos dunder method is fired. And just returns the _Second_Plus_Int. This way we are protected from adding a value if the plus sign is single. But the _Second_Plus_Int also checks for signs before it. And if it found something - well, it's at least the second plus in a row, time to increment the value.
As the prints show - those classes swap while using plusses to activate the pos dunder one by one.
❤1
I found myself frequently looking for set operations symbols in #python so I made a bizarre looking cheat-sheet.
❤1
Do you like the #python iterator mechanism as much as I do?
Shortly: sequences and (sometimes) containers can be iterated over. The built-in function "iter" converts those objects into the "Iterator" object. By applying the "next" built-in function to such "Iterator" - you can get the next value inside the iterable. Once the object is exhausted of values - the StopIteration error is raised.
But why do we need that?
Let's think about efficiency. Take a look at the first lines of the picture, where I demonstrate the concept by shadowing the built-in "zip" function. The "repeat" function of the itertools module will indefinitely provide the value if the second argument is not provided. And imagine that each test case, each list inside is millions items long. It would be a great waste of memory to manipulate those objects in whole. Thankfully we can operate with their values one step at a time. That's why functions like "zip" return generators instead of actual results. And it is for you to decide - do you want to traverse the output with the "next" approach or to convert the output into, let's say, tuple and let the iteration machinery do the work for you under the hood.
About the attached picture.
I declare the TEST_CASES global constant, each row represents a specific set of sequences to "zip". Later I provide the shallow shadow of the original "zip" function without some features like the "strict" parameter. I pack all the input objects into the "args" variable. I initialize all "Iterator" objects on the line 12-th with a list comprehension and in the infinite loop I request "next" values from each of those "Iterators" at once. And pack those into the tuple. Once ANY of the "Iterators" is exhausted - I intercept the exception. Otherwise - time to "yield" the current pack of values. That's the keyword which makes my function a generator. And lastly starting from the line 21-st I just compare the output of my imitation with the glorious origin.
Shortly: sequences and (sometimes) containers can be iterated over. The built-in function "iter" converts those objects into the "Iterator" object. By applying the "next" built-in function to such "Iterator" - you can get the next value inside the iterable. Once the object is exhausted of values - the StopIteration error is raised.
But why do we need that?
Let's think about efficiency. Take a look at the first lines of the picture, where I demonstrate the concept by shadowing the built-in "zip" function. The "repeat" function of the itertools module will indefinitely provide the value if the second argument is not provided. And imagine that each test case, each list inside is millions items long. It would be a great waste of memory to manipulate those objects in whole. Thankfully we can operate with their values one step at a time. That's why functions like "zip" return generators instead of actual results. And it is for you to decide - do you want to traverse the output with the "next" approach or to convert the output into, let's say, tuple and let the iteration machinery do the work for you under the hood.
About the attached picture.
I declare the TEST_CASES global constant, each row represents a specific set of sequences to "zip". Later I provide the shallow shadow of the original "zip" function without some features like the "strict" parameter. I pack all the input objects into the "args" variable. I initialize all "Iterator" objects on the line 12-th with a list comprehension and in the infinite loop I request "next" values from each of those "Iterators" at once. And pack those into the tuple. Once ANY of the "Iterators" is exhausted - I intercept the exception. Otherwise - time to "yield" the current pack of values. That's the keyword which makes my function a generator. And lastly starting from the line 21-st I just compare the output of my imitation with the glorious origin.
❤2
Once upon a time I stumbled upon a philosophical dispute whether do coders need #math. I do believe that math is a niche must have, though in mass it is not required. Honestly, very little math were involved while I set up #APIs, created #databases, routed messages and operated with json files.
Though math deserves its credit for shaping the way developer thinks. For abstraction skills. And, in my opinion, it really shines if you have to optimize #efficiency.
For example, take a look at a puzzle I just solved in #python on #CodeSignal. Image attached. Straightforward approach would be to simulate the whole situation with loops. Which is O(n) #complexity at best. But by applying math ideas - I was able to dramatically speed up to the glorious O(1), constant time. Just 11 arithmetical operations for ANY valid input.
In the comment section of the code you'll find my notes representing my thought process. I imagined the result in the 3d space and started to think how could I sum up different parts of the shape. I easily applied the sequence sum school formula, though needed some googling in order to remember how to sum the sequence of squares.
Though math deserves its credit for shaping the way developer thinks. For abstraction skills. And, in my opinion, it really shines if you have to optimize #efficiency.
For example, take a look at a puzzle I just solved in #python on #CodeSignal. Image attached. Straightforward approach would be to simulate the whole situation with loops. Which is O(n) #complexity at best. But by applying math ideas - I was able to dramatically speed up to the glorious O(1), constant time. Just 11 arithmetical operations for ANY valid input.
In the comment section of the code you'll find my notes representing my thought process. I imagined the result in the 3d space and started to think how could I sum up different parts of the shape. I easily applied the sequence sum school formula, though needed some googling in order to remember how to sum the sequence of squares.
So, which is faster in #python for strings - reverse function approach or negative step slicing?
Origin of the dispute: Didier Flamm comment to 🐍 Dorian Turba post
As it turns out in my speed-test - [::-1] is almost x7 times faster. Which makes sense. Indexing is a low-level single step optimized operation. While reversed-join path struggles from midway type casting and two step operation.
Origin of the dispute: Didier Flamm comment to 🐍 Dorian Turba post
As it turns out in my speed-test - [::-1] is almost x7 times faster. Which makes sense. Indexing is a low-level single step optimized operation. While reversed-join path struggles from midway type casting and two step operation.
#SOLID in the OOD (Object Oriented Design) stands for:
1 - Single Responsibility Principle: A class should have only one reason to change.
2 - Open-Closed Principle: Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
3 - Liskov Substitution Principle: Subtypes must be substitutable for their base types.
4 - Interface Segregation Principle: Clients should not be forced to depend upon methods that they do not use. Interfaces belong to clients, not to hierarchies.
5 - Dependency Inversion Principle: Abstractions should not depend upon details. Details should depend upon abstractions.
1 - Single Responsibility Principle: A class should have only one reason to change.
2 - Open-Closed Principle: Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
3 - Liskov Substitution Principle: Subtypes must be substitutable for their base types.
4 - Interface Segregation Principle: Clients should not be forced to depend upon methods that they do not use. Interfaces belong to clients, not to hierarchies.
5 - Dependency Inversion Principle: Abstractions should not depend upon details. Details should depend upon abstractions.
I made a short fun project dedicated to the "[Br]eaking [Ba]d" series: br-badizer of texts!
You can play with it here: https://rioran.github.io/breaking-badize/main.html
Source code to be found here: https://github.com/Rioran/breaking-badize
Made with #python and #pyscript thanks to PyScript for a nice tool!
You can play with it here: https://rioran.github.io/breaking-badize/main.html
Source code to be found here: https://github.com/Rioran/breaking-badize
Made with #python and #pyscript thanks to PyScript for a nice tool!
#python 3.12 final version is expected to arrive in October 2023. Along other changes we are to embrace the "Syntactic formalization of f-strings", which includes:
1) Quotes reuse inside f-strings, which makes it possible to have nested f-strings further than 4 levels deep.
In my humble opinion f-strings nesting presents unnecessary cognitive complexity and should be avoided in production. Though developers decided to ignore such concerns to focus on the parser technically and wish for linters to handle the situation.
2) Multi-line expressions and comments will be allowed.
Which IMO could make complex f-strings easier to read. Though preparing it's parts elsewhere is more likely to be easier to read.
3) Backslashes inside f-strings will be allowed.
Which will make it possible to use escaping and all related mechanisms like working with the newlines or emoji (Unicode escaped sequences). Though escaped braces are still disallowed intentionally, at least "for the time being" (c).
More details could be red in PEP-701.
Reasoning behind the f-strings formalization includes:
- lowering the maintenance cost of the CPython parser;
- allowing the new PEG parser to apply improved error messages;
- making f-strings a part of the "official Python grammar" so that other Python implementations can be sure they implemented f-strings correctly;
The mechanism behind the changes introduces 3 new tokens for the parser to work with: FSTRING_START, FSTRING_MIDDLE, FSTRING_END. So, the tokenizer won't be able to produce a single token for f-strings anymore, will need more.
1) Quotes reuse inside f-strings, which makes it possible to have nested f-strings further than 4 levels deep.
In my humble opinion f-strings nesting presents unnecessary cognitive complexity and should be avoided in production. Though developers decided to ignore such concerns to focus on the parser technically and wish for linters to handle the situation.
2) Multi-line expressions and comments will be allowed.
Which IMO could make complex f-strings easier to read. Though preparing it's parts elsewhere is more likely to be easier to read.
3) Backslashes inside f-strings will be allowed.
Which will make it possible to use escaping and all related mechanisms like working with the newlines or emoji (Unicode escaped sequences). Though escaped braces are still disallowed intentionally, at least "for the time being" (c).
More details could be red in PEP-701.
Reasoning behind the f-strings formalization includes:
- lowering the maintenance cost of the CPython parser;
- allowing the new PEG parser to apply improved error messages;
- making f-strings a part of the "official Python grammar" so that other Python implementations can be sure they implemented f-strings correctly;
The mechanism behind the changes introduces 3 new tokens for the parser to work with: FSTRING_START, FSTRING_MIDDLE, FSTRING_END. So, the tokenizer won't be able to produce a single token for f-strings anymore, will need more.
❤2
Wrote some notes over the "Software Architecture" course: https://www.linkedin.com/pulse/notes-over-software-architecture-foundations-course-roman-voronov
Linkedin
Notes over the “Software Architecture Foundations” course
Here are my chaotic notes over the “Software Architecture Foundations” course by Allen Holub. I want to highlight that the material is great and super-useful as an introduction into a huge topic, though at the beginning it feels a little biased: the author…
Open Systems Interconnection
Seven layers of the Model:
Physical's for bit transmission
Data Link's for data format
Network finds the data path
Transport Layer transmits data
Using different protocols
Session is facilitator
Presentation one ensures
Data's ready for an action
Application uses network
Handles human interaction
Seven layers of the Model:
Physical's for bit transmission
Data Link's for data format
Network finds the data path
Transport Layer transmits data
Using different protocols
Session is facilitator
Presentation one ensures
Data's ready for an action
Application uses network
Handles human interaction
❤2
If you are new to distributed applications - chances are you will probably follow any of those false assumptions:
1. The network is reliable.
Power failure, broken network cord, software error, message loss... There's a world of risks.
2. Latency is zero.
Even in ideal circumstances the maximum speed of information transmission is capped by the speed of light. Thus it will always take at least 30 ms to ping US from Europe and back.
3. Bandwidth is infinite.
No, STEAM doesn't load my newly acquired game in an instant. And there's also a packet loss to be considered.
4. The Network is Secure.
Top 2022 cyber security breaches include millions of users data breach of Twitter, 500M Whatsapp users phone numbers leaked, 50K Revolut users personal information exposed.
5. Topology doesn't change.
Dynamic IPs, CI/CD processes, databases sharding/replication, moving servers, clients changing devices & networks and that's only a top of the iceberg.
6. There is one administrator.
Live of your application depends on multiple parties. Whether it's external vendor or your fellow college - probably the occasion will come for you to solve an issue you are restricted to solve on your own.
7. Transport cost is zero.
You will inevitably pay. Time and resources for going between the application and transport level. Money for routers, network security, internet connections, electricity, etc.
8. The network is homogeneous.
Across almost every organization I saw operating systems being split by Miscrosoft & Linux, different processor architectures like x86, x64, and don't even mention the diversity of mobile devices. Do they work the same?
Fallacies were introduced by Peter Deutsch (first seven) & James Gosling (the eighth) in late 90s. I took some inspiration in Arnon Rotem-Gal-Oz paper. And added my personal perspective on examples.
#architecture #design
1. The network is reliable.
Power failure, broken network cord, software error, message loss... There's a world of risks.
2. Latency is zero.
Even in ideal circumstances the maximum speed of information transmission is capped by the speed of light. Thus it will always take at least 30 ms to ping US from Europe and back.
3. Bandwidth is infinite.
No, STEAM doesn't load my newly acquired game in an instant. And there's also a packet loss to be considered.
4. The Network is Secure.
Top 2022 cyber security breaches include millions of users data breach of Twitter, 500M Whatsapp users phone numbers leaked, 50K Revolut users personal information exposed.
5. Topology doesn't change.
Dynamic IPs, CI/CD processes, databases sharding/replication, moving servers, clients changing devices & networks and that's only a top of the iceberg.
6. There is one administrator.
Live of your application depends on multiple parties. Whether it's external vendor or your fellow college - probably the occasion will come for you to solve an issue you are restricted to solve on your own.
7. Transport cost is zero.
You will inevitably pay. Time and resources for going between the application and transport level. Money for routers, network security, internet connections, electricity, etc.
8. The network is homogeneous.
Across almost every organization I saw operating systems being split by Miscrosoft & Linux, different processor architectures like x86, x64, and don't even mention the diversity of mobile devices. Do they work the same?
Fallacies were introduced by Peter Deutsch (first seven) & James Gosling (the eighth) in late 90s. I took some inspiration in Arnon Rotem-Gal-Oz paper. And added my personal perspective on examples.
#architecture #design
👍2🔥1