Allow object access to its owning object's attribute - python

I've got a whole bunch of classes that are effectively algorithms, and they all inherit from a Mechanism class. I then have a MechanismStack class which holds a list of a bunch of these algorithm classes, they are all interchangeable/modular - i.e. output of Mechanism1.encode() goes into Mechanism2.encode() as the input etc. (effectively a queue of functions).
A couple of these classes produce extra data than just the output. I want to store this extra data in the MechanismStack class (which is also an object - there are multiple different stacks comprised of different algorithms)
class MechanismStack:
self.stack = [Mechanism1(), Mechanism2(), Mechanism3()]
self.attribute = list()
def encode(self, input):
#process input through self.stack Mechanisms
class Mechanism1(Mechanism):
def function(self, input):
#code
owningMechanismStack.attribute = ['some', 'list']
myStack = MechanismStack()
myStack.encode('myInputString')

Add the owning MechanismStack as a property of Mechanism, which you supply when calling the constructor.
class Mechanism:
def __init__(self, owner):
this.owningMechanismStack = owner
class MechanismStack:
self.stack = [Mechanism1(self), Mechanism2(self), Mechanism3(self)]
...

Related

Return a custom value when a class method is accessed as an attribute, but still allow for it to perform a computation when called?

Specifically, I would want MyClass.my_method to be used for lookup of a value in the class dictionary, but MyClass.my_method() to be a method that accepts arguments and performs a computation to update an attribute in MyClass and then returns MyClass with all its attributes (including the updated one).
I am thinking that this might be doable with Python's descriptors (maybe overriding __get__ or __call__), but I can't figure out how this would look. I understand that the behavior might be confusing, but I am interested if it is possible (and if there are any other major caveats).
I have seen that you can do something similar for classes and functions by overriding __repr__, but I can't find a similar way for a method within a class. My returned value will also not always be a string, which seems to prohibit the __repr__-based approaches mentioned in these two questions:
Possible to change a function's repr in python?
How to create a custom string representation for a class object?
Thank you Joel for the minimal implementation. I found that the remaining problem is the lack of initialization of the parent, since I did not find a generic way of initializing it, I need to check for attributes in the case of list/dict, and add the initialization values to the parent accordingly.
This addition to the code should make it work for lists/dicts:
def classFactory(parent, init_val, target):
class modifierClass(parent):
def __init__(self, init_val):
super().__init__()
dict_attr = getattr(parent, "update", None)
list_attr = getattr(parent, "extend", None)
if callable(dict_attr): # parent is dict
self.update(init_val)
elif callable(list_attr): # parent is list
self.extend(init_val)
self.target = target
def __call__(self, *args):
self.target.__init__(*args)
return modifierClass(init_val)
class myClass:
def __init__(self, init_val=''):
self.method = classFactory(init_val.__class__, init_val, self)
Unfortunately, we need to add case by case, but this works as intended.
A slightly less verbose way to write the above is the following:
def classFactory(parent, init_val, target):
class modifierClass(parent):
def __init__(self, init_val):
if isinstance(init_val, list):
self.extend(init_val)
elif isinstance(init_val, dict):
self.update(init_val)
self.target = target
def __call__(self, *args):
self.target.__init__(*args)
return modifierClass(init_val)
class myClass:
def __init__(self, init_val=''):
self.method = classFactory(init_val.__class__, init_val, self)
As jasonharper commented,
MyClass.my_method() works by looking up MyClass.my_method, and then attempting to call that object. So the result of MyClass.my_method cannot be a plain string, int, or other common data type [...]
The trouble comes specifically from reusing the same name for this two properties, which is very confusing just as you said. So, don't do it.
But for the sole interest of it you could try to proxy the value of the property with an object that would return the original MyClass instance when called, use an actual setter to perform any computation you wanted, and also forward arbitrary attributes to the proxied value.
class MyClass:
_my_method = whatever
#property
def my_method(self):
my_class = self
class Proxy:
def __init__(self, value):
self.__proxied = value
def __call__(self, value):
my_class.my_method = value
return my_class
def __getattr__(self, name):
return getattr(self.__proxied, name)
def __str__(self):
return str(self.__proxied)
def __repr__(self):
return repr(self.__proxied)
return Proxy(self._my_method)
#my_method.setter
def my_method(self, value):
# your computations
self._my_method = value
a = MyClass()
b = a.my_method('do not do this at home')
a is b
# True
a.my_method.split(' ')
# ['do', 'not', 'do', 'this', 'at', 'home']
And today, duck typing will abuse you, forcing you to delegate all kinds of magic methods to the proxied value in the proxy class, until the poor codebase where you want to inject this is satisfied with how those values quack.
This is a minimal implementation of Guillherme's answer that updates the method instead of a separate modifiable parameter:
def classFactory(parent, init_val, target):
class modifierClass(parent):
def __init__(self, init_val):
self.target = target
def __call__(self, *args):
self.target.__init__(*args)
return modifierClass(init_val)
class myClass:
def __init__(self, init_val=''):
self.method = classFactory(init_val.__class__, init_val, self)
This and the original answer both work well for single values, but it seems like lists and dictionaries are returned as empty instead of with the expected values and I am not sure why so help is appreciated here:

How to access attribute of object from another object's method, which is one of attributes in Python?

I would like to know if it's possible, and if yes, how to access attribute(s) of a "super" class instance, when having composition implemented.
Example provided below is only to provide idea here and setup common ground on further explanations.
I want to have access to "id" attribute for an instance of MiniVan directly from object "door" (type DoorElement).
My Code
class Car:
def __init__(self, _id):
self.id = _id
class CarElement:
def __init__(self, name):
self.name = name
def get_car_id(self):
# Body which will access value of attribute "id"
return car_id
class MiniVan(Car):
def __init__(self, _id):
super(MiniVan, self).__init__(_id)
self.door = DoorElement('door')
self.engine = EngineElement('engine')
class DoorElement(CarElement):
def __init__(self, name):
super(DoorElement, self).__init__(name)
class EngineElement(CarElement):
def __init__(self, name):
super(EngineElement, self).__init__(name)
def main():
mini_van = MiniVan(123)
id_from_door = mini_van.door.get_car_id()
id_from_engine = mini_van.engine.get_car_id()
print(id_from_door) # Expected output 123
print(id_from_engine) # Expected output 123
if __name__ == '__main__':
main()
Expected:
Printed out twice "123"
What I've tried:
Passing required attribute during creating object
I know that I could just define init method with passing "car_id" but for some reasons I would love to avoid it if possible. If not, I would propably just go for it.
to set class attribute, and then call it from CarElement class within classmethod e.g.:
#classmethod
def get_id(cls):
return Car.id
But issue with this solution is that, I can have many child-classes for Car class (MiniVan, Truck, etc.) and I want have it still working.
Trying to use descriptor
def __get__(self, instance, owner):
return instance.id
But I could understand it wrong, and actually getter (as far as I understand clean code) should return instance of a class and not any attribute.
Additional Info
I will ALWAYS use CarElement (or child classes) instances as attributes of instance of Car (or child classes) instances - different usage will be treated as use-error
There can be a lot of different child classes of Car class, but always within inheritance way ( Car <- RacingCar(Car) <- FormulaOneCar(RacingCar) ) but no composition
In order for your code to work, you would have to initialize all CarElement-s with car_id. Currently, the error you are getting comes from lack of such a variable in the scope of the method. My idea of a change is this:
class CarElement:
def __init__(self, name, car_id):
self.name = name
self.car_id = car_id
def get_car_id(self):
# Body which will access value of attribute id
return self.car_id
I can't see any other magic way.

How to initialise class attributes?

I currently have the following two ways:
class Venue:
store = Database.store()
ids = [vid for vid in store.find(Venue.id, Venue.type == "Y")]
def __init__(self):
self.a = 1
self.b = 2
OR
class Venue:
#classmethod
def set_venue_ids(cls):
store = Database.store()
cls.ids = [vid for vid in store.find(Venue.id, Venue.type == "Y")]
def __init__(self):
self.a = 1
self.b = 2
And before using/instantiating the class I would call:
Venue.set_venue_ids()
What would be the correct way of achieving this?
If it's the first way, what would I do if the instantiation of the attribute required more complex logic that could be done more simply through the use of a function?
Or is there an entirely different way to structure my code to accomplish what I'm trying to do?
From a purely technical POV, a class is an instance of its metaclass so the metaclass initializer is an obvious candidate for class attributes initialization (at least when you have anything a bit complex).
Now given the canonical lifetime of a class object (usually the whole process), I would definitly not use an attribute here - if anyone adds or removes venues from your database while your process is running, your ids attributes will get out of sync. Why don't you use a classmethod instead to make sure your data are always have up to date ?
Oh and yes, another way to construct your Venue.ids (or any other class attribute requiring non-trivial code) without having complex code at the class top-level polluthing the class namespace (did you noticed that in your first example store becomes a class attributes too, as well as vid if using Python 2.x ?) is to put the code in a plain function and call that function from within your class statement's body, ie:
def list_venue_ids():
store = Database.store()
# I assume `store.find()` returns some iterator (not a `list`)
# if it does return a list, you could just
# `return store.find(...)`.
return list(store.find(Venue.id, Venue.type == "Y"))
class Venue(object):
ids = list_venue_ids()
def __init__(self):
self.a = 1
self.b = 2

Is it possible to monitor a list (or mutable sequence) for when a member of the list is modified?

Say I have a very simple data type:
class SimpleObject:
def __init__(self, property):
self.property = property
def update_property(self, value):
self.property = value
And I a special kind of list to store the data type:
class SimpleList(collections.MutableSequence):
def update_useful_property_of_list(self, value):
self.useful_property_of_list = value
And I store them:
simple1 = SimpleObject(1)
simple2 = SimpleObject(2)
simple_list = SimpleList([simple1, simple2])
Is there any way for the SimpleList object to know when one of the properties of its members changes? For example, how can I get simple_list to execute self.update_useful_property_of_list() when something like this happens:
simple1.update_property(3)
As noted in the comments, you are looking for the Observer design pattern. Simplest, way to do it in your example:
class SimpleObject:
def __init__(self, property, propertyChangeObserver = None):
self.property = property
self.propertyChangeObserver = propertyChangeObserver
def registerPropertyChangeObserver(self, propertyChangeObserver):
self.propertyChangeObserver = propertyChangeObserver
def update_property(self, value):
self.property = value
if self.propertyChangeObserver:
self.propertyChangeObserver.simpleObjectPropertyChanged(self)
and:
class SimpleList(collections.MutableSequence):
def __init__(self, collection):
super(SimpleList, self).__init__(collection)
for e in collection:
e.registerPropertyChangeObserver(self)
def simpleObjectPropertyChanged(self, simpleObject):
pass # react to simpleObject.property being changed
Because you've called your property "property" it's hard to demonstrate low coupling here :) I've called the method simpleObjectPropertyChanged for clarity, but in fact, SimpleList doesn't have to know that it stores SimpleObject instances - it only needs to know that they are observable instances. In a similar manner, SimpleObject doesn't know about SimpleList - it only knows about some class that needs to observe its state (an observer - hence the name of the pattern).

Python - Getting subclass from input. Do I have to write a separate function?

I'm working in Python 2.7.8. What follows is a slight variant of the problem I'm working on.
I have a large number of custom classes that I've written where the inheritance is like a tree. The behavior is well encapsulated by the following example:
import random
class Animal(object):
def __init__(self, name):
self.name = name
self.can_own_pets = False #most Animals cannot own pets
self.get_features()
def give_pet(self, pet):
if not self.can_own_pets:
print(self.name+' cannot own a pet!')
else:
self.pets.append(pet)
def is_hungry(self):
return random.choice([True, False])
def get_features(self):
"""
In some classes, get features will be a function
that uses self.name to extract features.
In my problem, the features are extracted
with regular expressions that are determined by
by the class.
"""
pass
class Human(Animal):
def __init__(self, name):
super(Human, self).__init__(name)
self.can_own_pets = True
self.pets = []
class Dog(Animal):
def __init__(self, name):
super(Dog, self).__init__(name)
def bark(self):
print 'WOOF'
def get_features(self):
if 'chihuahua' in self.name:
self.is_annoying = True
elif 'corgi' in self.name:
self.adorable = True
My program needs to take in a large number of animals and delegate them to the correct classes -- I need the correct attributes and methods. What I would like to do is modify the Animal constructor so that if the name argument is something like "Finn the Dog" or "Jake the Human", it (the constructor) returns an instance of the class "Dog" or "Human", complete with the appropriate methods and attributes. Now, I know that I could easily write a function that takes a string and class as arguments, constructs a dictionary where the keys are the names of the subclasses of the given class, looks up the element of the dictionary that is contained in the string, and returns an object of that class. My question is whether or not there is a way to code this into the Animal class itself, which seems more elegant to me (as well as easier to maintain).
Here's an implementation --
def _get_all_subclasses(cls):
for scls in cls.__subclasses__():
yield scls
for scls in _get_all_subclasses(scls):
yield scls
class Animal(object):
#staticmethod
def from_string(s):
for cls in _get_all_subclasses(Animal):
# Somehow pick the class based on the string... This is a really simple example...
if cls.__name__ in s:
return cls()
raise ValueError('Bummer. Animal has not been discovered.')
class Dog(Animal):
pass
class Cat(Animal):
pass
class Lion(Cat):
pass
print Animal.from_string('is a Dog')
print Animal.from_string('is a Cat')
print Animal.from_string('Lions!!!')
print Animal.from_string('Lockness Monster')
There are limitations here
All of the constructors need to be pretty much the same which means that Cat.__init__ needs to basically do the same thing that Human.__init__ does.
After you create the instance, your code needs to have logic to handle Cat, Human, Dog, etc. In some cases that's Ok (e.g. the code really only cares that it is working with an Animal), but frequently it isn't (after all, Cats can walk on fences, but Humans can't).
Generally, the principle that I like to live by is to try to make the inputs to my functions permissive (is it a list or a tuple? Who cares! Duck Typing FTW!) but to try to have really well defined outputs. I think that this makes interfaces easier to use in the long haul and the code that I wrote above would probably not pass a code review if I was the reviewer :-).
To build upon mgilson's answer
You can override the __new__ method so that you can instantiate the classes like normal without a static method.
class Animal(object):
#classmethod
def _get_all_subclasses(cls):
for scls in cls.__subclasses__():
yield scls
for scls in scls._get_all_subclasses():
yield scls
def __new__(cls, name):
cls_ = cls
for subcls in Animal._get_all_subclasses():
if subcls.__name__ in name:
cls_ = subcls
break
instance = object.__new__(cls_)
if not issubclass(cls_, cls):
instance.__init__(name)
return instance

Categories

Resources