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
Related
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()
I am trying to assign a function defined elsewhere to a class variable so I can later call it in one of the methods of the instance, like this:
from module import my_func
class Bar(object):
func = my_func
def run(self):
self.func() # Runs my function
The problem is that this fails because when doing self.func(), then the instance is passed as the first parameter.
I've come up with a hack but seems ugly to me, anybody has an alternative?
In [1]: class Foo(object):
...: func = lambda *args: args
...: def __init__(self):
...: print(self.func())
...:
In [2]: class Foo2(object):
...: funcs = [lambda *args: args]
...: def __init__(self):
...: print(self.funcs[0]())
...:
In [3]: f = Foo()
(<__main__.Foo object at 0x00000000044BFB70>,)
In [4]: f2 = Foo2()
()
Edit: The behavior is different with builtin functions!
In [13]: from math import pow
In [14]: def pow_(a, b):
....: return pow(a, b)
....:
In [15]: class Foo3(object):
....: func = pow_
....: def __init__(self):
....: print(self.func(2, 3))
....:
In [16]: f3 = Foo3()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-16-c27c8778655e> in <module>()
----> 1 f3 = Foo3()
<ipython-input-15-efeb6adb211c> in __init__(self)
2 func = pow_
3 def __init__(self):
----> 4 print(self.func(2, 3))
5
TypeError: pow_() takes exactly 2 arguments (3 given)
In [17]: class Foo4(object):
....: func = pow
....: def __init__(self):
....: print(self.func(2, 3))
....:
In [18]: f4 = Foo4()
8.0
Python functions are descriptor objects, and when attributes on a class accessing them an instance causes them to be bound as methods.
If you want to prevent this, use the staticmethod function to wrap the function in a different descriptor that doesn't bind to the instance:
class Bar(object):
func = staticmethod(my_func)
def run(self):
self.func()
Alternatively, access the unbound function via the __func__ attribute on the method:
def run(self):
self.func.__func__()
or go directly to the class __dict__ attribute to bypass the descriptor protocol altogether:
def run(self):
Bar.__dict__['func']()
As for math.pow, that's not a Python function, in that it is written in C code. Most built-in functions are written in C, and most are not descriptors.
Given the class
class A(object):
def __init__(self):
self.x = 'hello'
one can recreate is dynamically with type.
type('A', (object,), {'x': 'hello'})
Is it possible to create class level variables with type?
class A(object):
my_class_variable = 'hello'
In [154]: A = type('A', (object,), {'my_class_variable':'hello'})
In [155]: A.my_class_variable
Out[157]: 'hello'
In your first example, type('A', (object,), {'x': 'hello'}), A.x is a class attribute, not an instance attribute too.
To make a class with the __init__ you posted, you would first need to define the __init__ function, then make that __init__ a class attribute:
In [159]: def __init__(self):
.....: self.x = 'hello'
.....:
In [160]: A2= type('A', (object,), {'__init__':__init__})
In [161]: 'x' in dir(A2)
Out[161]: False # x is not a class attribute
In [162]: 'x' in dir(A2())
Out[162]: True # x is an instance attribute
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'}
I'm new to python and trying to get a list of the classes an object's class inherits from. I'm trying to do this using the bases attribute but I'm not having any success. Can someone please help me out?
def foo(C):
print(list(C.__bases__))
class Thing(object):
def f(self):
print("Yo")
class Shape(Thing):
def l(self):
print("ain't no thang")
class Circle(Shape):
def n(self):
print("ain't no shape")
test = Circle()
foo(test)
Only classes have __bases__; class instances do not. You can get the class object through an instance's __class__: use foo(test.__class__) or foo(Circle).
Use inspect, from documentation
Return a tuple of class cls’s base classes, including cls, in method
resolution order. No class appears more than once in this tuple. Note
that the method resolution order depends on cls’s type. Unless a very
peculiar user-defined metatype is in use, cls will be the first
element of the tuple.
>>> import inspect
>>> inspect.getmro(test.__class__)
(<class '__main__.Circle'>, <class '__main__.Shape'>, <class '__main__.Thing'>, <type 'object'>)
>>>
This traverses up the inheritance hierarchy & prints all classes, including object. Pretty Cool eh ?
print '\n'.join(base.__name__ for base in test.__class__.__bases__)
Or, using the inspect module:
from inspect import getmro
print '\n'.join(base.__name__ for base in getmro(test))
Your implementation of foo works. But you need to pass a class to foo, not an instance.
In [1]: def foo(C):
...: print(list(C.__bases__))
...:
In [2]: class Thing(object):
...: def f(self):
...: print("Yo")
...:
In [3]: class Shape(Thing):
...: def l(self):
...: print("ain't no thang")
...:
In [4]: class Circle(Shape):
...: def n(self):
...: print("ain't no shape")
...:
In [5]: test = Circle()
In [6]: foo(test)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-6-7b85deb1beaa> in <module>()
----> 1 foo(test)
<ipython-input-1-acd1789d43a9> in foo(C)
1 def foo(C):
----> 2 print(list(C.__bases__))
3
AttributeError: 'Circle' object has no attribute '__bases__'
In [7]: foo(Thing)
[<type 'object'>]
In [8]: foo(Circle)
[<class '__main__.Shape'>]
In [9]: foo(Shape)
[<class '__main__.Thing'>]