I am working with python at the moment and wonder about something. I'm not too good with object programming, as I've always coded with imperative languages (C mostly).
So I'm asking myself.
Say I have an instance of class_1 called c1, declared this way:
c1 = class_1(bla bla bla...)
Say c1 has a heck lot of variable declarations inside, like
self.x = ...
self.y = ...
self.z = ...
#etc etc
Now, I have an instance of type class_2, called c2. Say c2 is declared INSIDE c1's init() function, like that
c2 = class_2(bla bla bla...)
Now, I wonder how I could... acces the objects of c1 from within c2?
Some could say I could make class_2 inherit from class_1. That's not exactly what I want in fact. The reason is that, class_1 should include in a logical way objects that are of type class_2, but class_2 needs to access variables from class_1!
If I would make class_2 inherit from class_1, I would always have to... declare class_2 objects in the external (to the classes) code. I want to work, in the external code, with class_1 objects. How can I reasonably do that? Starting to be a nightmare...
Thanks!
EDITED:
The context in which I use it... I have, as an assignment, to write a small space video game. I have to calculate trajectories in space. I also have a map. Some parameters such as acceleration, rotation speed, etc... Are specific to the 'map' : i.e. we design a map with obstacles and all, but depending on the map, the some physics constant vary.
I also have a 'physcis' class to handle different calculations related to the trajectory, position upating, etc etc.
So I just want to be able to use the many many many instances of different objects which are contained in the 'map' class, so that I can use these variables inside the physics class!
Is it legit?
Thanks!
From what I can gather from your question, each class_2 is related to a particular class_1. I'll call that class_1 the parent object.
You want to be instantiating a class_2 from within the parent, so something like
class Class_1(object):
def __init__(self):
self.x = 1 # Your instance variables here
self.y = 2
self.class_2_instance = Class_2()
class Class_2(object):
def __init__(self):
pass
is what you want. But you need to access stuff from the parent inside class_2, right?
Simply pass the parent into class_2:
class Class_1(object):
def __init__(self):
self.x = 1 # Your instance variables here
self.y = 2
self.class_2_instance = Class_2(self)
class Class_2(object):
def __init__(self, class_1_instance):
self.class_1_instance = class_1_instance
And now you can, from within class_2, access class_1's variables.
print(self.class_1_instance.x) # prints 1
edit: You've clarified something about your question in the comments since I started writing this response, so now that I know what c1 and c2 are, I can show you how you would use the code I've written here:
c1 = Class_1()
c1 will now have an instance of Class_2 contained within it. That instance will be able to access all of the properties of c1.
One trick is to pass a parent parameter into the class2.__init__ and keep it e.g.:
class class2:
def __init__(self, parent, ):
""" Create an instance of class2 saving the parent """
# You might wish to assert that parent is type class1 here
self.parent = parent
This will let you access class1 members from within class2 as self.parent.member which seems to be what you need.
Even if you can define a class within a class I would urge you not to - it would lead to unclear code and I suspect would actually have more of an overhead than you might expect.
You can define class2 in the same file as class1 and class1 can either inherit from it or simply have members of the type class2 but if you call your class2 an underscored name such as _class2_ then by convention you are making them private to the scope in which they are defined, in this case the file where they are defined, (N.B. In python private is a convention - not enforced - more a gentlemen's agreement with the warning that private members may be modified/removed at any new version).
Note that defining a class is not the same as creating a class instance.
Just to see if it could be done I tried:
Python 2.7.5+ (default, Sep 19 2013, 13:48:49)
[GCC 4.8.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:
... class B:
... def __init__(self):
... self.b = 3
... def __init__(self):
... self.b = B()
... self.a = 2
...
>>> a = A()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __init__
NameError: global name 'B' is not defined
This is because the rest of class A does not exist until init is finished, so class B needs to be defined inside the init before it is used -
>>> class A:
... def __init__(self):
... class B:
... def __init__(self):
... self.b = 3
... self.a = 2
... self.b = B()
...
>>> a=A()
>>> a.b.b
3
>>>
Related
Two of my classes need to have the same method, but they are not related by inheritance.
The following works in Python 3:
class A(object):
def __init__(self):
self.x = 'A'
def printmyx(self):
print(self.x)
class B(object):
def __init__(self):
self.x = 'B'
printmyx = A.printmyx
a = A()
b = B()
a.printmyx()
b.printmyx()
and prints
A
B
However, in Python 2 I'm getting
Traceback (most recent call last):
File "py2test.py", line 18, in <module>
b.printmyx()
TypeError: unbound method printmyx() must be called with A instance as first argument (got nothing instead)
I think the problem is that in Python 3 printmyx is just a regular function while in Python 2 it's an unbound method.
How to make the code work in Python 2?
edit
In my real code, A and B inherit from different parent classes. They need to share one helper method but have no other relation to each other.
Bear in mind that Python does support multiple inheritance, so it's very possible to define a mixin class and have both A and B inherit from it without disturbing the main inheritance hierarchy. I understand you're saying the classes have little in common - but they do both have a variable called x and a method to print it - and to me at least, that's enough in common to consider using inheritance.
But that said, another way to do this is using a class decorator to add the common method:
def add_printmyx(original_class):
def printmyx(self):
print (self.x)
original_class.printmyx = printmyx
return original_class
#add_printmyx
class B(object):
def __init__(self):
self.x = 'B'
b = B()
b.printmyx()
The class decorator takes the original class and adds (or replaces) a printmyx method that prints the contents of x.
Apparently, in Python 2 the original function an unbound method was created from is stored in the im_func attribute.1
To make the code work in Python 2 like it does in Python 3, use
printmyx = A.printmyx.im_func
in B's body.
1 Described in the The standard type hierarchy
section of the Python 2 Data Model documentation.
Why is inheritance not allowed? This is the perfect use case for inheritance.
class Common(object):
def printmyx(self):
print(self.x)
class A(Common):
def __init__(self):
self.x = 'A'
class B(Common):
def __init__(self):
self.x = 'B'
a = A()
b = B()
a.printmyx()
b.printmyx()
Here is a very simple setup:
class A(object):
x = 1
class B(object):
x = 2
class C(object):
x = 3
class B(B):
x = 4
class C(object):
x = 5
print A.x, B.x, C.x
which outputs the expected:
1, 4, 5
is it possible to detect that B has been 'redefined' but C has been 'replaced'? either during the creation phase or subsequently by inspecting the objects?
These classes are being used as configuration objects, there is a loader class above this which imports the module and then introspects to find the classses and their attributes which are then used by the application to instance named parameters. e.g.
class tcp_port(number):
minimum = 1024
maximum = 2048
really python is just being used as a convenient scripting language to define parameters in the main app. These files are available for edit by that most dangerous of people: The Customer So the requirement is to be able to detect at run time if a class has (accidentally) reused a name that has already been defined, but to safely pass the occasional case where a class is redefined, but then tweaks or add some attribute:
class tcp_port(tcp_port):
maximum = 4096
So... I'm hoping for some runtime sanity checker rather than a lint-like solution. Also, this needs to happen when the class is defined, not instanced.
... is there global function which gets called to create a class (or any other object)? a bit like have a __new__ but in the global context?
If the class was redefined in-place, it will have old versions of itself hanging around in the MRO:
>>> [x for x in A.mro() if x.__name__ == A.__name__]
[__main__.A]
>>> [x for x in B.mro() if x.__name__ == B.__name__]
[__main__.B, __main__.B]
>>> [x for x in C.mro() if x.__name__ == C.__name__]
[__main__.C]
So you could detect that occurrence:
def has_redefinition_inplace(classobj):
types = [x for x in classobj.mro() if x.__name__ == classobj.__name__]
return len(types) > 1
This would not be 100% reliable, because there could be legitimately be colliding class names coming into the MRO from different modules.
A good linter will warn on re-declarations without usage. And a good IDE will lint directly in the editor.
For example, PyCharm will highlight these class names with a warning colour:
Another good way to spot these is with coverage in your test suite. Functions with names that were overwritten (common copy-paste errors) can not have test coverage in the function body.
I solved this by defining a parent class for all the classes then using a metaclass to keep a track of the names of the classes created, check for 'derived from itself' and then report any names that were reused.
#!/usr/bin/python
class _Object_Meta(type):
_defined = set()
def __init__(cls, name, bases, dct):
for base in bases:
if name == base.__name__:
break
else:
if name in _Object_Meta._defined:
raise RuntimeError("%s redefined" % name)
_Object_Meta._defined.add(name)
class Object(object):
__metaclass__ = _Object_Meta
class A(Object):
x = 1
class B(Object):
x = 2
class C(Object):
x = 3
class B(B):
x = 4
class C(Object):
x = 5
I am trying to understand variable scopes in Python, most of the things are clear to me except for the part that I don't understand why class variable is not accessible from its method.
In following example mydef1() can't access a, but if a is declared in global scope(outside class definition) it can.
class MyClass1:
a = 25
def mydef1(self):
print(a)
ins1 = MyClass1()
ins1.mydef1()
Output
Traceback (most recent call last):
File "E:\dev\Python\scope_test2.py", line 6, in <module>
ins1.mydef1()
File "E:\dev\Python\scope_test2.py", line 4, in mydef1
print(a)
NameError: name 'a' is not defined
It's important to understand that some of these comments are not equivalent. MyClass.a is a member of the class itself, self.a is a member of the instance of the class.
When you use self.a it will return a from the class, because there is no a on the instance. If there was also an a which was a member of the instance, it would return that instead. Generally the instance a is set using the __init__ constructor. Both of these can exist simultaneously.
class MyClass1:
a = 25
def __init__(self):
self.a = 100
def instance_a(self):
print(self.a)
def change_instance_a(self):
self.a = 5
def class_a(self):
print(MyClass1.a)
def change_class_a(self):
MyClass1.a = 10
# Create two instances
ins1 = MyClass1()
ins2 = MyClass1()
# Both instances have the same Class member a, and the same instance member a
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()
# Now lets change instance a on one of our instances
ins1.change_instance_a()
# Print again, see that class a values remain the same, but instance a has
# changed on one instance only
print()
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()
# Lets change the class member a on just one instance
ins1.change_class_a()
# Both instances now report that new value for the class member a
print()
ins1.instance_a()
ins2.instance_a()
ins1.class_a()
ins2.class_a()
Short answer: That's Python's scoping rules. Nested functions in Python are lexically scoped, but that doesn't apply to things nested in classes.
class Foo:
a = 25
print(a)
class Bar:
print(a)
The first one prints, but the second is a NameError.
Longer answer:
There is a function closure for class-level variables, but it is all wrapped in __class__. (The main use for this is in the super() magic, which is why it no longer needs arguments in Python 3.)
class MyClass1:
a = 25
def mydef1(self):
print(__class__.a)
ins1 = MyClass1()
ins1.mydef1() # 25
Normally, you'd access such things through the self parameter to allow subclasses to override them, but __class__ would even work for a staticmethod, which has neither self, nor cls.
class MyClass1:
a = 25
#staticmethod
def mydef1():
print(__class__.a)
ins1 = MyClass1()
ins1.mydef1() # 25
The class object technically doesn't even exist until after the class declaration finishes executing, that's why you can't do
class Foo:
a = 25
class Bar:
# NameError: free variable '__class__' referenced before assignment
print(__class__.a)
Nor even,
class Foo:
a = 25
def bar():
print(__class__.a)
# NameError: free variable '__class__' referenced before assignment in enclosing scope
bar()
You can, however, access the locals() dict before then.
class Foo:
a = 21
locals()['a'] *= 2
Foo.a # 42
So this works.
class Foo:
a = 25
global foolocals
foolocals = locals()
def bar():
print(foolocals['a'])
bar() # 25
Consider the following class:
class ScopeTest(object):
classvariable = 0
number_of_objects_created = 0
def __init__(self, value=1):
self.instancevariable = value
ScopeTest.number_of_objects_created += 1
def number_of_brothers(self):
print(ScopeTest.number_of_objects_created)
def confusion(self, value=2):
self.classvariable = value
print (f"class: {ScopeTest.classvariable}, self:{self.classvariable}")
And let's see what happens when you play around with it:
>>> a = ScopeTest()
>>> a.instancevariable
1
>>> a.classvariable
0
>>> ScopeTest.classvariable
0
So far so good, but when you assign a new attribute to a:
>>> a.classvariable = 2
>>> a.classvariable
2
>>> ScopeTest.classvariable
0
The same holds if you add the attribute inside a class's method:
>>> a.confusion(4)
class: 0, self:4
These kind of class attributes are good to keep things common to all objects, as the number_of_objects_created:
>>> b = ScopeTest()
>>> b.number_of_brothers()
2
>>> a.number_of_brothers()
2
You could get a little more from this by adding yet another method to the class:
class ScopeTest(object):
...
def other_function(self, classvariable=3):
print(f"class: {ScopeTest.classvariable}\t"
f"instance: {self.classvariable}\t"
f"argument:{classvariable}")
And calling it (after using the first 'confusion' method to set self.classvariable):
>>> a.confusion()
class: 0, self:2
>>> a.other_function()
class: 0 instance: 2 argument:3
By calling print(a) in mydef1, python is looking for a local (or global, as you discovered) variable "a". That is, a variable not directly related to MyClass1 in any way, but such a variable has not been defined yet.
If you're trying to access the class variable "a" (i.e. a is a member of the class itself, not any instance of it), you must use MyClass1.a. Alternatively, because there is no instance variable named "a", you can also use self.a to the same effect. However, as soon as self.a is explicitly defined, self.a == MyClass1.a may not be true. For example:
>>>class MyClass1:
... a = 25
...
>>>my_obj = MyClass1()
>>>MyClass1.a
25
>>>my_obj.a
25
>>>MyClass1.a += 1
>>>MyClass1.a
26
>>>my_obj.a
26
>>>my_obj.a = 5 # explicitly define "a" for this instance; my_obj.a not longer synonymous with MyClass1.a
>>>MyClass1.a += 1
>>>MyClass1.a
27
>>>my_obj.a
5
You need self.a. There is no implicit class scope.
If I have 2 classes defined like this:
class A(object):
a = 10
class B(A):
b = 20
If I create an object:
c = A()
And then do:
c.__class__ = B
Is it a valid way to change ('upgrading') the class of the object, maintaining the primary class attributes and methods and gaining the secondary class attributes and methods?
If true, this only makes sense for this cases where the class to which we are changing the object inherits from the previous class? Best regards.
UPDATED:
To give more context.
I have the following class EmbrionDevice.
class EmbrionDevice(object):
def __init__(self, device_info, *args, **kwargs):
super(EmbrionDevice, self).__init__(*args, **kwargs)
# Serial number unique 64-bit address factory-set
self.shl = device_info['source_addr_long']
# 16-bit network address
self.my = device_info['source_addr']
# Node identifier
self.ni = device_info['node_identifier']
# Parent Address
self.pa = device_info['parent_address']
# Device type, 0-coordinator, 1-router, 2-End Device
self.dt = device_info['device_type']
# Device type identifier xbee or Digi device
self.dd = device_info['device_type_identifier']
# Device attributes summary in a dictionary
self.info = device_info
# Embrion future function
self.function_identifier = None
# Device state definition
self.state = DEV_STATE_CODES['embrion']
self.status = DEV_STATUS_CODES['no status']
That i would later like to change/upgrade, to one of the following specific device classes:
class PassiveDevice(EmbrionDevice):
pass
class ActiveDevice(EmbrionDevice):
pass
Basically i wanted to ease my copy, avoiding the copy of all the attributes.
This is not a valid way to change class of a instance object, A simple example can demonstrate it :-
class A(object):
a = 10
def __init__(self):
self.b = 20
self.c = 30
class B(A):
d = 35
def __init__(self):
self.x = 70
self.y = 80
c = A()
c.__class__ = B
print c
<__main__.B object at 0x02643F10>
So now c is instance of class B, Try printing instance attributes:
print c.x
print c.y
It says:
AttributeError: 'B' object has no attribute 'x'
That's definitely a hack, and this is also a hack, but I find it do be a bit cleaner:
In [1]: class A(object):
...: a = 10
...:
In [2]: class B(A):
...: b = 20
...:
In [3]: c = A()
In [4]: new_c = B()
In [5]: new_c.__dict__.update(c.__dict__.copy())
In [7]: repr(new_c)
Out[7]: '<__main__.B object at 0x102f32050>'
In [8]: new_c.b
Out[8]: 20
I'm not sure if your approach would work or not, but, this way, you're copying the properties of the old object into a new object that was properly instantiated. If you change .__class__, you can't guarantee that the old variable will reference a properly-created new-class object, as __init__(), __new__(), etc. wouldn't run.
To copy functions, and, this is ugly... but, you could take an approach like this:
In [18]: for name, obj in c.__class__.__dict__.iteritems():
....: if hasattr(obj, '__call__'):
....: # Copy the function.
....:
test
There are various hacky methods of adding functions to an existing object dynamically. They're all ugly, but, they can be found here.
You have a misunderstanding of what are "class attributes" in Python -
All instance attributes are kept in the instance itself: it does have a __dict__ attribute which is a dictionary where all the attributes defined by code like self.shl = device_info['source_addr_long'] is kept. (This statement creates an shl entry on that dict, for example).
These assignments are run inside the __init__method. If you change an object's class by assigning to its __class__ , it works in a sense: that is its new class. The methods the new class may have defined are now acessible. But all the attributes which were set in the previous class' __init__ still exist, because they are set on the instance's __dict__ that was not changed;. From what I got, this may be exactly what you want - but please note that methods on the original class (as well as class attributes - i.e., attributes defined on the class body itself) will not be acessible, unless the new class itself inherits from the original class. As in the example you show, this is what you are doing, this approach might actually work for you.
But be careful, and do some extensive unit testing, and testing on the interactive console.
An alternative for you might be to use zope.interface - tis will allow you to have a single object, but that "looks like" an object with different attributes and methods to other parts of the code, which might need an specific interface.
Dealing with classes (nested etc) does not look easy in Python, surprisingly! The following problem appeared to me recently and took several hours (try, search ...) without success. I read most of SO related links but none of them has pointed the issue presented here!
#------------------------------------
class A:
def __init__(self):
self.a = 'a'
print self.a
class B(A):
def __init__(self):
self.b = 'b'
A.a = 'a_b'
print self.b, A.a
#------------------------------------
class C:
class A:
def __init__(self):
self.a = 'a'
print self.a
class B(A):
def __init__(self):
self.b = 'b'
A.a = 'a_b'
print self.b, A.a
#------------------------------------
#------------------------------------
>>> c1 = A()
a
>>> c1.a
'a'
>>> c2 = B()
b
>>> c2.a, c2.b
('a_b', 'b')
>>> c3 = C()
>>> c4 = c3.A()
a
>>> c4.a
'a'
>>> c5 = c3.B()
b a_b
>>> c5.b
'b'
>>> c5.a
Traceback (most recent call last):
File "", line 1, in
AttributeError: B instance has no attribute 'a'
Where is the problem in the code?
AND
In both cases it seems that when B(A) is initialized A() is not initialized. What is the solution for this issue? Note that the term A.__init__() being called inside B()'s __init__() does not work!
Updates:
class Geometry:
class Curve:
def __init__(self,c=1):
self.c = c #curvature parameter
print 'Curvature %g'%self.c
pass #some codes
class Line(Curve):
def __init__(self):
Geometry.Curve.__init__(self,0) #the key point
pass #some codes
g = Geometry()
C = g.Curve(0.5)
L = g.Line()
which results in:
Curvature 0.5
Curvature 0
what I was looking for.
The code executed in a method runs in the local scope of that method. If you access an object that is not in this scope, Python will look it up in the global/module scope, NOT in the class scope or the scope of any enclosing class!
This means that:
A.a = 'a_b'
inside C.B.__init__ will set the class attribute of the global A class, not C.A as you probably intended. For that you would have to do this:
C.A.a = 'a_b'
Also, Python will not call parent methods if you override them in subclasses. You have to do it yourself.
The scoping rules mean that if you wanted to call the __init__ method of the parent class inside C.B.__init__, it has to look like this:
C.A.__init__(self)
and NOT like this:
A.__init__(self)
which is probably what you've tried.
Nested classes seems so unpythonic, even if considered as factories. But to answer your question: There simply is no c5.a (instance of C.B). In the init-method of C.B you add to the CLASS C.A an attribute a, but not to C.B! The class A does already have an attribute a, if instantiated! But the object of class B (and even the class) doesn't!
You must also keep in mind, that __init__ is not an constructor like in C++ or Java! The "real constructor" in python would be __new__. __init__ just initializes the instance of a class!
class A:
c = 'class-attribute'
def __init__(self):
self.i = 'instance-attribute'
So in this example c is a class-attribute, where i is an attribute of the instance.
Even more curios, is your attempt to add an attribute to the baseclass at the moment of the instantiation of the child-class. You are not getting a "late" inheritance-attribute that way.
You simply add to the class A an additional attribute, which surprises me to even work. I guess you are using python 3.x?
The reason for this behaviour? Well, i guess it has to do with pythons neat feature that in python definitions are executed(AFAIK).
The same reason why:
def method(lst = []):
is almost ever a bad idea. the deafult-parameter gets bound at the moment of the definition and you won't generate a new list-object every-time you call the method, but reusing the same list-object.