Descriptor pattern : trouble with property and instance attribute - python-3.x

I have implemented the following descriptor class.
I want to follow Player instances attribute credit.
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
class SignalDescriptor(object):
subscriptions = {}
#classmethod
def warn_me(cls, obj, attr, callback):
cls.subscriptions.setdefault(obj, {}).setdefault(attr,
set()).add(callback)
def __init__(self, name, value_init=None):
self.name = name
self.value = value_init
def __get__(self, obj, objtype):
for callback in self.subscriptions.get(obj, {}).get(self.name, ()):
callback('get', obj, self.name, self.value)
return self.value
def __set__(self, obj, value):
for callback in self.subscriptions.get(obj, {}).get(self.name, ()):
callback('set', obj, self.name, self.value, value)
self.value = value
class Player(object):
credits = SignalDescriptor("credits", 0)
def monitor_credits(action, obj, attribut, current_value, new_value=None):
if action == 'set':
print("Credits have been changed:")
else:
print("Credits have been consulted:")
print(action, obj, attribut, current_value, new_value)
MY PROBLEM IS :
1-how to follow multiple instances (ie j1.credits, j2.credits,j3.credits)
I dont know how to re-write my pattern to survey instance attributes, i have here only class attribute survey.
2-How to survey property with my pattern:
Lets look another example:
I dont care about Width or Height change, only surface matters : how to syntax my descriptor pattern ,or my Shape class to accept it,in thise case ?
class Shape():
def __init__(self, Width=1, Height=1):
self.Width = Width
self.Height = Height
#property
def surface(self):
return self.Width * self.Height
rect1 = Shape(3, 4)
rect2 = Shape(4, 3)

Related

Purpose of super() when class does not inherit

I have found a code in realpython.com about python super() and I don't understand what is the purpose of the super() in Rectangle and Triangle init method if both classes have no parent (don't inherit).
class Rectangle:
def __init__(self, length, width, **kwargs):
self.length = length
self.width = width
super().__init__(**kwargs)
def area(self):
return self.length * self.width
class Square(Rectangle):
def __init__(self, length, **kwargs):
super().__init__(length=length, width=length, **kwargs)
class Triangle:
def __init__(self, base, height, **kwargs):
self.base = base
self.height = height
super().__init__(**kwargs)
def tri_area(self):
return 0.5 * self.base * self.height
class RightPyramid(Square, Triangle):
...
This way, these classes can work with multiple-inheritance, and they may get ancestors unknown at coding time - the call to super, passing any unknown parameters they may have got, ensures they will play nice when used this way.
For example, let's suppose these shapes are used to represent the creation concrete 3D printing plastic objects.
class Print3D:
def __init__(self, *, filament="PLA", **kw):
self.filament=filament
print("Print3D part initialized")
super().__init__(**kwargs)
One now can do:
class PrintedSquare(Square, Print3D):
pass
mysquare = PrintedSquare(length=20, filament="PVC")
and everything will just work.

Factory design pattern using __init_subclass__ python3

I didn't find any info about the implementation of the factory design pattern using __init_subclass__ to register the product and the class. What do you think about?
https://peps.python.org/pep-0487/
class Shape:
product = None
shapes_classes = {}
def __init_subclass__(cls, **kwargs):
cls.shapes_classes[cls.product] = cls
#classmethod
def create_shape(cls, product, *args, **kwargs):
return cls.shapes_classes[product](*args, **kwargs)
def __str__(self):
return f'I am {self.__class__.__name__} shape'
def area(self):
raise NotImplemented
class Triangle(Shape):
product = 'triangle'
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
return self.height * self.base / 2
class Square(Shape):
product = 'square'
def __init__(self, base, ):
self.base = base
def area(self):
return self.base ** 2
#Usage:
Shape.shapes_classes
{'triangle': __main__.Triangle, 'square': __main__.Square}
triangle = Shape.create_shape(product='triangle',base=3,height=4)
square=Shape.create_shape(product='square',base=3)
print(triangle)
I am Triangle shape
print(square)
I am Square shape
triangle.area()
6.0
square.area()
9

Python3: Do subclasses of an abstract class inherit its magic methods?

Here's the tea: I'm writing a small Monopoly game using python. I've made this little class family to represent the bills. There's a base abstract class called Bill which inherits from the abc.ABC class.
Code:
from abc import ABC, abstractmethod
import colorama
colorama.init(autoreset=True, strip=True)
class Bill(ABC):
#Abstract Properties (must be overriden in subclasses)
#property
#abstractmethod
def count(self):
return 0
#property
#abstractmethod
def color(self): # colorama background color
return 0
#property
#abstractmethod
def worth(self): # integer representing the bill's worth
return 0
# Dunder methods (The same across class family)
def __add__(self, other):
return self.worth + other.worth
def __str__(self):
return f" {self.color} {self.worth}"
class One(Bill):
def __init__(self):
self.__count = 0
self.__color = "\033[0m"
self.__worth = 0
#super().init() ??
# Override Abstract Methods
#property
def count(self):
return self.__count
#count.setter
def count(self, amount):
self.__count += 1
#property
def worth(self):
return 1
#property
def color(self):
return colorama.Back.WHITE
My question is whether my subclasses will inherit the Bill class's dunder methods.
And if not, do I need to include super().__init__() in the One class's __init__ method?

How can I access methods of a class that is passed as argument to another class in python

I want to create a class(say, LockedAttributes) to access(READ/WRITE) some attributes safely by multiple threads.I want to pass those attributes that I want to share as a list to the LockedAttributes class. Some of the list elements are itself class objects with it's own setter and getter.
How can i access those setter/getter from a LockedAttribute class obj?
My use of getattr() setattr() might be wrong.
sample code:
class Coord:
def __init__(self, x=0.0, y=0.0, z=0.0):
self.x = x
self.y = y
self.z = z
def set_coordinator(self, x, y, z):
self.x = x
self.y = y
self.z = z
def get_coordinator(self):
return self.x, self.y, self.z
class LockedAttributes(object):
def __init__(self, obj):
self.__obj = obj
self.__lock = RLock()
def getmyPosition(self):
with self.__lock:
return self.__obj[0]
def getmySpeed(self):
with self.__lock:
return self.__obj[1]
def getcolPosition(self):
with self.__lock:
return self.__obj[2]
def getDistfromCol(self):
with self.__lock:
getattr(self, self.__obj[3])
def setDistfromCol(self, value):
with self.__lock:
setattr(self, self.__obj[3], value)
def getcolactivationFlag(self):
with self.__lock:
getattr(self, self.__obj[4])
def setcolactivationFlag(self, value):
with self.__lock:
setattr(self, self.__obj[3], value)
class OBU():
def __init__(self):
pos = Coord()
speed = Coord()
colpos = Coord()
distance_from_accident = 0.0
Flag = False
self.shared_attributes = LockedAttributes([ pos, speed, colpos, distance_from_accident, Flag])
mypos= self.shared_attributes.getmyPosition()
mypos.get_coordinator() # Not workinh
The __init__ method of the LockedAttributes class should take an argument so that you can actually pass a list object to it.
Change:
class LockedAttributes(object):
def __init__(self):
self.__obj = object
self.__lock = RLock()
To:
class LockedAttributes(object):
def __init__(self, obj):
self.__obj = obj
self.__lock = RLock()

Override abstract setter of property in Python 3

What is the simplest / most pythonic way to override only the setter of an abstract property in Python 3? Variant 3 seems to mean the least effort for the derived class implementor. Is it correct? Does it have disadvantages?
import abc
class A1(metaclass=abc.ABCMeta):
def __init__(self, x, **kwargs):
super().__init__(**kwargs)
self._x = x
#property
def x(self):
return self._x
#x.setter
#abc.abstractmethod
def x(self, value):
self._x = value
class B1(A1):
#property
def x(self):
return super().x
#x.setter
def x(self, value):
print("B1 setter")
super(B1, self.__class__).x.fset(self, value)
b1 = B1(x=1)
b1.x = 3
print(b1.x)
class A2(metaclass=abc.ABCMeta):
def __init__(self, x, **kwargs):
super().__init__(**kwargs)
self._x = x
#abc.abstractmethod
def _get_x(self):
return self._x
#abc.abstractmethod
def _set_x(self, value):
self._x = value
x = property(_get_x, _set_x)
class B2(A2):
def _get_x(self):
return super()._get_x()
def _set_x(self, value):
print("B2 setter")
super()._set_x(value)
x = property(_get_x, _set_x)
b2 = B2(x=1)
b2.x = 3
print(b2.x)
class A3(metaclass=abc.ABCMeta):
def __init__(self, x, **kwargs):
super().__init__(**kwargs)
self._x = x
def _get_x(self):
return self._x
#abc.abstractmethod
def _set_x(self, value):
self._x = value
x = property(
lambda self: self._get_x(),
lambda self, value: self._set_x(value))
class B3(A3):
def _set_x(self, value):
print("B3 setter")
super()._set_x(value)
b3 = B3(x=1)
b3.x = 3
print(b3.x)
So, yes, you listed a lot of ways in there - and although the one that requires more code is your variant 3, the most straighforard, least surprising way to do it is your variant 1 -
It just works, and is perfectly readable, no surprises - and there seems to be no simpler way than calling fget explicitly there.

Resources