Represent a class as a dict or list - python

I've classes that is used for getting data from one system, making some modifications and then outputting them into another system. Which usually goes the way of converting it into a dict or a list after I've made all the necessary conversions.
So far what I've done is that I've made two methods called as_dict() and as_list() and used that whenever I need that representation.
But I'm curious if there's a way to be able to do dict(instance_of_my_class) or list(instance_of_my_class).
I've been reading up on magic methods and it seems as if this is not possible?
And some simple sample code to work with:
class Cost(object):
#property
def a_metric(self):
return self.raw_data.get('a_metric', 0) * 0.8
[..]
# Repeat for various kinds of transformations
def as_dict(self):
return {
'a_metric': self.a_metric,
[...]
}

Do you mean something like this? If so you have to define a __iter__ method that yield's key-value pairs:
In [1]: class A(object):
...: def __init__(self):
...: self.pairs = ((1,2),(2,3))
...: def __iter__(self):
...: return iter(self.pairs)
...:
In [2]: a = A()
In [3]: dict(a)
Out[3]: {1: 2, 2: 3}
Also, it seems that dict tries to call the .keys / __getitem__ methods before __iter__, so you can make list(instance) and dict(instance) return something completely different.
In [4]: class B(object):
...: def __init__(self):
...: self.d = {'key':'value'}
...: self.l = [1,2,3,4]
...: def keys(self):
...: return self.d.keys()
...: def __getitem__(self, item):
...: return self.d[item]
...: def __iter__(self):
...: return iter(self.l)
...:
In [5]: b = B()
In [6]: list(b)
Out[6]: [1, 2, 3, 4]
In [7]: dict(b)
Out[7]: {'key': 'value'}

Related

Proper way to use dataclass in another class

After asking my last question, it seems like I have not really understood classes adn dataclasses.
So I would like to learn the correct way of doing the following:
define dataclass
define other class, which will use an instance of dataclass
use a method from the second class to updatenvalues of dataclass
The way I do gives me an error saying that my datafram doesn't exist. I created a method inside the dataclass, using that results in an error stating it is read-only.
#dataclass(slots=True)
def Storage():
timestamp: float
value: float
class UDP():
some attributes
self.datastorage: Storage = Storage()
def updatedata(self, time, val):
self.datastorage.timestamp = time
self.datastorage.value = val
def main():
test = UDP()
test.updatedata(0.01,2)
So my question is how to instantiate a dataclass in another class and be able to manipulate the values in the dataclass?
Your code has several syntactic problems. Once those are fixed, the code works. Storage objects are mutable, and you may freely modify their timestamp and value attributes.
In [7]: #dataclass(slots=True)
...: class Storage:
...: timestamp: float
...: value: float
...:
...:
...: class UDP:
...: datastorage: Storage = Storage(0.0, 0.0)
...:
...: def updatedata(self, time, val):
...: self.datastorage.timestamp = time
...: self.datastorage.value = val
...:
...: def main():
...: test = UDP()
...: test.updatedata(0.01,2)
...:
In [8]: main()

How to avoid infinite recursion in python class method

This is a follow-up question from this.
I want a class that handles a function that can update itself. This is a simplified example, but I still end up with an infinite recursion:
def f(x):
return x
class func:
def __init__(self, f):
self.f = f
def translate(self, c):
def f_(x):
return self.f(x + c)
self.f = f_
It works only once:
>>> myfunc = func(f)
>>> myfunc.f(1)
1
>>> myfunc.translate(5)
>>> myfunc(1)
...
RecursionError: maximum recursion depth exceeded
The problem is that self.f calls self.f, which would not happen if translate were defined outside of a class:
def translate(f, c):
def f_(x):
return f(x+c)
return f_
This works:
>>> f = translate(f, 5)
>>> f(1)
6
>>> f = translate(f,-5)
>>>f(1)
1
How can I make it work inside the class?
If you'd tried to write your outside-a-class translate closer to how you wrote your first translate:
def f(x):
return x
def translate(c):
global f
def f_(x):
return f(x+c)
f = f_
translate(5)
f(1)
you would have gotten a RecursionError there too. Your outside-a-class translate worked because its f_ looks for f in a local variable that doesn't get overwritten, rather than in the attribute or global you're about to rebind to your new f_.
Have your translate method look in a local variable too:
def translate(self, c):
f = self.f
def f_(self, x):
return f(x+c)
self.f = f_
(By the way, call this method enough times and you'll stack up so many layers of wrappers that you hit the recursion limit anyway. Stacking wrappers indefinitely is a bad idea.)
Just use a closure, like you are doing without the class, by getting a reference to the original function object before updating the self.f attribute:
In [1]: def f(x):
...: return x
...:
...: class func:
...:
...: def __init__(self, f):
...: self.f = f
...:
...: def translate(self, c):
...: f = self.f
...: def f_(x):
...: return f(x + c)
...: self.f = f_
...:
In [2]: myfunc = func(f)
In [3]: myfunc.f(1)
Out[3]: 1
In [4]: myfunc.translate(5)
In [5]: myfunc.f(1)
Out[5]: 6
You've run into a quirk of Python name resolution. Try something like this:
def translate(self, c):
def f_(x, f=self.f):
return f(x + c)
self.f = f_
I wish I understood the issue well enough to give a concise explanation. The rough version is that self.f always points to "the f method of self". When you replace the f-method of self, it points to the new function and not the old one. This is why it loops infinitely.
The kwargs trick works around the issue by creating a new variable in a special scope. The value of f in f=self.f is self-contained in the function and stays with this specific function definition. It gets set to the current value of self.f when the function is defined. As a result, it doesn't get changed to point to the circular version of the function.

How to define enum values that are functions?

I have a situation where I need to enforce and give the user the option of one of a number of select functions, to be passed in as an argument to another function:
I really want to achieve something like the following:
from enum import Enum
#Trivial Function 1
def functionA():
pass
#Trivial Function 2
def functionB():
pass
#This is not allowed (as far as i can tell the values should be integers)
#But pseudocode for what I am after
class AvailableFunctions(Enum):
OptionA = functionA
OptionB = functionB
So the following can be executed:
def myUserFunction(theFunction = AvailableFunctions.OptionA):
#Type Check
assert isinstance(theFunction,AvailableFunctions)
#Execute the actual function held as value in the enum or equivalent
return theFunction.value()
Your assumption is wrong. Values can be arbitrary, they are not limited to integers. From the documentation:
The examples above use integers for enumeration values. Using integers
is short and handy (and provided by default by the Functional API),
but not strictly enforced. In the vast majority of use-cases, one
doesn’t care what the actual value of an enumeration is. But if the
value is important, enumerations can have arbitrary values.
However the issue with functions is that they are considered to be method definitions instead of attributes!
In [1]: from enum import Enum
In [2]: def f(self, *args):
...: pass
...:
In [3]: class MyEnum(Enum):
...: a = f
...: def b(self, *args):
...: print(self, args)
...:
In [4]: list(MyEnum) # it has no values
Out[4]: []
In [5]: MyEnum.a
Out[5]: <function __main__.f>
In [6]: MyEnum.b
Out[6]: <function __main__.MyEnum.b>
You can work around this by using a wrapper class or just functools.partial or (only in Python2) staticmethod:
from functools import partial
class MyEnum(Enum):
OptionA = partial(functionA)
OptionB = staticmethod(functionB)
Sample run:
In [7]: from functools import partial
In [8]: class MyEnum2(Enum):
...: a = partial(f)
...: def b(self, *args):
...: print(self, args)
...:
In [9]: list(MyEnum2)
Out[9]: [<MyEnum2.a: functools.partial(<function f at 0x7f4130f9aae8>)>]
In [10]: MyEnum2.a
Out[10]: <MyEnum2.a: functools.partial(<function f at 0x7f4130f9aae8>)>
Or using a wrapper class:
In [13]: class Wrapper:
...: def __init__(self, f):
...: self.f = f
...: def __call__(self, *args, **kwargs):
...: return self.f(*args, **kwargs)
...:
In [14]: class MyEnum3(Enum):
...: a = Wrapper(f)
...:
In [15]: list(MyEnum3)
Out[15]: [<MyEnum3.a: <__main__.Wrapper object at 0x7f413075b358>>]
Also note that if you want you can define the __call__ method in your enumeration class to make the values callable:
In [1]: from enum import Enum
In [2]: def f(*args):
...: print(args)
...:
In [3]: class MyEnum(Enum):
...: a = partial(f)
...: def __call__(self, *args):
...: self.value(*args)
...:
In [5]: MyEnum.a(1,2,3) # no need for MyEnum.a.value(1,2,3)
(1, 2, 3)
Since Python 3.11 there is much more concise and understandable way. member and nonmember functions were added to enum among other improvements, so you can now do the following:
from enum import Enum, member
def fn(x):
print(x)
class MyEnum(Enum):
meth = fn
mem = member(fn)
#classmethod
def this_is_a_method(cls):
print('No, still not a member')
def this_is_just_function():
print('No, not a member')
#member
def this_is_a_member(x):
print('Now a member!', x)
And now
>>> list(MyEnum)
[<MyEnum.mem: <function fn at ...>>, <MyEnum.this_is_a_member: <function MyEnum.this_is_a_member at ...>>]
>>> MyEnum.meth(1)
1
>>> MyEnum.mem(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'MyEnum' object is not callable
>>> MyEnum.mem.value(1)
1
>>> MyEnum.this_is_a_method()
No, still not a member
>>> MyEnum.this_is_just_function()
No, not a member
>>> MyEnum.this_is_a_member()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'MyEnum' object is not callable
>>> MyEnum.this_is_a_member.value(1)
Now a member! 1
Another less clunky solution is to put the functions in a tuple. As Bakuriu mentioned, you may want to make the enum callable.
from enum import Enum
def functionA():
pass
def functionB():
pass
class AvailableFunctions(Enum):
OptionA = (functionA,)
OptionB = (functionB,)
def __call__(self, *args, **kwargs):
self.value[0](*args, **kwargs)
Now you can use it like this:
AvailableFunctions.OptionA() # calls functionA
In addition to the answer of Bakuriu... If you use the wrapper approach like above you loose information about the original function like __name__, __repr__
and so on after wrapping it. This will cause problems for example if you want to use sphinx for generation of source code documentation. Therefore add the following to your wrapper class.
class wrapper:
def __init__(self, function):
self.function = function
functools.update_wrapper(self, function)
def __call__(self,*args, **kwargs):
return self.function(*args, **kwargs)
def __repr__(self):
return self.function.__repr__()
Building on top of #bakuriu's approach, I just want to highlight that we can also use dictionaries of multiple functions as values and have a broader polymorphism, similar to enums in Java. Here is a fictitious example to show what I mean:
from enum import Enum, unique
#unique
class MyEnum(Enum):
test = {'execute': lambda o: o.test()}
prod = {'execute': lambda o: o.prod()}
def __getattr__(self, name):
if name in self.__dict__:
return self.__dict__[name]
elif not name.startswith("_"):
value = self.__dict__['_value_']
return value[name]
raise AttributeError(name)
class Executor:
def __init__(self, mode: MyEnum):
self.mode = mode
def test(self):
print('test run')
def prod(self):
print('prod run')
def execute(self):
self.mode.execute(self)
Executor(MyEnum.test).execute()
Executor(MyEnum.prod).execute()
Obviously, the dictionary approach provides no additional benefit when there is only a single function, so use this approach when there are multiple functions. Ensure that the keys are uniform across all values as otherwise, the usage won't be polymorphic.
The __getattr__ method is optional, it is only there for syntactic sugar (i.e., without it, mode.execute() would become mode.value['execute']().
Since dictionaries can't be made readonly, using namedtuple would be better and require only minor changes to the above.
from enum import Enum, unique
from collections import namedtuple
EnumType = namedtuple("EnumType", "execute")
#unique
class MyEnum(Enum):
test = EnumType(lambda o: o.test())
prod = EnumType(lambda o: o.prod())
def __getattr__(self, name):
if name in self.__dict__:
return self.__dict__[name]
elif not name.startswith("_"):
value = self.__dict__['_value_']
return getattr(value, name)
raise AttributeError(name)

Is there a way to apply decorators to Python data structures?

From what I got so far, decorators applies to callables(functions and classes).
Wondering if there is a way to apply a decorator to a dictionary?(It can be any data structure, in fact).
The problem I try to solve goes along the following lines:
I have a lot of dictionaries which, from time to time, might be valid or not.
I want to mark them with a decorator-like as shown in the skeleton bellow...:
class Data(object):
def invalide(self):
return False
def valide(self, some_dict):
return some_dict
#Data.invalide
dict_1 = {...}
#Data.valide
dict_2 = {...}
#Data.valide
dict_3 = {...}
...
...
#Data.invalide
dict_n = {...}
...so, when I call some_function(dict_x), it would know to do one thing or the other based on the valide, invalide marks.
-------------Later on--------------------
I ended up implementing the following:
In [2]: class Data(object):
...:
...: #classmethod
...: def valide(self, func):
...: #print "Data is valide."
...: return func()
...:
...: #classmethod
...: def invalide(self, func):
...: #print "Data is invalide."
...: return False
...:
In [3]: #Data.valide
...: def dict1():
...: return {"a": 1, "b": 2, "c": 3}
...:
...: #Data.invalide
...: def dict2():
...: return {"d": 4, "e": 4, "f": 6}
...:
...: def run_funct(some_dict):
...: return some_dict
...:
In [4]: print(run_funct(dict1))
...: print type(run_funct(dict1))
...:
{'a': 1, 'c': 3, 'b': 2}
<type 'dict'>
In [5]: print(run_funct(dict2))
...: print type(run_funct(dict2))
...:
False
<type 'bool'>
Decorators, to my knowledge, can only be applied to callables (functions, classes etc.)
If I was in your place, I'd probably separate the logic to decide between valid/invalid in its own function.
you could cobble something together with properties and decorators:
def valid(func):
return property(lambda self: func(self))
def invalid(func):
return property(lambda self: False)
class A:
#valid
def dict1(self):
return dict(a=4, b=5)
#invalid
def dict2(self):
return dict(c=6, d=7)
usage would then be:
a = A()
a.dict1
a.dict2
i can't say i would recommend doing this, but it should meet your needs.

Rebinding immutable class attribute in the base class from a derived class

I have this generic problem in python. The base class defines a class attribute class_attr. This attribute is immutable, in this case it is a number. I want to change this attribute from a derived class, thus rebinding Base.class_attr to the new value (in my toy case, incrementing it).
The question is how to do this without explicitly naming Base in statement Base.class_attr += 1.
class Base(object):
# class attribute:
class_attr = 0
class Derived(Base):
#classmethod
def increment_class_attr(cls):
Base.class_attr += 1
# is there a solution which does not name the owner of the
# class_attr explicitly?
# This would cause the definition of Derived.class_attr,
# thus Base.class_attr and Derived.class_attr would be
# two independent attributes, no more in sync:
# cls.class_attr += 1
Derived.increment_class_attr()
Derived.increment_class_attr()
print Base.class_attr # 2
Please note: I am after the very question, that is, can I rebind the attributes of a parent class. I am not after the work-around solutions to this problem (e.g., shift increment_class_attr to Base).
Use the __bases__ attribute:
In [68]: class Base(object):
...: # class attribute:
...: class_attr = 0
...:
In [69]: class Derived(Base):
...: #classmethod
...: def inc(cls):
...: p, = cls.__bases__
...: p.class_attr += 1
...:
In [70]: Base.class_attr
Out[70]: 0
In [71]: Derived.inc()
In [72]: Derived.inc()
In [73]: Base.class_attr
Out[73]: 2
If you have multiple inheritance:
In [88]: class DifferentInherited(object):
...: class2_attr = 0
...:
In [90]: class Der2(Base, DifferentInherited):
...: #classmethod
...: def inc(cls):
...: print cls.__bases__
...: a, b, = cls.__bases__
...: print a.class_attr
...: print b.class2_attr
...:
In [91]: Der2.inc()
(<class '__main__.Base'>, <class '__main__.DifferentInherited'>)
2
0
Assuming you don't know the inheritance order either, you'll need to test each class for the variable:
In [127]: class Der3(DifferentInherited, Base):
...: #classmethod
...: def inc(cls):
...: # This gets a list of *all* classes with the attribute `class_attr`
...: classes = [c for c in cls.__bases__ if 'class_attr' in c.__dict__]
...: for c in classes:
...: c.class_attr += 1
...:
In [128]: Der3.inc()
In [129]: Base.class_attr
Out[129]: 3
In [131]: DifferentInherited.class2_attr
Out[131]: 0
And multiple inheritance uses __mro__:
In [146]: class Multi(Der3):
...: #classmethod
...: def inc(cls):
...: c_attr = [c for c in cls.__mro__ if 'class_attr' in c.__dict__]
...: print c_attr
...: c_attr[0].class_attr += 1
...:
In [147]: Multi.inc()
[<class '__main__.Base'>]
In [148]: Base.class_attr
Out[148]: 4

Categories

Resources