I have a Python class C which should have two pseudo-dicts a and b. The term pseudo-dicts means that the dictionaries don't actually exist and that they are “recomputed” each time a key is accessed.
In pseudocode this would look like this:
class C:
def a.__getitem__(self, key):
return 'a'
def b.__getitem__(self, key):
return 'b'
>>> c = C()
>>> c.a['foo']
'a'
>>> c.b['bar']
'b'
I could implement a class for a and b, but since both have just a few short methods, I wonder whether there is a more elegant and compact way to do this.
Why not just define your own class?
class PseudoDict(object):
def __init__(self, c):
self.c = c
def __getitem__(self, key):
return self.c.somethingmagical()
class C(object):
def __init__(self):
self.a = PseudoDict(self)
self.b = PseudoDict(self)
c = C()
print c.a['foo']
print c.b['bar']
I'm not sure where the values for these 'pseudo-dicts' are coming from, so you'll have to update the __getitem__ method.
Like this?
from collections import defaultdict
class C:
a = defaultdict(lambda:'a')
b = defaultdict(lambda:'b')
c=C()
print c.a['foo']
print c.b['bar']
Or maybe like this for real calculation functions?
from collections import defaultdict
class C:
def __init__(self):
self.a = defaultdict(self.geta)
self.b = defaultdict(self.getb)
def geta(self):
return 'a'
def getb(self):
return 'b'
c=C()
print c.a['foo']
print c.b['bar']
Related
This question already has answers here:
Class that acts as mapping for **unpacking
(3 answers)
Implement packing/unpacking in an object
(4 answers)
Closed last year.
I'd like to make a class that unpacks it's objects like a dictionary.
For example, with a dictionary you can do this
foo = {
"a" : 1
"b" : 2
}
def bar(a,b):
return a + b
bar(**foo)
outputs 3
And I'd like to be able to do this
class FooClass:
def __init__(self):
self.a = a
self.b = b
f = FooClass()
bar(**f)
and have it output 3
This is the most related question I could find but it doesn't address this so I'm thinking it might not be possible.
Currently what my solution would be this:
class FooClass:
def __init__(self):
self.a = a
self.b = b
def to_dict(self):
return {
"a" : self.a,
"b" : self.b
}
f = FooClass()
bar(**f.to_dict())
As pointed out in the comments, writing a conformant subclass of the collections.abc.Mapping abstract class is the way to go. To (concretely) subclass this class, you need to implement __getitem__, __len__, and __iter__ to behave consistently like a dictionary would. So that means __getitem__ expects a string, __iter__ returns an iterable of strings, etc.
For a simple example, we'll simply delegate all of these to self.__dict__, but in real code you'd likely want to do something more refined.
from collections.abc import Mapping
class FooClass(Mapping):
def __init__(self, a, b):
self.a = a
self.b = b
def __getitem__(self, x):
return self.__dict__[x]
def __iter__(self):
return iter(self.__dict__)
def __len__(self):
return len(self.__dict__)
def bar(a, b):
return a + b
foo = FooClass(40, 2)
print(bar(**foo))
Aside from reyling on vars(f) or f.__dict__, you could use a dataclass.
from dataclasses import dataclass, asdict
#dataclass
class FooClass:
a: int
b: int
Demo:
>>> f = FooClass(1, 2)
>>> asdict(f)
{'a': 1, 'b': 2}
def bar(a, b):
return a + b
class FooClass:
def __init__(self, a, b):
self.a = a
self.b = b
f = FooClass(1, 2)
print(bar(*f.__dict__.values()))
# print(bar(**f.__dict__)) # Also works
Output:
3
I have two python classes:
class A:
def __init__(self, param1):
self.param1 = param1
class B:
def __init__(self, a):
self.a = a
Now I have an instance of B and need to access param1, I can just write b.a.param1. But the goal is to omit the 'a' part, so access this param with b.param1. I could add property to class B, but I am searching for generic solution - when A class has a lot variables. Is it possible? And would it be clean solution?
This is not the most elegant option and probably a bad practice but you can copy all the attributes of a to be attributes of b using getattr and setattr:
import inspect
class A:
def __init__(self, param1):
self.param1 = param1
class B:
def __init__(self, a):
self.a = a
variables = [i for i in dir(a) if not inspect.ismethod(i) and i[:2] != '__']
for var in variables:
setattr(self, var, getattr(a, var))
This way you can access a's attributes directly:
a = A(1)
b = B(a)
b.param1
which will return
1
There are three classes :
A, B and C
The __init__ of B creates an object of A. Using the mutators, I will be able to change the attributes of A from B for the instance created.
However, I am not unable to find any way to use that instance of A created by B to be used in C without passing the Object explicitly to the __init__ method [ not C.__init(self, object: A) ]
Is there any way to implicitly allow C to use that instance of A ?
I am new to python and not sure if this a valid question. I have looked at other sources where it explicitly passes the object to class C
class A:
def __init__(self):
x = []
y = []
class C :
def __init__(self):
#[get obj1 without passing the instance in init]
self.value = None
def method1():
self.value = len([]) #len(obj1 of A.x)
class B:
def __init__(self):
obj1 = A()
obj1.x = [1,2,3,4]
obj1.y = [1,2,3]
obj2 = B()
print(obj2.value) #this should be the length of x in the instance A created above
Here is a simple example:
class A:
def __init__(self, i = ""):
self.item = i
class B:
def __init__(self):
self.a = A("hello")
class C:
def __init__(self):
b = B()
print(b.a.item)
c = C()
Output:
hello
Let's say we have classes A and B:
class A:
def hello_world(self):
print("hello world")
class B:
def __init__(self):
self.a = A()
def hello_world(self):
self.a.hello_world()
You create an instance of class B (which will create an instance of class A inside):
b = B()
You can then pass a reference to either b or b.a to any function of an instance of class C (either a constructor or not)
class C:
def hello_world(self, a):
a.hello_world()
c = C()
c.hello_world(b.a)
You can also use global variables:
class C:
def hello_world(self):
b.a.hello_world()
c = C()
c.hello_world()
Here the instances of class C will rely on variable b to be in place and just use its a attribute.
Using global variables in classes is generally considered to be hard to maintain and a bad practice. If your class depends on a value or an instance of some class you should pass the reference in the constructor (__init__ function) or in the function that's using it.
If these classes are in different different python files then you can also use these classes by importing the class name and creating an object of that class:
eg:
file1.py
class A:
def __init__(self):
x = []
y = []
file2.py
from file1 import A
class C :
def __init__(self):
[get obj1 without passing the instance in init]
self.value = None
self.obj_a = A()
def xyz(self):
print "in class c"
file3.py
from file2 import C
from file1 import A
Class B:
def __init__(self):
self.obj_a = A()
self.obj_c = C()
def another_func(self):
print self.obj_c.xyz()# it will print "in class c"
Say i am using a class from some python package that looks like the following
class foo(object):
def __init__(self):
self.a = None
self.b = None
self.c = None
self.d = None
self.e = None
self.f = None
Now I need to use attributes b, d, and e of object foobar of class foo in some operation, say call a function qux for instance:
print qux(foobar.b, foobar.d, foobar.e)
Is there any way to create a shorthand version of this, something like the following imagined code:
print qux(*foobar.[b,d,e])
Note the constraints: neither the class nor the function can be changed.
Well, getattr and setattr get you close:
Assignment with setattr (not needed for the next to work, just here for illustration):
class foo(object):
def __init__(self):
for name in 'abcdef':
setattr(self, name, None)
Using values with getattr:
print qux(*(getattr(foobar, name) for name in 'bde'))
With normal, longer names you'd need to do in ['foo', 'bar'] instead.
Since you can't modify the class, how about a function that takes an instance and any number of attribute names, and returns a tuple:
class Foo(object):
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def getitems(obj, *items):
values = []
for item in items:
values.append(getattr(obj, item))
return tuple(values)
f = Foo()
print getitems(f, 'a', 'c') # prints (1, 3)
qux(*getitems(f, 'a', 'c'))
If you are willing to modify the class, you can override __getitem__ to accept a tuple of keys.
class Foo(object):
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def __getitem__(self, item):
if isinstance(item, basestring):
# treat single key as list of length one
item = [item]
values = []
for key in item:
# iterate through all keys in item
values.append(getattr(self, key))
return tuple(values)
f = Foo()
print f['a', 'c'] # prints (1, 3)
qux(*f['a', 'c'])
class A()
att = B()
class B()
...
a = A()
b = B()
a.att = b
How can b get reference of a ? I need to get an attribute of a here.
Thanks!
You can make a generic "Reference()" class, that keep any reference of itself in an attributes dictionnary.
class Reference(object):
def __init__(self):
self.references = {}
def __setattr__(self, key, value):
if hasattr(self, 'references'):
if isinstance(value, Reference):
if not key in value.references:
value.references[key] = []
value.references[key].append(self)
elif value is None and hasattr(self, key):
old = getattr(self, key).references
if key in old and self in old[key]:
old[key].remove(self)
super(Reference, self).__setattr__(key, value)
And then, create your classes :
class A(Reference):
def __init__(self):
super(A, self).__init__()
self.att = None
class B(Reference):
def __init__(self):
super(B, self).__init__()
self.att = None
And use it :
a = A()
b = B()
print 'A references', a.references
print 'B references', b.references
# A references {}
# B references {}
a.att = b
print 'A references', a.references
print 'B references', b.references
# A references {}
# B references {'att': [<__main__.A object at 0x7f731c8fc910>]}
At the end, you'll have back reference to all Reference class from any properties
Easiest way would be to just add an extra function parameter to the method in B that needs A, and pass it through when called. Or, just make B's init take an A as argument, and change the bit in A's init to be att = B(self)
class A(object):
def __init__(self):
self.att = B(self)
class B(object):
def __init__(self, a):
self.a = a
a = A()
a.att.a is a
Or another way,
class A(object):
def __init__(self, b):
b.a = self
self.att = b
class B(object):
pass
a = A(B())
a.att.a is a
This code doesn't make a lot of sense... but if I correctly understand your question...
class A(object):
pass #or whatever you like
class B(object):
def __init__(self, ref): #accept one argument
self.ref = ref
a = A()
b = B(a) #pass `a` as that argument
a.att = b
Might be one answer.
class A(object):
def __init__(self):
self._att=None
#property
def att(self):
return self._att
#att.setter
def att(self, value):
self._att = value
value.parent = self
class B(object):
pass
a = A()
b = B()
a.att = b
print b.parent