Passing values to class - python

I have this abstract class in Python:
class TransactionIdsGenerator(object):
def getId(self):
raise NotImplementedError
And this class that implements:
class TransactionIdsGeneratorGeneric(TransactionIdsGenerator):
INI_FILE = '/platpy/inifiles/postgres_config.ini'
__dbManager = None
def __init__(self):
TransactionIdsGenerator.__init__(self)
def getId(self):
_ret = None
_oDbManager = self.__getDbManager()
if _oDbManager.execQuery("select nextval('send_99_seq');"):
_row = _oDbManager.fetchOne()
if _row is not None:
_ret = _row[0]
return _ret
def __getDbManager(self):
if self.__dbManager is None:
self.__dbManager = PostgresManager(iniFile=self.INI_FILE)
return self.__dbManager
And in other file i have the instance of the class:
def __getTransactionIdsGenerator(self, operatorId):
_ret = TransactionIdsGeneratorGeneric()
return _ret
Is some way to pass the varibale operatorId to the instance, so i can use in the method getId in the class?
Thanks!

You just need to pass it as an argument to __init__. (Note that in your current code, you don't even need to define TransactionIdsGeneratorGeneric.__init__, since the only thing it does is call the parent's __init__.)
class TransactionIdsGeneratorGeneric(TransactionIdsGenerator):
INI_FILE = '/platpy/inifiles/postgres_config.ini'
__dbManager = None
def __init__(self, opid):
TransactionIdsGenerator.__init__(self)
self.opid = opid
Then when you instantiate the class:
def __getTransactionIdsGenerator(self, operatorId):
_ret = TransactionIdsGeneratorGeneric(operatorId)
return _ret
The key is that the child class's __init__ doesn't need to have the exact same signature as the parent's, as long as you make sure the correct arguments are passed to the parent when you call it. This isn't entirely true if you are making use of super, but since you aren't, I'll ignore that issue. :)

Related

How to use class property as a default parameter in Python?

I want to use class properties as standard (as when the user don't give any data then it has a default value) parameters to the same class methods.
class Class:
def __init__(self):
self.property = True
def method(self, parameter = False):
if not parameter:
parameter = self.property
return parameter
c = Class()
print(c.method())
print(c.method("False"))
>>>True
>>>False
The code above will work, but it feels messy, is there a more smart and concise way to do so?
If you are really hard-coding the default in __init__, you would be better off (ab)using a class attribute as the default.
class Class:
_param_default = True
def method(self, parameter=_param_default):
return parameter
del _param_default # Optional, but it's not really a class attribute
If this really should have an instance-specific default, you can't really make it any shorter. The method is defined before the instance is created, so you need to make the check at runtime.
class Class:
_sentinel = object()
def __init__(self):
self.property = True
def method(self, parameter=_sentinel):
if parameter is _sentinel:
parameter = self.property
return parameter
None is the more conventional sentinel, and you can use that in place of _sentinel if None isn't otherwise a valid argument to method.
I can't think at something more concise than this:
class Class:
def __init__(self):
self.property = True
def method(self, parameter=0):
return self.property if not parameter else parameter
I think this is the simplest way to do it:
class Class:
property = True
def method(self, parameter = 0):
if not parameter:
parameter = Class().property
return parameter
print(Class().method())
print(Class().method("False"))

How to have the same updated value of a Parent class be passed down to a inner class?

I need to access the value of an attribute defined at the parent class inside an inner class, here's the code:
class main(object):
def __init__(self):
self.session_id = None
self.devices = self.Devices(self.session_id)
class Devices(object):
def __init__(self, session_id):
self.session_id = session_id
And here's how I would like to use it:
>>> m = main()
>>> m.session_id = 1
>>> m.session_id
1
>>> m.devices.session_id
>>>
My expectation is that m.devices.session_id will always have the exact same value as m.session_id. I understand that at this point when I instantiate the inner class the session_id value is passed down as None because that's how it was initiated but I'm not sure how I can keep both values the same without doing something very ugly like:
m.devices.session_id = m.session_id
outside the class code.
How can I accomplish that inside the class itself ?
The other answer works, but I think this is a better design: lose the nested class, and add a getter on the device object to lookup a backref:
class Main(object):
def __init__(self):
self.session_id = None
self.devices = Devices(main_obj=self)
class Devices(object):
def __init__(self, main_obj):
self.main_obj = main_obj
...
#property
def session_id(self):
return self.main_obj.session_id
The difference here is that you're not storing the same data twice, so they can not get out of sync - there is only one "source of truth" for the session_id (on main object).
In the earlier answer, the data is actually stored in two different namespaces and will get out of sync as easily as m.devices.session_id = 123.
You can do it like this:
class main(object):
def __init__(self):
self._session_id = None
self.devices = self.Devices(self._session_id)
#property
def session_id(self):
return self._session_id
#session_id.setter
def session_id(self, value):
self._session_id = self.devices.session_id = value
class Devices(object):
def __init__(self, session_id):
self.session_id = session_id

Override function decorator argument

I've a base class and a child class. Base class has a class variable which is passed to decorator. Now, when I inherit Base into child, and change the variable value, the decorator does not take the over-ride class variable value.
Here's the code:-
class Base():
variable = None
#decorator(variable=variable)
def function(self):
pass
class Child(Base):
variable = 1
Without overriding the function again: How do I pass child class variable to the decorator?
The comment from deceze already explained why this is not getting reflected on the sub classes.
One workaround is, you can build the logic on the decorator side.
Ie, something like this.
def decorator(_func=None, *, variable):
def decorator_func(func):
def wrapper(self, *args, **kwargs):
variable_value = getattr(self.__class__, variable)
print(variable_value)
# You can use this value to do rest of the work.
return func(self, *args, **kwargs)
return wrapper
if _func is None:
return decorator_func
else:
return decorator_func(_func)
Also update the decorator syntax from #decorator(variable=variable) to #decorator(variable='variable')
class Base:
variable = None
#decorator(variable='variable')
def function(self):
pass
DEMO
b = Base()
b.function() # This will print `None`.
Lets try with the subclass
b = Child()
b.function() # This will print `1`.

Can class instances be accessed via an index in python?

Consider for example that we have a class 'Agent' as below:
class Agent:
def __init__(self, number):
self.position = []
self.number = number
for i in range(number):
self.position.append([0, 0])
I can make an instance of the class by:
agent = Agent(10)
and then access the i'th agent's position by:
agent.position[i]
However, this does not seem elegant enough and to me it's a bit counter-intuitive. Instead I want to index the class instance itself. For example:
pos_i = agent[i].position
which should return the same answer as the one-line code above. Is there a way to accomplish this?
If you want to do that, you just need a class-level container, with all instances.
Since your positions, given your example, are created in an arbitrary order, I'd suggest using a dictionary.
You can just fill the class-level "position" dictionary. You could then just implement the __getitem__ method to retrieve elements from this dictionary:
class Agent:
position = {}
def __new__(cls, pos):
if pos in cls.position:
return cls.position[pos]
instance = super().__new__(cls)
cls.position[pos] = instance
return instance
def __getitem__(self, item):
return self.position[pos]
This, however, will only allow you to retrieve an instance given the position from an instance - i.e.:
agent_5 = Agent(5)
agent_10 = agent_5[10]
would work, but not:
agent_10 = Agent[10]
If you want that, you have to use a custom metaclass, and put the __getitem__ method there:
class MAgent(type):
def __getitem__(cls, item):
return cls.position[pos]
class Agent(metaclass=MAgent):
position = {}
def __new__(cls, pos):
if pos in cls.position:
return cls.position[pos]
instance = super().__new__(cls)
cls.position[pos] = instance
return instance
If you want to overload the indexing operator just overload the __getitem__ method in the class.
class Agent:
def __getitem__(self, key):
return self.position[key]
>>> myobj = MyClass()
>>> myobj[3]

Using base class for all object creation

A senior dev would like me to implement Object Oriented Programming in Python where we instantiate all object creation using the Base class. It does not sit well with me because there are abstract methods in the Base class that the Derived class has to implement. His reasoning to use the Base class only as a way to instantiate our objects is so that when we iterate through a list of our objects, we can access its variables and methods the same way. Since each derived object of the base class has more attributes instantiated than the Base class, he suggests the init function to take in *args and **kwargs as part of the arguments.
Is this a good way to go about doing it? If not, can you help suggest a better alternative?
Here's a simple example of the implementation.
import abc
class Base(metaclass = abc.ABCMeta):
def __init__(self, reqarg1, reqarg2, **kwargs):
self.reqarg1 = reqarg1
self.reqarg2 = reqarg2
self.optarg1 = kwargs.get("argFromDerivedA", 0.123)
self.optarg2 = kwargs.get("argFromDerivedB", False)
self.dict = self.create_dict()
#abstractmethod
def create_dict(self):
pass
def get_subset_list(self, id):
return [item for item in self.dict.values() if item.id == id]
def __iter__(self):
for item in self.dict.values():
yield item
raise StopIteration()
class Derived_A(Base):
def __init__(self, regarg1, regarg2, optarg1):
super().__init__(regarg1, regarg2, optarg1)
def create_dict(self):
# some implementation
return dict
class Derived_B(Base):
def __init__(self, regarg1, regarg2, optarg2):
super().__init__(regarg1, regarg2, optarg2)
def create_dict(self):
# some implementation
return dict
EDIT: Just to make it clear, I don't quite know how to handle the abstractmethod in the base class properly as the senior dev would like to use it as follows:
def main():
b = Base(100, 200)
for i in get_subset_list(30):
print(i)
But dict in the Base class is not defined because it is defined in the derived classes and therefore will output the following error:
NameError: name 'abstractmethod' is not defined
My suggestion is that you use a factory class method in the Base class. You would only have to be able to determine the Derived class that you would need to return depending on the supplied input. I'll copy an implementation that assumes that you wanted a Derived_A if you supply the keyword optarg1, and Derived_B if you supply the keyword optarg2. Of course, this is completely artificial and you should change it to suit your needs.
import abc
class Base(metaclass = abc.ABCMeta):
#classmethod
def factory(cls,reqarg1,reqarg2,**kwargs):
if 'optarg1' in kwargs.keys():
return Derived_A(reqarg1=reqarg1,reqarg2=reqarg2,optarg1=kwargs['optarg1'])
elif 'optarg2' in kwargs.keys():
return Derived_B(reqarg1=reqarg1,reqarg2=reqarg2,optarg2=kwargs['optarg2'])
else:
raise ValueError('Could not determine Derived class from input')
def __init__(self, reqarg1, reqarg2, optarg1=0.123, optarg2=False):
self.reqarg1 = reqarg1
self.reqarg2 = reqarg2
self.optarg1 = optarg1
self.optarg2 = optarg2
self.dict = self.create_dict()
#abc.abstractmethod
def create_dict(self):
pass
def get_subset_list(self, id):
return [item for item in self.dict.values() if item.id == id]
def __iter__(self):
for item in self.dict.values():
yield item
class Derived_A(Base):
def __init__(self, reqarg1, reqarg2, optarg1):
super().__init__(reqarg1, reqarg2, optarg1=optarg1)
def create_dict(self):
# some implementation
dict = {'instanceOf':'Derived_A'}
return dict
class Derived_B(Base):
def __init__(self, reqarg1, reqarg2, optarg2):
super().__init__(reqarg1, reqarg2, optarg2=optarg2)
def create_dict(self):
# some implementation
dict = {'instanceOf':'Derived_B'}
return dict
This will allow you to always create a Derived_X class instance that will have the create_dict non-abstract method defined for when you __init__ it.
In [2]: b = Base.factory(100, 200)
ValueError: Could not determine Derived class from input
In [3]: b = Base.factory(100, 200, optarg1=1213.12)
In [4]: print(b.dict)
{'instanceOf': 'Derived_A'}
In [5]: b = Base.factory(100, 200, optarg2=True)
In [6]: print(b.dict)
{'instanceOf': 'Derived_B'}
Moreover, you can have more than one factory method. Look here for a short tutorial.
You don't have to use keyword arguments at all; just define the variables with their default value in the parameters section of the function, and send only the parameters you want to send from the derived classes.
Note that parameters with a default value doesn't have to be supplied - that way you can have a function with a ranging number of arguments (where the arguments are unique, and can not be treated as a list).
Here is a partial example (taken from your code):
import abc
class Base(metaclass = abc.ABCMeta):
def __init__(self, reqarg1, reqarg2, optarg1 = 0.123, optarg2 = False):
self.reqarg1, self.reqarg2 = reqarg1, reqarg2
self.optarg1, self.optarg2 = optarg1, optarg2
...
class Derived_A(Base):
def __init__(self, regarg1, regarg2, optarg1):
super().__init__(regarg1, regarg2, optarg1=optarg1)
...
class Derived_B(Base):
def __init__(self, regarg1, regarg2, optarg2):
super().__init__(regarg1, regarg2, optarg2=optarg2)
...
EDIT: As the question update, I would give just a small note - abstract method is there to make sure that a mixed list of some derived Base objects can call the same method. Base object itself can not call this method - it is abstract to the base class, and is just there so we can make sure every derived instance will have to implement this method.

Categories