Inheritance from class and override method - python

I have two classes, one inherits of the other. When I hesitate and re-establish the function get_commande_date I receive the following error:
TypeError: BooksCommande.get_commandes_date() missing 1 required positional argument: 'key'
This is my code:
class BaseCommande(ABC):
def __init__(self, list_of_commande: list) -> NoReturn:
if list_of_commande:
self.list_of_commande = list_of_commande
self.commande_date = None
self.comande_payed = None
self.commande_price = None
self.total_commandes = None
self.process_commande(list_of_commande)
super().__init__()
def get_commandes_date(self, list_of_commande):
return [commande['date_start'] for commande in list_of_commande]
def process_commande(self, list_of_commande):
self.commande_date = self.get_commandes_date(list_of_commande)
def my_dict(self):
return{
"commende_date": self.commande_date}
class BooksCommande(BaseCommande):
def __init__(self, list_of_commande: list) -> NoReturn:
super().__init__(list_of_commande)
self.commande_syplies = None
self.commande_books = None
self.process_books(list_of_commande)
def get_commandes_date(self, list_of_commande, key):
commande_date = []
for commande in list_of_commande:
cmd = {
'date_start': commande['date_start'],
'key': key,
'date_end': commande['date_end'],
}
commande_date.append(cmd)
return commande_date
def get_commande_books(self, books: list):
return 10
def process_books(self, list_of_commande):
self.books_list = self.get_commande_books(list_of_commande)
def my_dict2(self):
return{**super().my_dict(),
"books": self.books_list
}
commande_list = [{"date_start": "10/10/2021", "date_end": "12/15/2019"}]
print(BooksCommande(commande_list).my_dict2())
Is there a way to force BaseCommande to use the new redefined function or not? I really don't know how or from where to start.

The problem is you're attempting to change the number of arguments that get passed to the get_commandes_date() method — something that cannot be done when defining a derived class.
The workaround is to make the argument optional. So in class BaseCommande declare a key parameter:
def get_commandes_date(self, list_of_commande, key):
return [commande['date_start'] for commande in list_of_commande]
And then give it a default value in the derived BooksCommande class version of the method. (I'm not sure what might make sense here, so just made it None.)
def get_commandes_date(self, list_of_commande, key=None):
commande_date = []
for commande in list_of_commande:
cmd = {
'date_start': commande['date_start'],
'key': key,
'date_end': commande['date_end'],
}
commande_date.append(cmd)
return commande_date

As others have explained, the issue with your code is that your subclass, BooksCommande, changes the signature of the get_commandes_date method to be different than the version in the base class, BaseCommande. While that might be a bad idea in an abstract sense, it's not forbidden by Python. The real trouble is that one of BaseCommande's other methods, process_commande, tries to use the old signature, so everything breaks when that it gets called.
There is a fairly direct way to fix this, if you want to do so without dramatically changing the code. The general idea is for the two BaseCommande methods to call each other through a private reference. Even if one is overridden in a subclass, the private reference will remain pointing to the original implementation. Name mangling, with two leading underscores is often useful for this:
class BaseCommande(ABC):
...
def get_commandes_date(self, list_of_commande): # this method will be overridden
return [commande['date_start'] for commande in list_of_commande]
__get_commandes_date = get_commandes_date # private reference to previous method
def process_commande(self, list_of_commande):
self.commande_date = self.__get_commandes_date(list_of_commande) # use it here
This kind of design won't always be correct, so you'll need to figure out if it's appropriate for your specific classes or not. If the fact that process_commande is calls get_commandes_date is supposed to be an implementation detail (and so it should keep behaving the same way, even though the latter method is overridden), then this is a good approach. If the relationship between the methods is part of the class's API, then you probably don't want to do this (since overriding the get_commandes_date method may be a deliberate way to change the results of processess_commande in a subclass).

I think you want the method my_dict to have both my_dict and my_dict2 and have a boolean to trigger whenever you want to use one or the other.
def my_dict(self, trigger=False):
if not Trigger:
return{
"commende_date": self.commande_date}
else:
return{**super().my_dict(),
"books": self.books_list
Put this in place of your old my_dict method
def my_dict(self):
return{
"commende_date": self.commande_date}
Edit to add code

Related

Translation of message dict into msg enum

I'm dealing with refactoring code which extensively uses dicts in a circumstance where enums could be used. Unfortunately, to reduce typing the dict keys were abbreviated in a cryptic fashion.
In order to have more meaningful code and fewer string literals as well as a more advanced interface I translated the message dictionary based code into an Enum based code using the same messages.
The message dictionaries looked like the following:
MsgDictionary = {'none': None,
'STJ': 'start_job',
'RPS': 'report_status',
'KLJ': 'kill_job'}
ExecStates = {'none': None,
'JCNS': 'job_could_not_start',
'JSS': 'job_successfully_started',
'JSF': 'job_successfully_finished'}
This, unfortunately lead to cluttered code:
...
self.send_message(id = MsgDictionary["stj"], some_data)
...
msg = self.receive_msg()
if msg.id in (MsgDictionary['STJ'], MsgDictionary['KLJ']):
self.toggle_job()
...
I would merely like to get rid of the string accesses, the cryptic names and the low level interface, like in the following. This send_message should send the str typed value of the Enum not the Enum instance itself.
...
self.send_message(id = MessagesEnum.START_JOB, some_data)
...
msg = self.receive_msg()
if msg.id in (MessagesEnum.START_JOB, MessagesEnum.KILL_JOB):
self.toggle_job()
...
But as in the original case, undefined execution states should still be allowed. This does currently not work. The reason is to not break existing code:
e = ExecStates(None)
-> ValueError: None is not a valid ExecutionStates
And I would like to be able to compare enum instances, e.g.:
e = ExecState[START_JOB]
if e == ExecState[START_JOB]:
pass
if e == ExecState[KILL_JOB]:
pass
Using the following definitions, I believe I'm almost there:
import enum
class _BaseEnum(str, enum.Enum):
#classmethod
def values(cls) -> DictValues:
return cls.__members__.values()
def _generate_next_value_(name: str, *args: object) -> str:
return name.lower()
def __str__(self):
return str(self.value) # Use stringification to cover the None value case
class MessageEnum(_BaseEnum):
NONE = None
START_JOB = enum.auto()
REPORT_STATUS = enum.auto()
KILL_JOB = enum.auto()
class ExecutionState(_BaseEnum):
NONE = None
JOB_COULD_NOT_START = enum.auto()
JOB_SUCCESSFULLY_STARTED = enum.auto()
JOB_SUCCESSFULLY_FINISHED = enum.auto()
However, one problem still remains. How can I deal with None value as well as strings in the enumerations? In my case, all enum items gets mapped to the lowercase of the enum item name. Which is the intended functionality. However, None gets unintendedly mapped to 'None'. This in effect leads to problems at other spots in the existing code which initializes an ExecutionState instance with None. I would like to also cover this case to not break existing code.
When I add a __new__ method to the _BaseEnum,
def __new__(cls, value):
obj = str.__new__(cls)
obj._value_ = value
return obj
I loose the possibility to compare the enumeration instances as all instances compare equal to ``.
My question is, in order to solve my problem, if I can corner case the None either in the _generate_next_value_ or the __new__ method or maybe using a proxy pattern ?
Two things that should help:
in your __new__, the creation line should read obj = str.__new__(cls, value) -- that way each instance will compare equal to its lower-cased name
export your enum members to the global namespace, and use is:
START_JOB, REPORT_STATUS, KILL_JOB = MessageEnum
...
if e is START_JOB: ...
...
if msg.id in (START_JOB, KILL_JOB): ...

How to make nested enum also have value

Consider the following code example:
from enum import Enum
class Location(Enum):
Outside = 'outside'
Inside = 'inside'
class Inside(Enum): # TypeError for conflicting names
Downstairs = 'downstairs'
Upstairs = 'upstairs'
How do I make Inside have the value 'inside' whilst also being a nested enum for accessing Downstairs and Upstairs?
Desired input:
print(Location.Inside)
print(Location.Inside.value)
print(Location.Inside.Downstairs)
print(Location.Inside.Downstairs.value)
Desired output:
Location.Inside
inside
Location.Inside.Downstairs
downstairs
UPDATE 1:
Some more context to my specific problem:
class Location(Enum):
Outside = 'outside'
Inside = 'inside'
class Inside(Enum): # TypeError for conflicting names
Downstairs = 'downstairs'
Upstairs = 'upstairs'
class Human:
def __init__(self, location):
self.location = location
def getLocationFromAPI():
# this function returns either 'inside' or 'outside'
# make calls to external API
return location # return location from api in str
def whereInside(human):
if human.location != Location.Inside:
return None
# here goes logic that determines if human is downstairs or upstairs
return locationInside # return either Location.Downstairs or Location.Upstairs
location_str = getLocationFromAPI() # will return 'inside' or 'outside'
location = Location(location_str) # make Enum
human = Human(location) # create human with basic location
if human.location == Location.Inside:
where_inside = whereInside(human)
human.location = where_inside # update location to be more precise
The problem is when I create the Human object I only know of a basic location, as in 'inside' or 'outside'. Only after that can I update the location to be more precise.
You can accomplish this by embedding an enum.Enum inside another like so: (just watch out for names conflicting)
from enum import Enum
class _Inside(Enum):
Downstairs = 'downstairs'
Upstairs = 'upstairs'
class Location(Enum):
Outside = 'outside'
Inside = _Inside
print(Location.Inside.value.Downstairs.value)
downstairs
it may be a bit late and the one who asked the question is no longer necessary, but I leave it here in case someone wants to take a look at it, and even if it has already been validated as one, although the same comment that it is not completely complete .
But I have been thinking about it and in the end I have solved it by looking at the same documentation XD.
You cannot extend classes of Enums, but you can extend methods, I have followed this way and the only thing I have done has been to override the new and init methods, the use case can be modified, this is only to nest enumerators.
from enum import Enum
class SuperNestedEnum(Enum):
def __new__(cls, *args):
obj = object.__new__(cls)
value = None
# Normal Enumerator definition
if len(args) == 1:
value = args[0]
# Have a tuple of values, first de value and next the nested enum (I will set in __init__ method)
if len(args) == 2:
value = args[0]
if value:
obj._value_ = value
return obj
def __init__(self, name, nested=None):
# At this point you can set any attribute what you want
if nested:
# Check if is an Enumerator you can comment this if. if you want another object
if isinstance(nested, EnumMeta):
for enm in nested:
self.__setattr__(enm.name, enm)
class Homework(Enum):
Task = "5"
class Subjects(SuperNestedEnum):
Maths = "maths"
English = "english"
Physics = "nested", Homework
class School(SuperNestedEnum):
Name = "2"
Subjects = "subjects", Subjects
Ignore the use case because it doesn't make sense, it's just an example
>>> School.Name
<School.Name: '2'>
>>> School.Subjects
<School.Subjects: 'subjects'>
>>> School.Subjects.value
'subjects'
>>> School.Subjects.Maths
<Subjects.Maths: 'maths'>
>>> School.Subjects.Physics.value
'nested'
>>> School.Subjects.Physics.Task
<Homework.Task: '5'>
>>> School.Subjects.Physics.Task.value
'5'
If anyone has similar issues and just wants a simple solution for the topic without patching any functions or additional imports for enums containing strings, follow these steps:
Create the value enums, in your lower hierarchy, like:
class __private_enum1__(str, enum.Enum):
VAL11 = "abc"
VAL12 = "def"
class enum2(str, enum.Enum):
VAL21 = "123"
VAL22 = "456"
Create a base class (a container) for these enums. Where you can either import the enums classes or simply directly acccess the enums.
class myValues:
VAL11 = __private_enum1__.VAL11
VAL12 = __private_enum1__.VAL12
VALS2X = enum2
Then you can access your values by:
print(myValues.VAL11.value)
print(myValues.VAL2X.VAL21.value)
.value is not necessary here but it shows that you both access the string inside the enum for passing it to other functions but also the enum itself, which is pretty neat. So basically, first create the values, then the structure. That way you have a class but it provides you the basic functionality of enums and you can nest them as deep as you want to without further imports.

How to create dynamic methods with python?

For my project I need to dynamically create custom (Class) methods.
I found out it is not so easy in Python:
class UserFilter(django_filters.FilterSet):
'''
This filter is used in the API
'''
# legacy below, this has to be added dynamically
#is_field_type1 = MethodFilter(action='filter_field_type1')
#def filter_field_type1(self, queryset, value):
# return queryset.filter(related_field__field_type1=value)
class Meta:
model = get_user_model()
fields = []
But it is giving me errors (and headaches...). Is this even possible?
I try to make the code between #legacy dynamic
One option to do this I found was to create the class dynamically
def create_filter_dict():
new_dict = {}
for field in list_of_fields:
def func(queryset, value):
_filter = {'stableuser__'+field:value}
return queryset.filter(**_filter)
new_dict.update({'filter_'+field: func})
new_dict.update({'is_'+field: MethodFilter(action='filter_'+field)})
return new_dict
meta_model_dict = {'model': get_user_model(), 'fields':[]}
meta_type = type('Meta',(), meta_model_dict)
filter_dict = create_filter_dict()
filter_dict['Meta'] = meta_type
UserFilter = type('UserFilter', (django_filters.FilterSet,), filter_dict)
However, this is giving me
TypeError at /api/v2/users/
func() takes 2 positional arguments but 3 were given
Does anyone know how to solve this dilemma?
Exception Value: 'UserFilter' object has no attribute 'is_bound'
You are getting this error because the class methods you are generating, are not bound to any class. To bound them to the class, you need to use setattr()
Try this on a console:
class MyClass(object):
pass
#classmethod
def unbound(cls):
print "Now I'm bound to ", cls
print unbound
setattr(MyClass, "bound", unbound)
print MyClass.bound
print MyClass.bound()
Traceback:
UserFilter = type('Foo', (django_filters.FilterSet, ), create_filter_dict().update({'Meta':type('Meta',(), {'model':
get_user_model(), 'fields':[]} )})) TypeError: type() argument 3 must
be dict, not None
Now, this is failing because dict.update() doesn't return the same instance, returns None. That can be fixed easily
class_dict = create_filter_dict()
class_dict.update({'Meta':type('Meta',(), {'model': get_user_model(), 'fields':[]})}
UserFilter = type('Foo', (django_filters.FilterSet, ), class_dict))
However, just look how messy that code looks. I recommend to you to try to be
clearer with the code you write even if it requires to write a few extra lines. In the long run, the code will be easier to maintain for you and your team.
meta_model_dict = {'model': get_user_model(), 'fields':[]}
meta_type = type('Meta',(), meta_model_dict)
filter_dict = create_filter_dict()
filter_dict['Meta'] = meta_type
UserFilter = type('Foo', (django_filters.FilterSet,), filter_dict)
This code might not be perfect but it is more readable than the original line of code you posted:
UserFilter = type('Foo', (django_filters.FilterSet, ), create_filter_dict().update({'Meta':type('Meta',(), {'model': get_user_model(), 'fields':[]})}))
And removes a complication on an already kinda difficult concept to grasp.
You might want to learn about metaclasses. Maybe you can overwrite the new method of a class. I can recommend you 1 or 2 posts about that.
Another option is that maybe you are not adding the filters correctly or in a way django doesn't expect? That would explain why you get no errors but none of your functions gets called.
You can use classmethod. Here is example how you can use it:
class UserFilter:
#classmethod
def filter_field(cls, queryset, value, field = None):
# do somthing
return "{0} ==> {1} {2}".format(field, queryset, value)
#classmethod
def init(cls,list_of_fields ):
for field in list_of_fields:
ff = lambda cls, queryset, value, field=field: cls.filter_field(queryset, value, field )
setattr(cls, 'filter_'+field, classmethod( ff ))
UserFilter.init( ['a','b'] )
print(UserFilter.filter_a(1,2)) # a ==> 1 2
print(UserFilter.filter_b(3,4)) # b ==> 3 4
You are asking for:
custom (Class) methods.
So we take an existing class and derive a subclass where you can add new methods or overwrite the methods of the original existing class (look into the code of the original class for the methods you need) like this:
from universe import World
class NewEarth(World.Earth):
def newDirectionUpsideDown(self,direction):
self.rotationDirection = direction
All the other Methods and features of World.Earth apply to NewEarth only you can now change the direction to make the world turn your new way.
To overwrite an existing method of a class is as as easy as this.
class NewEarth(World.Earth):
def leIitRain(self,amount): # let's assume leIitRain() is a standard-function of our world
return self.asteroidStorm(amount) #let's assume this is possible Method of World.Earth
So if someone likes a cool shower on earth he/she/it or whatever makes room for new development on the toy marble the burning way.
So have fun in your way learning python - and don't start with complicated things.
If I got you completely wrong - you might explain your problem in more detail - so more wise people than me can share their wisdom.

Inverse of hasattr in Python

hasattr(obj, attribute) is used to check if an object has the specified attribute but given an attribute is there a way to know where (all) it is defined?
Assume that my code is getting the name of an attribute (or a classmethod) as string and I want to invoke classname.attribute but I don't have the classname.
One solution that comes to my mind is this
def finder(attr):
for obj in globals():
try:
if globals()[obj].__dict__[attr]:
return(globals()[obj])
except:
...
usage:
class Lime(object):
#classmethod
def lfunc(self):
print('Classic')
getattr(finder('lfunc'),'lfunc')() #Runs lfunc method of Lime class
I am quite sure that this is not the best (oe even proper way) to do it. Can someone please provide a better way.
It is always "possible". Wether it is desirable is another history.
A quick and dirty way to do it is to iterate linearly over all classes and check if any define the attribute you have. Of course, that is subject to conflicts, and it will yield the first class that has such a named attribute. If it exists in more than one, it is up to you to decide which you want:
def finder(attr):
for cls in object.__subclasses__():
if hasattr(cls, attr):
return cls
raise ValueError
Instead of searching in "globals" this searches all subclasses of "object" - thus the classes to be found don't need to be in the namespace of the module where the finder function is.
If your methods are unique in teh set of classes you are searching, though, maybe you could just assemble a mapping of all methods and use it to call them instead.
Let's suppose all your classes inehrit from a class named "Base":
mapper = {attr_name:getattr(cls, attr_name) for cls in base.__subclasses__() for attr_name, obj in cls.__dict__.items()
if isinstance(obj, classmethod) }
And you call them with mapper['attrname']()
This avoids a linear search at each method call and thus would be much better.
- EDIT -
__subclassess__ just find the direct subclasses of a class, not the inheritance tree - so it won't be usefull in "real life" - maybe it is in the specifc case the OP has in its hands.
If one needs to find things across a inheritance tree, one needs to recurse over the each subclass as well.
As for old-style classes: of course this won't work - that is one of the motives for which they are broken by default in new code.
As for non-class attributes: they can only be found inspecting instances anyway - so another method has to be thought of - does not seem to be the concern of the O.P. here.
This might help:
import gc
def checker(checkee, maxdepth = 3):
def onlyDict(ls):
return filter(lambda x: isinstance(x, dict), ls)
collection = []
toBeInspected = {}
tBI = toBeInspected
gc.collect()
for dic in onlyDict(gc.get_referrers(checkee)):
for item, value in dic.iteritems():
if value is checkee:
collection.append(item)
elif item != "checker":
tBI[item] = value
def _auxChecker(checkee, path, collection, checked, current, depth):
if current in checked: return
checked.append(current)
gc.collect()
for dic in onlyDict(gc.get_referents(current)):
for item, value in dic.iteritems():
currentPath = path + "." + item
if value is checkee:
collection.append(currentPath)
else:
try:
_auxChecker(checkee, currentPath, collection,
checked, value, depth + 1)
if depth < maxdepth else None
except TypeError:
continue
checked = []
for item, value in tBI.iteritems():
_auxChecker(checkee, item, collection, checked, value, 1)
return collection
How to use:
referrer = []
class Foo:
pass
noo = Foo()
bar = noo
import xml
import libxml2
import sys
import os
op = os.path
xml.foo = bar
foobar = noo
for x in checker(foobar, 5):
try:
y= eval(x)
referrer.append(x)
except:
continue
del x, y
ps: attributes of the checkee will not be further checked, for recursive or nested references to the checkee itself.
This should work in all circumstances, but still needs a lot of testing:
import inspect
import sys
def finder(attr, classes=None):
result = []
if classes is None:
# get all accessible classes
classes = [obj for name, obj in inspect.getmembers(
sys.modules[__name__])]
for a_class in classes:
if inspect.isclass(a_class):
if hasattr(a_class, attr):
result.append(a_class)
else:
# we check for instance attributes
if hasattr(a_class(), attr):
result.append(a_class)
try:
result += finder(attr, a_class.__subclasses__())
except:
# old style classes (that don't inherit from object) do not
# have __subclasses; not the best solution though
pass
return list(set(result)) # workaround duplicates
def main(attr):
print finder(attr)
return 0
if __name__ == "__main__":
sys.exit(main("some_attr"))

Pythonic - How to initialize a construtor with multiple arguments and validate

I'm a python noob and I'm trying to solve my problems the 'pythonic' way. I have a class, who's __init__ method takes 6 parameters. I need to validate each param and throw/raise an Exception if any fails to validate.
Is this the right way?
class DefinitionRunner:
def __init__(self, canvasSize, flightId, domain, definitionPath, harPath):
self.canvasSize = canvasSize
self.flightId = flightId
self.domain = domain
self.harPath = harPath
self.definitionPath = definitionPath
... bunch of validation checks...
... if fails, raise ValueError ...
If you want the variables to be settable independently of __init__, you could use properties to implement validations in separate methods.
They work only for new style classes though, so you need to define the class as class DefinitionRunner(object)
So for example,
#property
def canvasSize(self):
return self._canvasSize
#canvasSize.setter
def canvasSize(self, value):
# some validation here
self._canvasSize = value
Broadly speaking, that looks like the way you'd do it. Though strictly speaking, you might as well do validation before rather than after assignment, especially if assignment could potentially be time or resource intensive. Also, style convention says not to align assignment blocks like you are.
I would do it like you did it. Except the validating stuff. I would validate in a setter method and use it to set the attributes.
You could do something like this. Make a validator for each type of input. Make a helper function to run validation:
def validate_and_assign(obj, items_d, validators):
#validate all entries
for key, validator in validators.items():
if not validator[key](items_d[key]):
raise ValueError("Validation for %s failed" % (key,))
#set all entries
for key, val in items_d.items():
setattr(obj, key, val)
Which you'd use like this:
class DefinitionRunner:
validators = {
'canvasSize': canvasSize_validator,
'flightId': flightId_validator,
'domain': domain_validator,
'definitionPath': definitionPath_validator,
'harPath': harPath_validator,
}
def __init__(self, canvasSize, flightId, domain, definitionPath, harPath):
validate_and_assign(self, {
'canvasSize': canvasSize,
'flightId': flightId,
'domain': domain,
'definitionPath': definitionPath,
'harPath': harPath,
}, DefinitionRunner.validators)
The validators might be the same function, of course, if the data type is the same.
I'm not sure if this is exactly "Pythonic", but I've defined a function decorator called require_type. (To be honest, I think I found it somewhere online.)
def require_type(my_arg, *valid_types):
'''
A simple decorator that performs type checking.
#param my_arg: string indicating argument name
#param valid_types: list of valid types
'''
def make_wrapper(func):
if hasattr(func, 'wrapped_args'):
wrapped = getattr(func, 'wrapped_args')
else:
body = func.func_code
wrapped = list(body.co_varnames[:body.co_argcount])
try:
idx = wrapped.index(my_arg)
except ValueError:
raise(NameError, my_arg)
def wrapper(*args, **kwargs):
def fail():
all_types = ', '.join(str(typ) for typ in valid_types)
raise(TypeError, '\'%s\' was type %s, expected to be in following list: %s' % (my_arg, all_types, type(arg)))
if len(args) > idx:
arg = args[idx]
if not isinstance(arg, valid_types):
fail()
else:
if my_arg in kwargs:
arg = kwargs[my_arg]
if not isinstance(arg, valid_types):
fail()
return func(*args, **kwargs)
wrapper.wrapped_args = wrapped
return wrapper
return make_wrapper
Then, to use it:
class SomeObject(object):
#require_type("prop1", str)
#require_type("prop2", numpy.complex128)
def __init__(self, prop1, prop2):
pass

Categories

Resources