From 2cc490f3f27f84a2c74caaab6ee367835d042135 Mon Sep 17 00:00:00 2001 From: Brandon Rozek Date: Wed, 8 Apr 2020 19:05:28 -0400 Subject: [PATCH] New Posts --- content/blog/copydecorator.md | 48 +++++++++++++++++++++++++++++++ content/blog/pydataclass.md | 29 +++++++++++++++++++ content/blog/pygetset.md | 53 +++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 content/blog/copydecorator.md create mode 100644 content/blog/pydataclass.md create mode 100644 content/blog/pygetset.md diff --git a/content/blog/copydecorator.md b/content/blog/copydecorator.md new file mode 100644 index 0000000..88710e0 --- /dev/null +++ b/content/blog/copydecorator.md @@ -0,0 +1,48 @@ +--- +title: "Quick Python: Copy Decorator" +date: 2020-04-08T18:49:54-04:00 +draft: false +tags: ["python"] +--- + +If you want to guarantee that your function doesn't modify any of the references and don't mind paying a price in memory consumption, here is a decorator you can easily add to your functions. + +```python +from copy import deepcopy +def copy_arguments(func): + def wrapper(*args, **kwargs): + new_args = deepcopy(args) + new_kwargs = deepcopy(kwargs) + return func(*new_args, **new_kwargs) + return wrapper +``` + +Example usage: + +```python +@copy_arguments +def modify1(xs): + for i, _ in enumerate(xs): + xs[i] *= 2 +``` + +Comparison: + +```python +def modify2(xs): + for i, _ in enumerate(xs): + xs[i] *= 2 + +a = [1, 2, 3, 4, 5] +b = [1, 2, 3, 4, 5] +modify1(a) +modify2(a) +print(a) +print(b) +``` + +``` +[1, 2, 3, 4, 5] +[2, 4, 6, 8, 10] +``` + diff --git a/content/blog/pydataclass.md b/content/blog/pydataclass.md new file mode 100644 index 0000000..5e14f42 --- /dev/null +++ b/content/blog/pydataclass.md @@ -0,0 +1,29 @@ +--- +title: "Quick Python: Dataclasses" +date: 2020-04-08T18:59:48-04:00 +draft: false +tags: ["python"] +--- + +Python 3.7 and above have a feature called dataclasses. This allows us to reduce boilerplate code by removing the need to create a whole constructor and providing a sensible `__repr__` function. + +```python +from dataclasses import dataclass + +@dataclass +class Person: + name: str + age: int +``` + +Usage: + +```python +p = Person("Bob", 30) +print(p) +``` + +``` +Person(name='Bob', age=20) +``` + diff --git a/content/blog/pygetset.md b/content/blog/pygetset.md new file mode 100644 index 0000000..4479184 --- /dev/null +++ b/content/blog/pygetset.md @@ -0,0 +1,53 @@ +--- +title: "Quick Python: Getters and Setters" +date: 2020-04-08T18:15:21-04:00 +draft: false +tags: ["python"] +--- + +One of the hidden gems in Python classes are seamless getters and setters. I discovered this through the book [Effective Python by Brett Slatkin](https://effectivepython.com/). Though the example I'll use is different and shorter than the one he uses in his book. + +Let's create a class representing a person. The only information we're going to store is their age and we'll make it optional to provide it. + +```python +class Person: + def __init__(self, age=None): + self._age = None + @property + def age(self): + if self._age is None: + raise ValueError("age must be set before accessing it.") + return self._age + @age.setter + def age(self, age): + if age < 0: + raise ValueError("age must be at least zero.") + self._age = age +``` + +The second function in the class decorated by `@property` will be the getter function for the attribute `_age`. The name of the function will be what we expect the user to access it as. The setter is then decorated with `age.setter` where `age` is the name of the attribute. As such the name chosen in the getter function name, setter function name, and decorator must all match. + +Now let's try using it + +```python +bobby = Person() +bobby.age +``` + +``` +Traceback (most recent call last): + File "", line 1, in + File "/home/user/test.py", line 7, in age + raise ValueError("age must first be set before accessing it") +ValueError: age must first be set before accessing it +``` + +```python +bobby.age = 5 +bobby.age +``` + +``` +5 +``` +