|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "Walkthrough with features introduced in Core Python 3.7" |
| 4 | +date: "2018-08-12 15:51:15 +0530" |
| 5 | +tag: |
| 6 | + - Python |
| 7 | + - Core_python |
| 8 | + - Python3.7 |
| 9 | +--- |
| 10 | + |
| 11 | + |
| 12 | +In this post, I will try to discuss improvements done in Core Python version 3.7. Below is the summary of features convered in this post. |
| 13 | + |
| 14 | +* Fstrings |
| 15 | + |
| 16 | +* Breakpoints |
| 17 | + |
| 18 | +* Disabling breakpoints using environment variable |
| 19 | + |
| 20 | +* namedtuples |
| 21 | + |
| 22 | +* subprocess |
| 23 | + |
| 24 | +* dataclass |
| 25 | + |
| 26 | +* int with under_scores |
| 27 | + |
| 28 | +* __dir__ and __attr__ at module level. Inside __init__.py file |
| 29 | + |
| 30 | + |
| 31 | +* Fstring: Fstring is one of the coolest feature introduced with this version of |
| 32 | + Python. F-String is yet another way of re-presenting formatted strings. At |
| 33 | + present, Python already have more than two ways to format string. This version |
| 34 | + do introduce yet another way to format the strings. In my view, this option is |
| 35 | + more concise than the other available options. |
| 36 | + |
| 37 | + ```python |
| 38 | + >>> name = "Jay" |
| 39 | + >>> print(f"Hello {name}") |
| 40 | + Hello Jay |
| 41 | + >>> name = "Vijay" |
| 42 | + >>> print(f"Hello {name}") |
| 43 | + Hello Vijay |
| 44 | + ``` |
| 45 | + |
| 46 | + You have to append **f** before the starting of the formatted string. The |
| 47 | + variable substitution will be done by looking for the value of that variable |
| 48 | + inside the present scope. If, the variable isn't defined that it will raise a |
| 49 | + NameError. |
| 50 | + |
| 51 | + |
| 52 | +* Breakpoint: Breakpoints are extream important feature for debugging. Since, I |
| 53 | + started learning Python I am using the same API of putting breakpoints. With |
| 54 | + latest improvements, you can put breakpoints by calling the function |
| 55 | + "breakpoint()". Yes, ```breakpoint`` is a built in function now. You don't |
| 56 | + need to import ```pdb``` and call ```pdb.set_trace``` anymore. |
| 57 | + |
| 58 | + Example |
| 59 | + ```python |
| 60 | + >>> for i in range(5): |
| 61 | + ... if i % 2 == 0: |
| 62 | + ... breakpoint() |
| 63 | + ... else: |
| 64 | + ... print(i) |
| 65 | + ... |
| 66 | + > <stdin>(1)<module>() |
| 67 | + (Pdb) c |
| 68 | + 1 |
| 69 | + > <stdin>(1)<module>() |
| 70 | + (Pdb) c |
| 71 | + 3 |
| 72 | + > <stdin>(1)<module>() |
| 73 | + (Pdb) c |
| 74 | + ``` |
| 75 | + |
| 76 | +* Disabling breakpoint with environment variable: Have you felt anytime that you |
| 77 | + are debugging your code and you have added lost of breakpoints. Now, you want |
| 78 | + to disable them for a moment. Removing them is time consuming and putting them |
| 79 | + back is too. Now, it is possible to disable all the breakpoints of your code |
| 80 | + by just setting an environment variable named "PYTHONBREAKPOINT=0". When you |
| 81 | + want to enable them again, you can either unset the value of this environment |
| 82 | + variable or set the value of it to "1". |
| 83 | + |
| 84 | + # TODO: Add video demonstration or gif demonstration for this. |
| 85 | + |
| 86 | + |
| 87 | +* Default arguments to Namedtuples: Namedtuples are less known, but very helpful |
| 88 | + feature of Python. I use them whenever I constructing a Class is lengthy, but |
| 89 | + I want to expose it as an instance. |
| 90 | + |
| 91 | + ```python |
| 92 | + >>> from collections import namedtuple |
| 93 | + >>> Point = namedtuple("Point", ["x", "y"], defaults=[2,]) |
| 94 | + >>> p = Point(3) |
| 95 | + >>> p |
| 96 | + Point(x=3, y=2) |
| 97 | + ``` |
| 98 | + |
| 99 | + One important point to observe here is that the default arguments will be |
| 100 | + assigned in the order of left to right. Here, the default argument **2** will |
| 101 | + be assigned to **y**, and not **x**. |
| 102 | + |
| 103 | +* Subprocess got new parameter named *capture_output*: We all use |
| 104 | + ```subprocess.run``` a lot for running various commands. For capturing the |
| 105 | + output of Standard output stream (stdout) and Standard error stream, we have |
| 106 | + to pipe them with existing subprocess module. Like below |
| 107 | + |
| 108 | + ```python |
| 109 | + >>> import subprocess |
| 110 | + >>> ls = subprocess.run(["ls", "-l", "/var"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 111 | + >>> print(ls.stdout.decode()) |
| 112 | + total 28 |
| 113 | + drwxr-xr-x 11 root root 4096 Apr 24 15:14 cache |
| 114 | + drwxr-xr-x 4 root root 4096 Aug 12 15:28 db |
| 115 | + drwxr-xr-x 2 root root 4096 Jul 2 13:47 empty |
| 116 | + drwxr-xr-x 34 root root 4096 Jul 20 04:22 lib |
| 117 | + lrwxrwxrwx 1 root root 9 Oct 12 2017 lock -> /run/lock |
| 118 | + drwxr-xr-x 11 root root 4096 Aug 12 14:52 log |
| 119 | + lrwxrwxrwx 1 root root 15 Apr 23 14:08 mail -> /var/spool/mail |
| 120 | + lrwxrwxrwx 1 root root 4 Oct 12 2017 run -> /run |
| 121 | + drwxr-xr-x 7 root root 4096 Jun 15 09:22 spool |
| 122 | + drwxrwxrwt 3 root root 4096 Aug 10 15:15 tmp |
| 123 | + |
| 124 | + >>> print(ls.stderr.decode()) |
| 125 | + |
| 126 | + |
| 127 | + ``` |
| 128 | + |
| 129 | + With this version, you can get exact output by just passing this option |
| 130 | + ```capture_output=True``` to ```subprocess.run(...)```. Below is the example |
| 131 | + for this. |
| 132 | + |
| 133 | + ```python |
| 134 | + >>> import subprocess |
| 135 | + >>> ls = subprocess.run(["ls", "-l", "/var"], capture_output=True) |
| 136 | + >>> print(ls.stdout.decode()) |
| 137 | + total 28 |
| 138 | + drwxr-xr-x 11 root root 4096 Apr 24 15:14 cache |
| 139 | + drwxr-xr-x 4 root root 4096 Aug 12 15:28 db |
| 140 | + drwxr-xr-x 2 root root 4096 Jul 2 13:47 empty |
| 141 | + drwxr-xr-x 34 root root 4096 Jul 20 04:22 lib |
| 142 | + lrwxrwxrwx 1 root root 9 Oct 12 2017 lock -> /run/lock |
| 143 | + drwxr-xr-x 11 root root 4096 Aug 12 14:52 log |
| 144 | + lrwxrwxrwx 1 root root 15 Apr 23 14:08 mail -> /var/spool/mail |
| 145 | + lrwxrwxrwx 1 root root 4 Oct 12 2017 run -> /run |
| 146 | + drwxr-xr-x 7 root root 4096 Jun 15 09:22 spool |
| 147 | + drwxrwxrwt 3 root root 4096 Aug 10 15:15 tmp |
| 148 | + |
| 149 | + >>> print(ls.stderr.decode()) |
| 150 | + |
| 151 | + ``` |
| 152 | + |
| 153 | + |
| 154 | +* Dataclass decorator: This new decorator will reduce many lines of your code. |
| 155 | + Python is known for such improvements. For understanding this more, you should |
| 156 | + be aware with Python's latest feature of providing type hints. I will try to |
| 157 | + write a tutorial on type hints in up coming days. Until there, I will suggest |
| 158 | + to grab any inital tutorial from your Google search. |
| 159 | + |
| 160 | + Below is the usual way to define a Class and creating an object from it. |
| 161 | + |
| 162 | + ```python |
| 163 | + >>> class Point: |
| 164 | + ... def __init__(self, x, y): |
| 165 | + ... self.x = x |
| 166 | + ... self.y = y |
| 167 | + ... |
| 168 | + >>> p = Point(2, 4) |
| 169 | + >>> p |
| 170 | + <__main__.Point object at 0x7f3c73688b00> |
| 171 | + ``` |
| 172 | + |
| 173 | + Above lines can be reduced with using ```@dataclass``` decorator. |
| 174 | + |
| 175 | + ```python |
| 176 | + >>> from dataclasses import dataclass |
| 177 | + >>> @dataclass |
| 178 | + ... class Point: |
| 179 | + ... x: float |
| 180 | + ... y: float |
| 181 | + ... |
| 182 | + >>> p = Point(2, 4) |
| 183 | + >>> p |
| 184 | + Point(x=2, y=4) |
| 185 | + ``` |
| 186 | + |
| 187 | + Those lines of putting construct for obious things is gone! Additionally, the |
| 188 | + class level decorator ```@dataclass``` is defining dundre methods like |
| 189 | + ```__repr__()``` and ```__eq__()``` and ```__hash__()``` for us. |
| 190 | + |
| 191 | + |
| 192 | +* Putting underscores in defining Integers: Writing large numbers as value in |
| 193 | + code is difficult to read. I myself put finger on screen and count the places |
| 194 | + to get an idea of number. In this version, you can add put *_* for values. |
| 195 | + Below example will make it more clear. |
| 196 | + |
| 197 | + ```python |
| 198 | + >>> x = 1_00_000 |
| 199 | + >>> x |
| 200 | + 100000 |
| 201 | + ``` |
| 202 | + |
| 203 | +* Module level definition of dunder methods __dir__() and __attr__(): I was |
| 204 | + facing this issue of hinding actual imports of my module with user. It was |
| 205 | + always confusing when someone calls "dir()" on my modules. There is already |
| 206 | + dunder method called "__dir__()" to override this behaviour, but this method |
| 207 | + was limited to Classes. With this version, it is possible to override the |
| 208 | + behaviour of module by defining module level ```__dir__()``` method. |
| 209 | + |
| 210 | + |
| 211 | + # TODO: Write the example of them here. |
| 212 | + |
| 213 | + |
| 214 | +* __attr__ : You can override this method for various purposes like firing an |
| 215 | + API deprication warning. The method will behave just as it was behaving on |
| 216 | + Class. |
| 217 | + |
| 218 | + # TODO: Example of __attr__ at module level. |
| 219 | + |
| 220 | + |
| 221 | + I request to share your views on this post. If you think I have missed any |
| 222 | + important point, or something is confusing I request you to write me at |
| 223 | + [jaysinhp@gmail.com](mailto:jaysinhp@gmail.com). I will be happy to find |
| 224 | + improvements on me. Thanks for reading :) |
0 commit comments