In the following example, is there any way the a attribute in A can be accessed by the B class or C inner class?
class A:
def __init__(self, a):
self.a = a
def C_test(self):
for i in range(4):
c = self.C()
class C:
print(self.a)
class B(A):
def __init__(self):
print(self.a)
How come I get this error?
Traceback (most recent call last):
File "/Users/home/Desktop/Pygame/test.py", line 1, in <module>
class A:
File "/Users/home/Desktop/Pygame/test.py", line 10, in A
class C:
File "/Users/home/Desktop/Pygame/test.py", line 11, in C
print(self.a)
NameError: name 'self' is not defined
self is not a special variable name in Python - it's just the name that is typically given to the first argument of a method, which is bound to the object calling that method.
Your self.a in class C doesn't appear inside a method definition where self is listed as an argument, so self has no meaning there.
For your B example, this general idea does work, just not automatically. Python does Python does have broadly similar rules to Java when it comes to single inheritance. The reason it doesn't work automatically here is because of Python's data model - member variables are attached to each unique instance, rather than being an intrinsic part of the class. They're usually, as in your examples, attached to the instance when __init__ runs. So, for your B to have an a, it would need to be attached by A.__init__. Python will automatically run that for you if you don't write a B.__init__, but if you do have that, you need to call up explicitly. The easiest way is this:
class B(A):
def __init__(self):
super().__init__()
Again, you might recognise this idea of explicitly chaining up using super from other languages - although the spelling is a bit different here. But the only major technical difference between Python and Java in this respect is that Python needs the parent constructor to be called for the instance variables to even exist (in Java, they will still exist, but might not have the right value, or even be initialised).
For your C example, Python is very different from Java here. Python doesn't usually use the term 'inner class', although you can define a class inside another class (note that you haven't in your code sample, though) - but instances of the inner class won't be associated with an instance of the outer class. So, they behave a bit more like Java inner static classes. You could associate them explicitly by doing something like this:
class A:
def __init__(self, a):
self.a = a
self.my_C = A.C(self)
class C:
def __init__(self, A_self):
print(A_self.a)
But this isn't exactly common, and depending on exactly what your problem is, there is almost always a better way to solve it than trying to shoehorn Java idioms into Python code.
If you derive a class from your own base-class, you have to call the constructor of the base-class with super to inherit the base-classes attributes:
class A(object):
def __init__(self, a):
self.a = a
class B(A):
def __init__(self):
super(B, self).__init__(self)
After running this you can do this for example:
a = A(1)
b = B()
b.a = a.a
b has declared no attribute a, but inherits it from class A by calling the constructor of A via super in class B.
Now b.a evaluates 1 cause it is set to the value of a.a.
Related
Is there any way to connect 2 classes (without merging them in 1) and thus avoiding repetition under statement if a: in class Z?
class A:
def __init__(self, a):
self.a = a
self.b = self.a + self.a
class Z:
def __init__(self, z, a=None):
self.z = z
if a: # this part seems like repetition
self.a = a.a
self.b = a.b
a = A('hello')
z = Z('world', a)
assert z.a == a.a # hello
assert z.b == a.b # hellohello
Wondering if python has some tools. I would prefer to avoid loop over instance variables and using setattr.
Something like inheriting from class A to class Z, Z(A) or such.
Here's a trivial example of class inheritance that may help you to understand:
class A:
def __init__(self, a):
self._a = a
self._b = self.a + self.a
class Z(A):
def __init__(self, z, a):
super().__init__(a)
self._z = z
clazz = Z('Hello', 'world')
print(clazz._z, clazz._a)
Conceptually, the standard techniques for associating an A instance with a Z instance are:
Using composition (and delegation)
"Composition" simply means that the A instance itself is an attribute of the Z instance. We call this a "has-a" relationship: every Z has an A that's associated with it.
In normal cases, we can simply pass the A instance to the Z constructor, and have it assign an attribute in __init__. Thus:
class A:
def __init__(self, a):
self.a = a
self.b = self.a + self.a
def action(self): # added for demonstration purposes.
pass
class Z:
def __init__(self, z, a=None):
self.z = z
self._a = a # if not None, this will be an `A` instance
Notice that the attribute for the a instance is specially named to avoid conflicting with the A class attribute names. This is to avoid ambiguity (calling it .a makes one wonder whether my_z.a should get the .a attribute from the A instance, or the entire instance), and to mark it as an implementation detail (normally, outside code won't have a good reason to get the entire A instance out of the Z; the entire point of delegation is to make it so that users of Z don't have to worry about A's interface).
One important limitation is that the composition relationship is one-way by nature: self._a = a gives the Z class access to A contents, but not the other way around. (Of course, it's also possible to build the relationship in both directions, but this will require some planning ahead.)
"Delegation" means that we use some scheme in the code, so that looking something up in a Z instance finds it in the composed A instance when necessary. There are multiple ways to achieve this in Python, at least two of which are worth mentioning:
Explicit delegation per attribute
We define a separate property in the Z class, for each attribute we want to delegate. For example:
# within the `Z` class
#property
def a(self):
return self._a.a
# The setter can also be omitted to make a read-only attribute;
# alternately, additional validation logic can be added to the function.
#a.setter
def a(self, value):
self._a.a = value
For methods, using the same property approach should work, but it may be simpler to make a wrapper function and calling it:
def action(self):
return self._a.action()
Delegation via __getattr__
The __getattr__ magic ("dunder") method allows us to provide fallback logic for looking up an attribute in a class, if it isn't found by the normal means. We can use this for the Z class, so that it will try looking within its _a if all else fails. This looks like:
def __getattr__(self, name):
return getattr(self._a, name)
Here, we use the free function getattr to look up the name dynamically within the A instance.
Using inheritance
This means that each Z instance will, conceptually, be a kind of A instance - classes represent types, and inheriting Z from A means that it will be a subtype of A.
We call this an "is-a" relationship: every Z instance is an A instance. More precisely, a Z instance should be usable anywhere that an A instance could be used, but also Z might contain additional data and/or use different implementations.
This approach looks like:
class A:
def __init__(self, a):
self.a = a
self.b = self.a + self.a
def action(self): # added for demonstration purposes.
return f'{self.z.title()}, {self.a}!'
class Z(A):
def __init__(self, z, a):
# Use `a` to do the `A`-specific initialization.
super().__init__(a)
# Then do `Z`-specific initialization.
self.z = z
The super function is magic that finds the A.__init__ function, and calls it as a method on the Z instance that's currently being initialized. (That is: self will be the same object for both __init__ calls.)
This is clearly more convenient than the delegation and composition approach. Our Z instance actually has a and b attributes as well as z, and also actually has a action method. Thus, code like my_z.action() will use the method from the A class, and accessing the a and b attributes of a Z instance works - because the Z instance actually directly contains that data.
Note in this example that the code for action now tries to use self.z. this won't work for an A instance constructed directly, but it does work when we construct a Z and call action on it:
>>> A('world').action()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in action
AttributeError: 'A' object has no attribute 'z'
>>> Z('hello', 'world').action()
'Hello, world!'
We say that such an A class, which doesn't properly function on its own, is abstract. (There are more tools we can use to prevent accidentally creating an unusable base A; these are outside the scope of this answer.)
This convenience comes with serious implications for design. It can be hard to reason about deep inheritance structures (where the A also inherits from B, which inherits from C...) and especially about multiple inheritance (Z can inherit from B as well as A). Doing these things requires careful planning and design, and a more detailed understanding of how super works - beyond the scope of this answer.
Inheritance is also less flexible. For example, when the Z instance composes an A instance, it's easy to swap that A instance out later for another one. Inheritance doesn't offer that option.
Using mixins
Essentially, using a mixin means using inheritance (generally, multiple inheritance), even though we conceptually want a "has-a" relationship, because the convenient usage patterns are more important than the time spent designing it all up front. It's a complex, but powerful design pattern that essentially lets us build a new class from component parts.
Typically, mixins will be abstract (in the sense described in the previous section). Most examples of mixins also won't contain data attributes, but only methods, because they're generally designed specifically to implement some functionality. (In some programming languages, when using multiple inheritance, only one base class is allowed to contain data. However, this restriction is not necessary and would make no sense in Python, because of how objects are implemented.)
One specific technique common with mixins is that the first base class listed will be an actual "base", while everything else is treated as "just" an abstract mixin. To keep things organized while initializing all the mixins based on the original Z constructor arguments, we use keyword arguments for everything that will be passed to the mixins, and let each mixin use what it needs from the **kwargs.
class Root:
# We use this to swallow up any arguments that were passed "too far"
def __init__(self, *args, **kwargs):
pass
class ZBase(Root):
def __init__(self, z, **kwargs):
# a common pattern is to just accept arbitrary keyword arguments
# that are passed to all the mixins, and let each one sort out
# what it needs.
super().__init__(**kwargs)
self.z = z
class AMixin(Root):
def __init__(self, **kwargs):
# This `super()` call is in case more mixins are used.
super().__init__(**kwargs)
self.a = kwargs['a']
self.b = self.a + self.a
def func(self): # This time, we'll make it do something
return f'{self.z.title()}, {self.a}!'
# We combine the base with the mixins by deriving from both.
# Normally there is no reason to add any more logic here.
class Z(ZBase, AMixin): pass
We can use this like:
>>> # we use keyword arguments for all the mixins' arguments
>>> my_z = Z('hello', a='world')
>>> # now the `Z` instance has everything defined in both base and mixin:
>>> my_z.func()
'Hello, world!'
>>> my_z.z
'hello'
>>> my_z.a
'world'
>>> my_z.b
'worldworld'
The code in AMixin can't stand on its own:
>>> AMixin(a='world').func()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in func
AttributeError: 'AMixin' object has no attribute 'z'
but when the Z instance has both ZBase and AMixin as bases, and is used to call func, the z attribute can be found - because now self is a Z instance, which has that attribute.
The super logic here is a bit tricky. The details are beyond the scope of this post, but suffice to say that with mixin classes that are set up this way, super will forward to the next, sibling base of Z, as long as there is one. It will do this no matter what order the mixins appear in; the Z instance determines the order, and super calls whatever is "next in line". When all the bases have been consulted, next in line is Root, which is just there to intercept the kwargs (since the last mixin doesn't "know" it's last, and passes them on). This is necessary because otherwise, next in line would be object, and object.__init__ raises an exception if there are any arguments.
For more details, see What is a mixin and why is it useful?.
I have a series of Python classes in a file. Some classes reference others.
My code is something like this:
class A():
pass
class B():
c = C()
class C():
pass
Trying to run that, I get NameError: name 'C' is not defined. Fair enough, but is there any way to make it work, or do I have to manually re-order my classes to accommodate? In C++, I can create a class prototype. Does Python have an equivalent?
(I'm actually playing with Django models, but I tried not complicate matters).
Actually, all of the above are great observations about Python, but none of them will solve your problem.
Django needs to introspect stuff.
The right way to do what you want is the following:
class Car(models.Model):
manufacturer = models.ForeignKey('Manufacturer')
# ...
class Manufacturer(models.Model):
# ...
Note the use of the class name as a string rather than the literal class reference. Django offers this alternative to deal with exactly the problem that Python doesn't provide forward declarations.
This question reminds me of the classic support question that you should always ask any customer with an issue: "What are you really trying to do?"
In Python you don't create a prototype per se, but you do need to understand the difference between "class attributes" and instance-level attributes. In the example you've shown above, you are declaring a class attribute on class B, not an instance-level attribute.
This is what you are looking for:
class B():
def __init__(self):
self.c = C()
This would solve your problem as presented (but I think you are really looking for an instance attribute as jholloway7 responded):
class A:
pass
class B:
pass
class C:
pass
B.c = C()
Python doesn't have prototypes or Ruby-style open classes. But if you really need them, you can write a metaclass that overloads new so that it does a lookup in the current namespace to see if the class already exists, and if it does returns the existing type object rather than creating a new one. I did something like this on a ORM I write a while back and it's worked very well.
A decade after the question is asked, I have encountered the same problem. While people suggest that the referencing should be done inside the init method, there are times when you need to access the data as a "class attribute" before the class is actually instantiated. For that reason, I have come up with a simple solution using a descriptor.
class A():
pass
class B():
class D(object):
def __init__(self):
self.c = None
def __get__(self, instance, owner):
if not self.c:
self.c = C()
return self.c
c = D()
class C():
pass
>>> B.c
>>> <__main__.C object at 0x10cc385f8>
All correct answers about class vs instance attributes. However, the reason you have an error is just the order of defining your classes. Of course class C has not yet been defined (as class-level code is executed immediately on import):
class A():
pass
class C():
pass
class B():
c = C()
Will work.
I am having some problem using multiple inheritance in Python and can't understand what I am doing wrong.
I have three classes A,B,C defined as follows it does not work.
class A(object):
def __init__(**kwargs):
.
.
class B(object):
def __init__(**kwargs):
# prepare a dictionary "options" with the options used to call A
super(B,self).__init__(**options)
def coolmethod(x):
#some cool stuff
For A and B I don't have any problems.
I want to create a third class C that inherits both from A and B
so that I can the coolmethod defined in B, but would like to use the constructor defined in A.
Trying to define class C(A,B) does not work because the MRO is not defined.
But defining class C(B,A) does not allow me to use A.init rather than B.init.
How can I solve the issue?
You can call A.__init__() directly instead of using super() in C:
class C(B,A):
def __init__(self, **kwargs):
A.__init__(self, **kwargs)
You can use
class A(object):
def __init__(self, **kwargs):
super(A, self).__init__(**kwargs)
if you expect multiple inheritance from A and something else. This way, A.__init__ will always be called.
The order is important because of the way method resolution works in python. If you have C inherit from (A, B), it means that if you invoke a method on C that exists both on A and B, the one on A is selected (it has precedence). If you write super(A, self).method in class A, it means you want to extend functionality provided by method. Therefore, it would be strange to skip over one such extension if both A and B had such extensions and C inherited from both. That's why when you call C.method, it will execute A.method, which will call B.method when it invokes super(A, self).method. In other terms, it's as if A inherited from B for the purpose of method extension. This is different when C inherits from (B, A).
Note that __init__'s first argument should always be self, just like for every method.
I have looked at many questions posted here to find an answer to my problem, but I wasn't successful. The problem might be, that I just don't know for what keywords I should look. So my problem is the following:
I've got a program, that has a multi-level inheritance and I am trying to figure out how the best way would be to change the class of an object to a subclass. Let's say I have the following code:
class A(object):
def __init(self, filename, ..)
super(A, self).__init__()
...some assignments here
class B(A):
def __init(self, filename, ..)
super(B, self).__init__()
...some assignments here
class C(A):
def __init(self, filename, ..)
super(C, self).__init__()
...some assignments here
and so on...
I always want to start initialising an object of class A. Depending on the type of the file that is used, the assignments may differ and depending on those assignments I can determine what kind of file it is. So now I want to change the class of the object to whatever class is suitable..
I know I could pass the A object to B or C and use copy or deepcopy, but in A i am assigning an object of which the reference should not change and some others where it should change. Also I would need to delete that object of A, after initialising B or C.
class B(A):
def __init__(self, filename, objA = None):
if objA is not None:
self.__dict__ = copy.deepcopy(objA.__dict__)
del(objA)
else:
super(B, self).__init__(filename)
Also there is another possibility by changing the _class attribute to another class and use some kind of update method of the new class.
I would like to know, which of the two approaches is recommended or is there even a better one. Thanks in advance.
What you want is a factory: a function that opens the file, reads the stuff it needs to read to figure out what kind of file it is, and then initializes and returns an object of the appropriate class.
If you want to keep it a class, you'd want to override __new__() and then return an object of the desired class instead of its own class. (You could also do it using a metaclass and overriding __call__() on that.)
You can change an instance's class after instantiating it as well, by changing its __class__ attribute to point to the desired class. That'll work, but the factory is going to be more familiar to other programmers who will read your code.
This code will explain what you want to do
class B(object):
def x(self):
print 'b'
class A(object):
def x(self):
print 'a'
Now we create two objects
a = a()
b = b()
a.x()
a
b.x()
b
now if you want 'a' to become a B object
a.__class__ = type(b)
or
a.__class__ = B
now the x attribute is from the B class.
a.x()
b
I have a series of Python classes in a file. Some classes reference others.
My code is something like this:
class A():
pass
class B():
c = C()
class C():
pass
Trying to run that, I get NameError: name 'C' is not defined. Fair enough, but is there any way to make it work, or do I have to manually re-order my classes to accommodate? In C++, I can create a class prototype. Does Python have an equivalent?
(I'm actually playing with Django models, but I tried not complicate matters).
Actually, all of the above are great observations about Python, but none of them will solve your problem.
Django needs to introspect stuff.
The right way to do what you want is the following:
class Car(models.Model):
manufacturer = models.ForeignKey('Manufacturer')
# ...
class Manufacturer(models.Model):
# ...
Note the use of the class name as a string rather than the literal class reference. Django offers this alternative to deal with exactly the problem that Python doesn't provide forward declarations.
This question reminds me of the classic support question that you should always ask any customer with an issue: "What are you really trying to do?"
In Python you don't create a prototype per se, but you do need to understand the difference between "class attributes" and instance-level attributes. In the example you've shown above, you are declaring a class attribute on class B, not an instance-level attribute.
This is what you are looking for:
class B():
def __init__(self):
self.c = C()
This would solve your problem as presented (but I think you are really looking for an instance attribute as jholloway7 responded):
class A:
pass
class B:
pass
class C:
pass
B.c = C()
Python doesn't have prototypes or Ruby-style open classes. But if you really need them, you can write a metaclass that overloads new so that it does a lookup in the current namespace to see if the class already exists, and if it does returns the existing type object rather than creating a new one. I did something like this on a ORM I write a while back and it's worked very well.
A decade after the question is asked, I have encountered the same problem. While people suggest that the referencing should be done inside the init method, there are times when you need to access the data as a "class attribute" before the class is actually instantiated. For that reason, I have come up with a simple solution using a descriptor.
class A():
pass
class B():
class D(object):
def __init__(self):
self.c = None
def __get__(self, instance, owner):
if not self.c:
self.c = C()
return self.c
c = D()
class C():
pass
>>> B.c
>>> <__main__.C object at 0x10cc385f8>
All correct answers about class vs instance attributes. However, the reason you have an error is just the order of defining your classes. Of course class C has not yet been defined (as class-level code is executed immediately on import):
class A():
pass
class C():
pass
class B():
c = C()
Will work.