How do I access *args variable name(s) in __init__ method?
E.g.
class Parent:
def __init__(self, *args):
# How to access *args variable names here?
# In this example: foo, bar
pass
class Child(Parent):
def __init__(self, foo, bar):
super().__init__(foo, bar)
Inspired by OP's comment, maybe you could do something like
class Parent:
def __init__(self, *args):
self.child_varnames = type(self).__init__.__code__.co_varnames[1:]
class Child(Parent):
def __init__(self, foo, bar):
super().__init__(foo, bar)
In my tests, I get
>>> c = Child(1, 2)
>>> c.child_varnames
('foo', 'bar')
Related
I'm working with classes that have a lot of instance variables, and I want to have classes that inherit every instance variables from them. something like this:
class foo(object):
def __init__(self,thing1,thing2,thing3,thing4,thing5,thingetc):
self.1 = thing1
self.2 = thing2
self.3 = thing3
self.4 = thing4
self.5 = thing5
self.etc = thingetc
class bar(foo):
self.6 = []
a = bar
print a.3
obviously this won't work, but all the documentation that I can find on line is confusing. How do you inherit variables in cases like this?
Currently, your code is invalid syntax as a digit cannot be at the very front of a variable name. However, you can use *args with __dict__:
class foo:
def __init__(self, *args):
self.__dict__ = dict(zip(['var{}'.format(i) for i in range(1, len(args)+1)], args))
f = foo(*range(15))
print(f.var1)
print(f.var14)
Output:
0
13
Use this as a template for your inheritance, emphasis on the super() method:
class Foo:
def __init__(self):
self.name = 'Foo'
class Bar(Foo):
def __init__(self):
super().__init__()
b = Bar()
b.name
# outputs 'Foo'
For your specific type of class (that takes an unknown number of initialization arguments, i.e. *args):
class Foo:
def __init__(self, *args):
self.name = 'Foo'
for i, arg in enumerate(args):
setattr(self, 'thing_' + str(i), arg)
class Bar(Foo):
def __init__(self, *args):
super().__init__(*args)
b = Bar('hello', 'world')
b.name
# outputs 'Foo'
b.thing_0
# outputs 'hello'
b.thing_1
# outputs 'world'
Now I would personally use the **kwargs over *args for specifying unique instance attributes:
class Foo:
def __init__(self, **kwargs):
self.name = 'Foo'
for att in kwargs:
setattr(self, att, kwargs[att])
class Bar(Foo):
def __init__(self, **kwargs):
super().__init__(**kwargs)
b = Bar(value = 4, area = 3.14)
b.name
# outputs 'Foo'
b.value
# outputs 4
b.area
# outputs 3.14
If I do something like this:
class MyClass(object):
def __init__(self, a=MyClass.f):
self.a = a
#classmethod
def f():
print 'tump drump'
I get the following error:
NameError: name 'MyClass' is not defined
Obviously, I could do this:
class MyClass(object):
def __init__(self, a=None):
if a is None:
self.a = MyClass.f
else:
self.a = a
But is there a more elegant way to use a classmethod as default argument of a class method?
No, there isn't, because the functions are created before the class object is. There is not class to reference here, and the use of a sentinel (like None) is the correct way to do this.
Note that there is no need to use an else suite if you assign to a rather than self.a in the if suite:
class MyClass(object):
def __init__(self, a=None):
if a is None:
a = MyClass.f
self.a = a
or you could use a conditional expression:
class MyClass(object):
def __init__(self, a=None):
self.a = MyClass.f if a is None else a
or even:
class MyClass(object):
def __init__(self, a=None):
self.a = a or MyClass.f
if all you need to support is truthy objects (function objects always are 'true' in a boolean context, for example).
For example values from args i can extract like this
globals().update(vars(args))
Is it possible automatically create same properties fro class? Something like this
class SomeClass():
def __init__(self, args):
globals().update(vars(args))
exit(self.location)
I think you meant you want to update the attributes on the class; you can do so with:
class SomeClass():
def __init__(self, args):
vars(self).update(vars(args))
Demo:
>>> class Foo:
... def __init__(self):
... self.bar = 'baz'
...
>>> result = SomeClass(Foo())
>>> result.bar
'baz'
I'd like to do something like this:
class A(object):
def __init__(self, **kwargs):
"""
return exception if certain arguments not set
"""
class B(A):
def __init__(self, **kwargs):
super(B, self).__init__(**kwargs)
Basically, each subclass will require certain arguments to be properly instantiated. They are the same params across the board. I only want to do the checking of these arguments once. If I can do this from the parent init() - all the better.
Is it possible to do this?
Sure. This is not an uncommon pattern:
class A(object):
def __init__(self, foo, bar=3):
self.foo = foo
self.bar = bar
class B(A):
def __init__(self, quux=6, **kwargs):
super(B, self).__init__(**kwargs)
self.quux = quux
B(foo=1, quux=4)
This also insulates you a little from super shenanigans: now A's argspec can change without requiring any edits to B, and diamond inheritance is a little less likely to break.
Absolutely. Parameter and keyword expansion will work naturally when fed into parameter and keyword arguments.
I have the following inheritance chain:
class Foo(object):
def __init__(self):
print 'Foo'
class Bar(Foo):
def __init__(self):
print 'Bar'
super(Foo, self).__init__()
class Baz(Bar):
def __init__(self):
print 'Baz'
super(Bar, self).__init__()
When instantiating Baz class the output is:
Baz
Foo
Why isn't Bar's constructor isn't called?
The call to super() takes the current class as the first argument, not the super class (super() works that out for itself). In this case, the following should fix it... note the change to both super() calls:
class Foo(object):
def __init__(self):
print 'Foo'
class Bar(Foo):
def __init__(self):
print 'Bar'
super(Bar, self).__init__()
class Baz(Bar):
def __init__(self):
print 'Baz'
super(Baz, self).__init__()