I have 2 class (that are defined in two different package).
An A object as a "set" of B objects that all refer to the said A object.
Here is how it looks like :
the a.py :
from b import B
class A():
def __init__(self, data):
self.data = data
self.Bs = {}
def add_B(self, id, data_B):
self.Bs[id] = B(data_B, self)
the b.py :
class B():
def __init__(self, data, a_instance):
self.data = data
self.a = a_instance
so everything works preety good, but I'd like to hint python that the a_instance is indeed a class A object to have autocompletion in visual studio code.
At first i've tried to add from a import A and modify def __init__(self, data, a_instance : A): in the b.py file, but i've obviously got a circular import error
So I've been trying to use the typing package, and so added those lines to the a.py file :
from typing import NewType
A_type = NewType('A_type', A)
But I'm steel getting a circular import error.
Can Anyone explain me what I'm doing wrong ?
thanks for the help
PS: My classes actually have some complex methods and are defined in _a.py (resp. _b.py) and the __init__.py just import the class A and declare the A_type (resp. just import the class B)
Use
typing.TYPE_CHECKING, a variable that's never true at runtime
the string form of a type annotation to refer to a name that is not in scope at runtime:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from a import A
class B:
def __init__(self, data, a_instance: "A"):
...
However, if you can restructure your code in a way that avoids circular imports altogether, all the better.
You could try an abstract class with attributes of A and B, then implement each accordingly.
from collections.abc import abstractmethod, ABCMeta
class ABInerface(metaclass=ABCMeta):
#property
#abstractmethod
def data(self):
pass
#data.setter
#abstractmethod
def data(self, value):
pass
#property
#abstractmethod
def Bs(self):
pass
#Bs.setter
#abstractmethod
def Bs(self, value):
pass
#property
#abstractmethod
def a(self):
pass
#a.setter
#abstractmethod
def a(self, value):
pass
#abstractmethod
def add_B(self, id, data_B):
pass
Then, create each class by extending the Interface meta class.
class B(ABInerface):
def __init__(self, data, a_instance):
self.data = data
self.a = a_instance
class A(ABInerface):
def __init__(self, data):
self.data = data
def add_B(self, id, data_B):
self.Bs[_id] = B(data_B, self)
Related
I'm trying to mock a class in python with another class using unittest but the unittest.patch creates an instance from the mock class and replaces the original class with it. Here is the description
The Origin class is located in the file: src/libutil/util.py
class A:
def __init__(self) -> None:
self.a = self.g()
self.c = "parent"
def g(self):
return "HI from parent"
The mock class is located in the file tests/libraries/mocks/util.py
class B(A):
def __init__(self) -> None:
super().__init__()
def g(self):
return "Hi from child"
I'm mocking that using unittest as follows:
#pytest.fixture(scope="session", autouse=True)
def mock_util():
from tests.libraries.mocks.util import B
with mock.patch('libutil.util.A', new_callable=B, create=False) as util_mock:
yield util_mock
The problem is that the patch creates an instance from class B and replaces class A with it instead of replacing class A with class B itself. When I use a = libutil.util.A() that doesn't work and throws TypeError: 'B' object is not callable.
Can you help me in mocking class A with class B itself? Please note that the usage here is a simplified example.
I can't figure out the correct way to model this problem.
Here I give you a minimalistic version of my code:
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
class AreaCalculator():
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getArea(self):
pass
def compute(self):
self.getArea()
class PerimeterCalculator():
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getPerimeter(self):
pass
def compute(self):
self.getPerimeter()
class TriangleAreaCalculator(AreaCalculator):
def __init__(self):
AreaCalculator.__init__(self)
def getArea(self):
return area
class TrianglePerimeterCalculator(PerimeterCalculator):
def __init__(self):
PerimeterCalculator.__init__(self)
def getPerimeter(self):
return perimeter
a = TriangleAreaCalculator()
b = TrianglePerimeterCalculator()
Is there an elegant way to merge "TrianglePerimeterCalculator" and "TriangleAreaCalculator" classes into one, but keeping "PerimeterCalculator" and "AreaCalculator" separated?
[edit] As Kyle suggested in the comments, I can create a new class (let's call it "Triangle") that inherits from "PerimeterCalculator" and "AreaCalculator" at the same time, but what I want is to be able to tell a new instance of "Triangle" to behave as "PerimeterCalculator" or "AreaCalculator", but not both at the same time.
I think the "design pattern" you should use is multiple inheritance. Below is a modified version of your code demonstrating how do it (plus a few other changes to make it actually runnable and all classes new-style).
from abc import ABCMeta, abstractmethod
class AreaCalculator(object):
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getArea(self):
pass
def compute(self):
self.getArea()
class PerimeterCalculator(object):
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getPerimeter(self):
pass
def compute(self):
self.getPerimeter()
class TriangleAreaCalculator(AreaCalculator):
def __init__(self):
super(TriangleAreaCalculator, self).__init__()
def getArea(self):
print('TriangleAreaCalculator.getArea() called on instance of {}'.format(
self.__class__.__name__))
# return area
return 13
class TrianglePerimeterCalculator(PerimeterCalculator):
def __init__(self):
super(TrianglePerimeterCalculator, self).__init__()
def getPerimeter(self):
print('TrianglePerimeterCalculator.getPerimeter() called on instance of {}'.format(
self.__class__.__name__))
# return perimeter
return 42
class MergedCalculator(TriangleAreaCalculator, TrianglePerimeterCalculator):
def __init__(self):
super(MergedCalculator, self).__init__()
merged = MergedCalculator()
print('merged.getArea() -> {}'.format(merged.getArea()))
print('merged.getPerimeter() -> {}'.format(merged.getPerimeter()))
Output:
TriangleAreaCalculator.getArea() called on instance of MergedCalculator
merged.getArea() -> 13
TrianglePerimeterCalculator.getPerimeter() called on instance of MergedCalculator
merged.getPerimeter() -> 42
Here's another answer, following the editing and clarification of your question. It allows creation of a single Triangle instance that can behave like either an AreaCalculator or PerimeterCalculator, as needed.
This programming pattern is called "delegation" and is used where the responsibility for implementing a particular operation is handed off to a different object—in this case an internally held instance of some other class. A common way to do this in Python is by overriding the class's default __getattr__() method.
Since you've never responded to the comment under my other answer about exactly what it is that controls which behavior is used, I added a set_behavior() method to allow it to be specified explicitly.
from abc import ABCMeta, abstractmethod
class AreaCalculator:
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getArea(self):
pass
def compute(self):
return self.getArea()
class PerimeterCalculator:
__metaclass__ = ABCMeta
def __init__(self):
pass
#abstractmethod
def getPerimeter(self):
pass
def compute(self):
return self.getPerimeter()
class TriangleAreaCalculator(AreaCalculator):
def __init__(self):
super(TriangleAreaCalculator, self).__init__()
def getArea(self):
print('TriangleAreaCalculator.getArea() called')
area = 13
return area
class TrianglePerimeterCalculator(PerimeterCalculator):
def __init__(self):
super(TrianglePerimeterCalculator, self).__init__()
def getPerimeter(self):
print('TrianglePerimeterCalculator.getPerimeter() called')
perimeter = 42
return perimeter
class Triangle:
def __init__(self):
delegate_classes = TriangleAreaCalculator, TrianglePerimeterCalculator
# Map delegate classes to instances of themselves.
self._delegates = {delegate_class: delegate_class()
for delegate_class in delegate_classes}
self.set_behavior(TriangleAreaCalculator) # Set default delegate.
def __getattr__(self, attrname):
# Called only for attributes not defined by this class (or its bases).
# Retrieve attribute from current behavior delegate class instance.
return getattr(self._behavior, attrname)
def set_behavior(self, delegate_class):
try:
self._behavior = self._delegates[delegate_class]
except KeyError:
raise TypeError("{} isn't a valid {} behavior delegate class"
.format(delegate_class, self.__class__.__name__))
if __name__ == '__main__':
triangle = Triangle()
# Uses instance's default behavior.
print('triangle.compute() -> {}'.format(triangle.compute()))
triangle.set_behavior(TrianglePerimeterCalculator) # Change behavior.
print('triangle.compute() -> {}'.format(triangle.compute()))
Output:
TriangleAreaCalculator.getArea() called
triangle.compute() -> 13
TrianglePerimeterCalculator.getPerimeter() called
triangle.compute() -> 42
I figured it out myself, with inspiration on the commentas/answers of Kyle and martineau.
I can create a merged class "Triangle" as follows:
class Triangle():
def __init__(self):
pass
def getTriangleArea(self):
print 'Triangle area'
def getTrianglePerimeter(self):
print 'Triangle perimeter'
And then modify TriangleAreaCalculator and TrianglePerimeterCalculator as follows:
class TriangleAreaCalculator(AreaCalculator, Triangle):
def __init__(self):
TriangleCalculator.__init__(self)
AreaCalculator.__init__(self)
def getArea(self):
super(TriangleAreaCalculator, self).getTriangleArea()
class TrianglePerimeterCalculator(PerimeterCalculator, Triangle):
def __init__(self):
TriangleCalculator.__init__(self)
PerimeterCalculator.__init__(self)
def getPerimeter(self):
super(TrianglePerimeterCalculator, self).getTrianglePerimeter()
This way, I can create a new Triangle-like instance that behaves as "PerimeterCalculator" or "AreaCalculator" (but not both at the same time):
a = TriangleAreaCalculator()
b = TrianglePerimeterCalculator()
a.compute() # correctly prints "Triangle area"
b.compute() # correctly prints "Triangle perimeter"
I have the following class ClassA, for which I dynamically create a method returning string version of another method:
# module_a.py
class ClassA(object):
def width(self):
return 5
def height(self):
return 10
#classmethod
def add_str_method(cls, name):
method = getattr(cls, name)
def str_method(self):
return str(method(self))
setattr(cls, '{0}_str'.format(name), str_method)
for name in ['width', 'height']:
ClassA.add_str_method(name)
This part works perfectly fine as long as I don't subclass ClassA in a different module. But when I do, like in the example below, the dynamically added methods are not inherited.
# module_b.py
from module_a import ClassA
class ClassB(ClassA):
pass
What would be the proper way of adding methods dynamically such that they are automatically inherited by subclasses?
First you have to declare add_str_method as a #classmethod if you want to update the class A dynamically (not just an instance of A).
# file a.py
class A(object):
def __init__(self, a=5):
self._a = a
def a(self):
return self._a
#classmethod
def add_str_method(cls, name):
def str_method(self):
return str(getattr(self, name)())
setattr(cls, '{0}_str'.format(name), str_method)
for name in ['a']:
A.add_str_method(name)
In order to access the a method from A, and thus the variable _a attached to a particular instance, the str method has to be bounded to self, note this lines:
def str_method(self):
return str(getattr(self, name)())
Now, with this testing script it works as expected:
# file b.py
from a import A
class B(A):
pass
print(B(10).a_str()) # prints '10'
You'll have to add the procedure to the initialization (__init__) of classA:
class ClassA(object):
def __init__(self):
for name in ['width', 'height']:
self.add_str_method(name)
def width(self):
return 5
def height(self):
return 10
def add_str_method(cls, name):
method = getattr(self, name)
def str_method(self):
return str(method())
setattr(cls, '{0}_str'.format(name), str_method)
Now doing
from module_a import ClassA
class ClassB(ClassA):
pass
print(dir(ClassB))
Gives:
>>> ... 'height', 'width']
I try python introspection in some weird manner.
For example, I have Class LoggerManager which incapsulate pool of specific loggers classes for statistic. I know this is no standard way to do it, but I can't use mixins due to my object of class SpecificLogger is serializable to json in code and I really don't want to pass self.data throw params to init (in this case I need to rewrite many rows code and get problem with garbage in serialization again).
class LoggerManager(object):
def __init__(self):
self.data
self.b = SpecificLogger()
self.c = SpecificLogger2()
...
class SpecificLogger(LoggerGeneral):
def get_data(self):
global data #now I want get object from namespace object of LoggerManager, not really global
do_something_with_data(data)
I want behavior like this code with mixins:
import json
class A(object):
def __init__(self):
self.data = 'something'
def create_pool_of_specific_objects(self):
self.obj = B()
class B(A):
def __init__(self):
A.__init__(self)
def do_something_with_data(self):
print(self.data)
self.data = 'new_data'
print(self.data)
def save(self):
return json.dumps(self.__dict__, ensure_ascii=False)
def hack_save(self):
data_to_dumped = {x:y for x,y in self.__dict__.iteritems() if x != 'obj'}
return json.dumps(data_to_dumped, ensure_ascii=False)
b=B()
b.create_pool_of_specific_objects()
b.do_something_with_data()
b.save() #will raise exception due to we have all stuff from instance of class A there
b.hack_save() #will work but it is very ugly and unusable with runtime modify object of A class
Now I wrote code with GC, but using method get_objects I have some sort of overhead, is not it?
import json
import gc
class A(object):
def __init__(self):
self.data = 'something'
self.obj = B()
class B(object):
def __init__(self): pass
def do_something_with_data(self):
for obj in gc.get_objects(): #or even for obj in globals().values()
if isinstance(obj, A):
print(obj.data)
obj.data = 'new_data'
print(obj.data)
def save(self):
return json.dumps(self.__dict__, ensure_ascii=False)
a=A()
b=B()
b.do_something_with_data()
b.save() #will work
Any suggestion to do it with introspection and not inheritance and GC overhead? Maybe python save ref to namespace above and I can get A instance in friendly manner?
Ok, guyz. Correctly asked question includes right answer itself.
All I need is:
import inspect
def my_method(self):
parent_self = inspect.currentframe().f_back.f_locals['self']
do_something_with_parent_self(parent_self)
I am learning python and I am facing a dilemma:
from abc import ABCMeta, abstractproperty, abstractmethod
import jsocket
from acme.core import StatusCode, Direction
import acme.db as db
class ModuleThread(jsocket.ServerFactoryThread):
__metaclass__ = ABCMeta
#abstractproperty
def module_name(self):
pass
#abstractproperty
def _db_model(self):
pass
def __init__(self):
super(ModuleThread, self).__init__()
self.code = StatusCode.PENDING
self.status = None
def _get_config_for_domain(self, domain, direction):
# here I want to be sure that my db model is an instance
# of a pewee model
print self._db_model
class CheckMxThread(ModuleThread):
#property
def module_name(self):
return 'check_mx'
#property
def _db_model(self):
return db.ModMx
And the call
CheckMxThread()._get_config_for_domain('nocheck.mx', Direction.INCOMING)
I want to be sure that when using self._db_model I get an instance of Pewee Model, how should I handle this:
directly by using the top import like I've done
Injecting db package in the ModuleThread class and using later as self.db.ModMx in child classes ?
You can verify this by using isinstance:
#property
def _db_model(self):
if not instanceof(self, db.ModMx):
raise IOError('can not use this instance type')
This work with child inhertance, example:
>>> class A:
... pass
>>> class B(A):
... pass
>>> b = B()
>>> isinstance(b, A)
True