One of the key concepts of #python is the concept of callable.
Callable is an object that can be called. Basically, all of those are callables: user-defined functions, instance methods, generator functions, coroutine functions, async generator functions, built-in functions, built-in methods, classes and class instances.
In order to be a classic callable - you need to have a dunder method "call" to be defined. As it is in my short demo code on the attached image.
I make a custom class inheriting all there is from the float class. And I add the only method of the topic - the call dunder. For fun sake upon using our object as function - we will return a float times the specified number. In order to return our Callable_Number other than the float - we need to also modify the multiplication dunder. Which is now by default returns the float type.
On the line 5 we initiate our class. By the way, we are calling the class to get it's instance. That's how classes themselves are callable. And we get our Callable_Number object as the result. The following print statement clearly shows the float value and the existence of the call dunder, thanks to the callable built-in function.
On the line 7 we CALL the "a" object, an INSTANCE of our class. That's where the call dunder is activated. Thus the multiplication as a result. As you see - our newly created "b" object lacks the call dunder. Since it is a usual float due to the mechanism I described previously.
Useful links:
1 - callable built-in function https://docs.python.org/3/library/functions.html#callable
2 - datamodel with callable types described https://docs.python.org/3/reference/datamodel.html
3 - expressions reference on calls https://docs.python.org/3/reference/expressions.html#calls
4 - C-API call protocol https://docs.python.org/3/c-api/call.html
Callable is an object that can be called. Basically, all of those are callables: user-defined functions, instance methods, generator functions, coroutine functions, async generator functions, built-in functions, built-in methods, classes and class instances.
In order to be a classic callable - you need to have a dunder method "call" to be defined. As it is in my short demo code on the attached image.
I make a custom class inheriting all there is from the float class. And I add the only method of the topic - the call dunder. For fun sake upon using our object as function - we will return a float times the specified number. In order to return our Callable_Number other than the float - we need to also modify the multiplication dunder. Which is now by default returns the float type.
On the line 5 we initiate our class. By the way, we are calling the class to get it's instance. That's how classes themselves are callable. And we get our Callable_Number object as the result. The following print statement clearly shows the float value and the existence of the call dunder, thanks to the callable built-in function.
On the line 7 we CALL the "a" object, an INSTANCE of our class. That's where the call dunder is activated. Thus the multiplication as a result. As you see - our newly created "b" object lacks the call dunder. Since it is a usual float due to the mechanism I described previously.
Useful links:
1 - callable built-in function https://docs.python.org/3/library/functions.html#callable
2 - datamodel with callable types described https://docs.python.org/3/reference/datamodel.html
3 - expressions reference on calls https://docs.python.org/3/reference/expressions.html#calls
4 - C-API call protocol https://docs.python.org/3/c-api/call.html
The way I like my imports to be refactored in #python - is for them to be grouped and each name on a single line. It is highly readable, less prone for errors.
A simple way to refactor imports - is to use the isort library. I prefer to utilize the following flags:
mode 3 - stands for VERTICAL_HANGING_INDENT
force grid wrap 2 - to start grid wrapping with only 2 imported names
trailing comma - so that all lines are similar
With some shortcuts the final command looks like this:
You can edit the isort config file in order to NOT TO use all those flags each time. For these and other helpful details you can always refer to the isort official documentation: https://pycqa.github.io/isort/index.html
A simple way to refactor imports - is to use the isort library. I prefer to utilize the following flags:
mode 3 - stands for VERTICAL_HANGING_INDENT
force grid wrap 2 - to start grid wrapping with only 2 imported names
trailing comma - so that all lines are similar
With some shortcuts the final command looks like this:
isort file-name.py -m 3 -fgw 2 -tcYou can edit the isort config file in order to NOT TO use all those flags each time. For these and other helpful details you can always refer to the isort official documentation: https://pycqa.github.io/isort/index.html
During the 20-th PyErevan meetup one of the speakers - Ruben - showed how a #python #PyGame application can be #WASM-ed and shared through the net.
For fun sake I made my own humble visual #game and shared it through the Itch.io
- game hosted on https://rioran.itch.io/random-shifting-colors
- source code can be found on github https://github.com/Rioran/random-colors-visuals
For fun sake I made my own humble visual #game and shared it through the Itch.io
- game hosted on https://rioran.itch.io/random-shifting-colors
- source code can be found on github https://github.com/Rioran/random-colors-visuals
Telegram
PYerevan
Hey, Pythonistas!
Let me remind that we start our event in almost an hour, at 19:00!
We are looking forward to meeting you!
https://www.eventbrite.com/e/pyerevan-20-meetup-around-python-tickets-698442459197
Let me remind that we start our event in almost an hour, at 19:00!
We are looking forward to meeting you!
https://www.eventbrite.com/e/pyerevan-20-meetup-around-python-tickets-698442459197
Finally got my hands on the Jupyter Notebook 7. Whoa, I like those new features!
Here is my screenshot with the debugger and table of contents pane out of the box. Nice and clean! And those just scratch the tip of the iceberg!
Though, not everything is ideal. Some users, me included, could face difficulties to upgrade Notebook 6 to 7 from the Anaconda Navigator on Windows machine. Pity, I do love the Anaconda Distribution. So, terminal is our best friend. Install:
Here is my screenshot with the debugger and table of contents pane out of the box. Nice and clean! And those just scratch the tip of the iceberg!
Though, not everything is ideal. Some users, me included, could face difficulties to upgrade Notebook 6 to 7 from the Anaconda Navigator on Windows machine. Pity, I do love the Anaconda Distribution. So, terminal is our best friend. Install:
pip install jupyterAnd run:
pip install notebook
jupyter notebookHere is a nice library to be aware about: https://pypi.org/project/python-dotenv/
Python-dotenv reads key-value pairs from a .env file and can set them as environment variables. It helps in the development of applications following the 12-factor principles.
Python-dotenv reads key-value pairs from a .env file and can set them as environment variables. It helps in the development of applications following the 12-factor principles.
Rioran Tech Notes
Here is a nice library to be aware about: https://pypi.org/project/python-dotenv/ Python-dotenv reads key-value pairs from a .env file and can set them as environment variables. It helps in the development of applications following the 12-factor principles.
As a feature reach alternative to the slim dotenv library my fellow Python tamers recommend the dynaconf. It handles a lot more.
π1
Hey, dear #python enthusiasts, PyPI just went through a public audit! A huge masterpiece report can be found in the Trail Of Bits repository . Shortly: 8 medium and 6 low severity exposures, low test coverage, but overall all is good.
Just finished a 3 month "Python Intro" course. Tutored 11 bright students by the flag of the Armenian Code Academy.
LinkedIn post.
LinkedIn post.
Linkedin
Just graduated my Russian-speaking stream of developers by the flag of the⦠| Roman Voronov | 10 comments
Just graduated my Russian-speaking stream of developers by the flag of the Armenian Code Academy!
For three months of constant theory and practice 11 bright students got Python basics. With respect and gratitude I took Hrachya Ishkhanyan course program andβ¦
For three months of constant theory and practice 11 bright students got Python basics. With respect and gratitude I took Hrachya Ishkhanyan course program andβ¦
A must-have technique for a huge or feature-rich application - feature flags. It is a great way to control your project without the need to redeploy. You decide what parts of the project you want to work and in what way, remotely and smoothly.
Here is a well written entry article for the topic.
Here is a well written entry article for the topic.
Unleash Documentation
11 best practices for building and scaling feature flag systems
Build a scalable, secure feature flag system with 11 key principles. Improve DevOps metrics, ensure reliability, and enhance developer experience.
β€1π1π₯1π―1
tempfile - a nice built-in Python library to create temporary directories and files. You can use those tmp objects directly in Python or in complex scenarios like execution of a terminal command with BashOperator inside Airflow DAG.
Official docs: https://docs.python.org/3/library/tempfile.html
Example:
Official docs: https://docs.python.org/3/library/tempfile.html
Example:
from tempfile import NamedTemporaryFile
with NamedTemporaryFile('w') as file:
file.write('Roman\nRioran\nVoronov\n')
file.flush()
print(f'{file.name = }') # file.name = '/tmp/tmpbrotweh8'
with open(file.name, 'r') as tmp_file:
print(f'{tmp_file.readlines() = }') # tmp_file.readlines() = ['Roman\n', 'Rioran\n', 'Voronov\n']
Python documentation
tempfile β Generate temporary files and directories
Source code: Lib/tempfile.py This module creates temporary files and directories. It works on all supported platforms. TemporaryFile, NamedTemporaryFile, TemporaryDirectory, and SpooledTemporaryFil...
Several years ago during my analyst work in Yandex I regularly performed SQL related tasks via one hell of an internal tool. Not sure if NDA allows me to announce its internal name. But! Lo and behold - a huge and powerful part of that tool is now publicly released as YTsaurus! As I see it - the name is a mix of several geek words like "thesaurus" including one internal joke.
Just check out the number and quality of those features! https://ytsaurus.tech/
This tool allowed me to perform intensive and complicated calculations over billions of samples of user activity data in Taxi service.
Just check out the number and quality of those features! https://ytsaurus.tech/
This tool allowed me to perform intensive and complicated calculations over billions of samples of user activity data in Taxi service.
π3
As I continue reading "Refactoring" by Martin Fowler, chapter 6 discusses data access, particularly reference versus value. This topic brings back memories from years ago when I witnessed a team spend weeks debugging issues caused by poor data access practices.
Here is my Python 3.10 illustration of the technique Martin mentions. The two code samples have common parts. If you don't encapsulate - sooner or later, you'll run into trouble. As shown here: employee_b data gets modified by changes to seemingly unrelated objects. The overhead of copying is negligible, but the risks drop dramatically.
Risky code:
Encapsulated data:
Here is my Python 3.10 illustration of the technique Martin mentions. The two code samples have common parts. If you don't encapsulate - sooner or later, you'll run into trouble. As shown here: employee_b data gets modified by changes to seemingly unrelated objects. The overhead of copying is negligible, but the risks drop dramatically.
Risky code:
from dataclasses import dataclass, field
@dataclass
class Employee:
name: str = 'No name'
birth_year: int | None = None
projects: list[str] = field(default_factory=list)
def __repr__(self):
return f'Employee({self.name}, {self.projects})'
if __name__ == '__main__':
employee_a = Employee(name='Roman')
employee_b = Employee(name='Rioran')
new_projects = ['Party', 'New Year']
employee_a.projects = employee_b.projects = new_projects
employee_a.projects.append('Gym')
new_projects[0] = 'Dance'
print(f'{employee_b = }')
# employee_b = Employee(Rioran, ['Dance', 'New Year', 'Gym'])
Encapsulated data:
from dataclasses import dataclass, field
@dataclass
class Employee:
name: str = 'No name'
birth_year: int | None = None
_projects: list[str] = field(default_factory=list)
def __repr__(self):
return f'Employee({self.name}, {self.projects})'
@property
def projects(self):
return self._projects.copy()
@projects.setter
def projects(self, new_value: list):
self._projects = new_value.copy()
if __name__ == '__main__':
employee_a = Employee(name='Roman')
employee_b = Employee(name='Rioran')
new_projects = ['Party', 'New Year']
employee_a.projects = employee_b.projects = new_projects
employee_a.projects.append('Gym')
new_projects[0] = 'Dance'
print(f'{employee_b = }')
# employee_b = Employee(Rioran, ['Party', 'New Year'])
π1
By the way, #postgresql source code contains great documentation on indexes! For example, here's the HASH index README.
GitHub
postgres/src/backend/access/hash/README at REL_17_2 Β· postgres/postgres
Mirror of the official PostgreSQL GIT repository. Note that this is just a *mirror* - we don't work with pull requests on github. To contribute, please see https://wiki.postgresql.org/wiki/...
Here is how py2puml & plantuml tools combination could help you visualize your Python project entities.
Both are easily installed. PlantUML is even available as a PyCharm plugin. Normally going from zero to image would take less than a minute.
Minor hickups are possible though. On Windows py2puml tryed standard output instead of file creation. And output redirection was polluted with NULL symbols. Also by default py2puml didn't capture method names.
Here is my Kettle in Python:
That's what py2puml produced:
Both are easily installed. PlantUML is even available as a PyCharm plugin. Normally going from zero to image would take less than a minute.
Minor hickups are possible though. On Windows py2puml tryed standard output instead of file creation. And output redirection was polluted with NULL symbols. Also by default py2puml didn't capture method names.
Here is my Kettle in Python:
class Heater:
def __init__(self, min_temperature: int = 0, max_temperature: int = 100):
self.enabled: bool = False
self.temperature: int = 0
self.min_temperature: int = min_temperature
self.max_temperature: int = max_temperature
def start(self):
self.enabled = True
def update(self):
if self.enabled:
self.temperature += 1
self.temperature = min(self.max_temperature, self.temperature)
else:
self.temperature -= 1
self.temperature = max(self.min_temperature, self.temperature)
class Reservoir:
def __init__(self, volume: int = 1000):
self.volume: int = volume
self.water: int = 0
def fill(self, input_water):
total_water = self.water + input_water
self.water = min(self.volume, self.water + input_water)
spilled = total_water - self.water
return spilled
def pour(self, amount):
pour_amount = min(self.water, amount)
self.water -= pour_amount
return pour_amount
class Kettle(Heater, Reservoir):
def __init__(self, volume=1000, min_temperature=0, max_temperature=100):
Reservoir.__init__(self, volume)
Heater.__init__(self, min_temperature, max_temperature)
That's what py2puml produced:
@startuml tea
!pragma useIntermediatePackages false
class tea.Heater {
enabled: bool
temperature: int
min_temperature: int
max_temperature: int
+ __init__(min_temperature: int = 0, max_temperature: int = 100)
+ start()
+ update()
}
class tea.Kettle {
}
class tea.Reservoir {
volume: int
water: int
+ __init__(volume: int = 1000)
+ fill(input_water: int): int
+ pour(amount: int): int
}
tea.Heater <|-- tea.Kettle
tea.Reservoir <|-- tea.Kettle
footer Generated by //py2puml//
@enduml
β€1π1
