Skip to main content

A Python Package to make life ez for pythonistas

Project description

ez_life

The objective of ez_life is to make coding with Python easier by removing repetitive code while still maintaining the same level of functionality

Installation

pip install -U ez_life

param2attr

  • Here is a little sneak peak of what you can do with this package!
    • First consider this code block:
from ez_life import Param2attr

class Foo: 
	def __init__(self, param1 = None, param2 = None, param3 = None): 
		# This sux 
		self.param1 = param1 
		self.param2 = param2 
		self.param3 = param3
  • We can instead create a class that looks like this, using a property decorator to perform the param to attribute assignments
class Foo: 
	@Param2attr(exclude=None) 
	def __init__(self, param1 = None, param2 = None, param3 = None): 
		# this good, allows u to write other code here during initialization 
		pass
  • If you are interested to learn about the implementation or other features that param2attr supports, feel free to read the Param2attr documentation!

JTProperty

  • Ez_life can also be used to create "variable dependencies" using the @JTProperty decorator
    • It essentially builds upon the functionality that the @property decorator gives!

Understanding The Classic @property:

  • The concept of python's classic decorator @property is not difficult to learn, read this section if you want to learn it or get a refresher

Classic Setter and Getter Methods

  • First consider a classic class Square
    • A square has a 3 properties:
      • A length, an perimeter and an area
    • First we will code the length:
class Square: 
	def getLength(self): 
		return self._length # the underscore "_" in "_length" means that it is a "protected variable"

	def setLength(self, r): 
		if r <= 0: 
			raise ValueError("length should be greater than 0") 
		self._length = r
  • We can use this class as follows:
square = Square() # create a class instance
square.setLength(4) # sets self._length to 4
print(square.getLength()) # 4
square.setLength(-1) # raises a ValueError "length should be greater than 0"

Property Setter and Getter Methods Part 1

  • Python's inbuilt @property decorator allows setters and getters to be used in a much easier way:
class Square:
	@property 
	def length(self): # the setter method
		return self._length 

	@length.setter 
	def length(self, r): # the getter method 
		if r <= 0: 
			raise ValueError("length should be greater than 0") 
		self._length = r
  • The code below shows how to use the setter and getter methods for this class:
square = Square() # create a square instance
square.length = 4 # sets self._length to 4
print(square.length) # 4
square.length = -1 # raises a ValueError "length should be greater than 0"
  • Syntactically, the code above is much more pythonic, but the problem is that the setter must be called before the getter
    • The code below demonstrates this vulnerability:
square = Square() 
print(square.length) # raises an error

Property Setter and Getter Methods Part 2

  • The reason why an error is raised is because the length has not been set yet via the setter method
    • A solution to this could be achieved as follows:
class Square: 
	@property 
	def length(self): 
		if "_length" not in dir(self): # checks if self._length is an attribute yet 
			self.length = 1 # if not, call the setter method to set self._length to 1 
		return self._length 

	@length.setter 
	def length(self, r): 
		if r <= 0: 
			raise ValueError("length should be greater than 0") 
		self._length = r
  • Now we will not get an error when calling the getter before the setter, we instead get some default value
    • In this case the default value is 1
square = Square() 
print(square.length) # 1

Understanding The @JTProperty:

JTProperty Setter and Getter Methods

  • Obviously, the code with the @property decorator is Pythonic, however it is far from perfect
    • We can see that there are many lines of code already written for just the length setter and getter methods
  • Now we will demonstrate how the ez_life @JTProperty decorator can make the Square class above more concise
    • @JTProperty does this by abstracting away the self._length variable
# importing the JTProperty decorator from the ez_life module
from ez_life import JTProperty 

class Square: 
	@JTProperty() 
	def length(self): 
		return 1 

	@length.setter 
	def length(self, r): 
		if r <= 0: 
			raise ValueError("length should be greater than 0") 
		return r
  • For JTProperty we can call the setter before the getter method
square = Square() # create a class instance
square.length = 4 # sets self._length to 4
print(square.length) # 4
square.length = -1 # raises a ValueError "length should be greater than 0"
  • Or we can call the getter before the setter method
square = Square() 
print(square.length) # 1
  • As we can see, JTProperty offers the same functionality as @property but with less code!

Full Implementation of Square with JTProperty

  • Now that we have an understanding of JTProperty, we can fully implement the square class perimeter and area setter methods!
class Square: 
	@JTProperty() 
	def length(self): 
		return 1 

	@length.setter 
	def length(self, r): 
		if r <= 0: 
			raise ValueError("length should be greater than 0") 
		return r 

	@JTProperty() 
	def area(self): 
		return self.length ** 2 

	@JTProperty() 
	def perimeter(self): 
		return self.length * 4
  • We can call these methods as follows:
square = Square()
print(square.area) # (1 ** 2) => 1
print(square.perimeter) # (1 * 4) => 4

square.length = 2 # set length to 2

print(square.area) # 1 <= note that square.area stays the same even though square.length changed
print(square.perimeter) # 4 <= note that square.perimeter stays the same

# square.area = 10 # (note that this gives an error because no setter method is defined for area)

Full Implementation of Square with JTProperty part 2 (with dependencies)

  • Notice that square.area and square.perimeter do not update when square.length is changed to 2
    • To update square.area and square.perimeter when square.length is changed, a "dependency" list must be given to JTProperty for both square.area and square.perimeter methods:
class Square: 
	@JTProperty() 
	def length(self): 
		return 1 

	@length.setter 
	def length(self, r): 
		if r <= 0: 
			raise ValueError("length should be greater than 0") 
		return r 

	@JTProperty(deps = 'length') 
	def area(self): 
		return self.length ** 2 

	@JTProperty(deps = 'length') 
	def perimeter(self): 
		return self.length * 4
  • Now when changing square.length to some other value, both square.area and square.perimeter return their corresponding updated values when called
square = Square()
print(square.area) # (1 ** 2) => 1
print(square.perimeter) # (1 * 4) => 4

square.length = 2 # set length to 2

print(square.area) # (2 ** 2) => 4
print(square.perimeter) # (2 * 4) => 8
  • This concludes the introduction to some of the features that JTProperty supports!
  • Other features not covered here include:
    • Support for hierarchal classes
    • default and default type setters
    • Circular dependency graphs
  • If you are interested to learn about these other features and more, feel free to read the JTProperty documentation!

ez-life directory layout:

  • develop: the package containing all .ipynb dev files and converted .py files
    • param2attr.ipynb: dev notebook for automation of parameter creation to class object attributes
    • param2attr.py: param2attr.ipynb -> param2attr.py via Makefile
    • jt_property.ipynb: dev notebook for more writing dependency related code
    • jt_property.py: jt_property.ipynb -> jt_property.py via Makefile
  • ez_life: the package containing all converted .py files
  • .gitignore: for ignoring files when pushing and pulling
  • LICENSE: what u can and can't do with this repo
  • MAKEFILE: automated test cases and .ipynb to .py conversion
  • README: this file essentially
  • MANIFEST.in: Files to include in pip upload
  • build: automatically generated file for pip
  • dist: automatically generated file for pip
  • setup.py: contains setups for when uploading to pip
  • test*.py: test files for modules within ez_life

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ez-life-1.1.0.tar.gz (16.3 kB view hashes)

Uploaded Source

Built Distribution

ez_life-1.1.0-py3-none-any.whl (20.2 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page