How to use a class defined within a class? - python

I am trying to define a class within a class. I am not trying to solve a real world problem with this. I am simply trying to learn Python with this code.
class Foo:
class Bar:
def __init__(self):
self.x = 'Bar'
def __init__(self):
self.x = 'Foo'
self.bar = Bar()
def print(self):
print('self.x:', self.x)
print('self.bar.x:', self.bar.x)
foo = Foo()
foo.print()
When I try to execute this code, I get this error:
Traceback (most recent call last):
File "demo.py", line 14, in <module>
foo = Foo()
File "demo.py", line 8, in __init__
self.bar = Bar()
NameError: name 'Bar' is not defined
What went wrong? When we can define and use functions defined within a function, why not the same for classes? Am I making a mistake in using Bar class?

Use Foo.Bar() instead, because Bar is not a global name.

You need to access Bar through Foo (Bar is not defined in module level)
Replace following line:
self.bar = Bar()
with:
self.bar = Foo.Bar()
or
self.bar = self.Bar()
According to Class definition:
The
class’s suite is then executed in a new execution frame (see section
Naming and binding), using a newly created local namespace and the
original global namespace. (Usually, the suite contains only function
definitions.) When the class’s suite finishes execution, its execution
frame is discarded but its local namespace is saved. A class
object is then created using the inheritance list for the base classes
and the saved local namespace for the attribute dictionary. The class
name is bound to this class object in the original local namespace.

Related

How to get the caller's class definition line number?

There are some packages which has some methods like subscribe or add which let user adds a customized callback function. For debug purpose and curiosity, I would like to know which function and which class in this package actually called my callback function later. So it would be nice if I have the line number of the class.
Minimal working example
# test.py
import inspect
class Foo: # line 5
def caller(self):
print("Hello from caller")
b=Bar()
b.func()
class Bar:
def func(self):
print("Hello from func")
stack = inspect.stack()
the_class = stack[1][0].f_locals["self"].__class__.__name__
the_method = stack[1][0].f_code.co_name
# Need some help here to get value 5
# To do
# ...
print(f"Called by {the_class}.{the_method}()")
f = Foo()
f.caller()
Output:
Hello from caller
Hello from func
Called by Foo.caller()
Q: Inside func, how to get value 5 which is line number of definition of class Foo? Ideally by inspect or other traceback magic, not by searching the string in file.

Using a method from the parent class

I want to call a method from the parent class in a child class.
I use XX.__init__() in my child class and call the press function from the parent class. But it fails when I run the following code:
Func.py
class PC:
def __init__(self):
PCKeyDis = {}
self.PCKeyDis = PCKeyDis
def Press(self,key):
KeyDis = self.PCKeyDis
if len(key)==1 and key.islower():
key = key.upper()
win32api.keybd_event(KeyDis[key],0,0,0)
time.sleep(0.1)
win32api.keybd_event(KeyDis[key],0,win32con.KEYEVENTF_KEYUP,0)
class PCFunc(PC):
def __init__(self):
pass
def Sentence(self,string):
PC.__init__()
strlist = list(string)
for i in xrange(len(strlist)):
if strlist[i] == ' ':
strlist[i] = 'Space'
PC.Press(strlist[i]) #use this function
action.py
import Func
import win32gui
PC = Func.PC()
PCFunc = Func.PCFunc ()
win32gui.SetForegroundWindow(win32gui.FindWindow(winclass,winnm))
PCFunc.Sentence(path)
I get:
unbound method Sentence() must be called with PCFunc instance as first argument (got str instance instead)
If you want to call the constructor of the base class, then you do it on instantiation in the __init__() method, not in the Sentence() method:
def __init__(self):
super(self.__class__, self).__init__()
Since Sentence() is an instance method, you need to call it via an instance of the class (like the error tells you):
pc_func = PCFunc()
pc_func.Sentence(var)
Here you are calling the method with an undefined variable:
PCFunc.Sentence(path)
Instead you need to give a string as parameter, so either write Sentence('path'), or define the variable first:
path = 'my path'
pc_func.Sentence(path)
Do not use the same name as the class name for an instance of the class:
PCFunc = Func.PCFunc ()
Otherwise the variable name storing the instance overwrites the class name.
Apart from that, it is unclear what your code is actually supposed to do. Have a look at the Python code conventions for a first step to making your code more readible. Then do some research about classes and inheritance.
The code you posted does not produce the error you posted. Here is an example that will produce that error:
class Dog:
def do_stuff(self, string):
print string
d = Dog()
d.do_stuff('hello')
Dog.do_stuff(d, 'goodbye')
Dog.do_stuff('goodbye')
--output:--
hello
goodbye
Traceback (most recent call last):
File "1.py", line 9, in <module>
Dog.do_stuff('goodbye')
TypeError: unbound method do_stuff() must be called with Dog instance as first argument (got str instance instead)
An __init__() function can also produce that error:
class Dog:
def __init__(self):
pass
def do_stuff(self, string):
print(string)
Dog.__init__()
--output:--
Traceback (most recent call last):
File "1.py", line 7, in <module>
Dog.__init__()
TypeError: unbound method __init__() must be called with Dog instance as first argument (got nothing instead)
In the line:
d.do_stuff('hello')
the fragment d.do_stuff causes python to create and return a bound method object--which is then immediately executed by the function execution operator () in the fragment ('hello’). The bound method is bound to the instance d, hence the reason it is called a bound method. A bound method automatically passes the instance it contains to the method when the method is executed.
On the other hand, when you write:
Dog.do_stuff(....)
the fragment Dog.do_stuff causes python to create and return an unbound method. An unbound method does not contain an instance, so when an unbound method is executed by the function execution operator (), you must manually pass an instance. (In python3, things changed and you can pass anything as the first argument--an instance of the class isn't required.)

How to detect an instance data attribute change when debugging?

I am trying to debug a multi-threaded program that uses a third-party package.
At some point, one of the attributes of an object (that is not created directly by me) is changed and I can't figure out what changed it. I could not find anything in my code that changes it.
Since this is a third-party package, I prefer not to change its code directly, but rather patch it from the outside as necessary.
My plan was to somehow tap into or wrap the code that sets the attribute and set a breakpoint or print the stack trace from there.
I tried monkey-patching the __setattr__ method of the instance, but it was not triggered.
I also tried to patch the class itself:
def patch_class(target):
def method(self, name, value):
print(name, value)
print("called from", target)
setattr(self, name, value) # break or print trace here
target.__setattr__ = types.MethodType(method, target)
patch_class(WebSocket)
but then all of the attributes are set on the class itself, as the method is bound to it.
Wrapping the class with a proxy does not really help either, since I am not instantiating it myself, but rather get the instance at some point after its creation.
If it matters, the said class is ws4py's WebSocket that is created by another third-party package, but I consider this an exercise in general debugging techniques.
Is there a more "pythonic" way of tapping into the mutation of an existing instance? (hack-ish ways will be appreciated as well)
I ended up creating a __setattr__ for the class.
def setter_fun(self, name, value):
print('setting', name, value)
self.__dict__[name] = value
if name is 'problematic_prop' and value is 'problematicValue':
traceback.print_stack()
# and set the class setter magic method
instance.__class__.__setattr__ = setter_fun
It is also possible to use setattr instead of using the __dict__ magic property:
setattr(self, name, value)
Now, when something sets the instance's problematic_prop to problematicValue, the stack trace will be printed:
>>> class A(object):
def __init__(self):
self.foo = 1
def set_problematic(self):
self.problematic_prop = 'problematicValue'
>>> a = A()
>>> a.__class__.__setattr__ = setter_fun
>>> a.foo = 2
setting foo 2
>>> print(a.foo)
2
>>> a.set_problematic()
setting problematic_prop problematicValue
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 6, in set_problematic
File "<input>", line 5, in setter_fun
NameError: name 'traceback' is not defined
My failed attempts included either trying to attach the __setattr__ to the instance instead of the class, or trying to attach a bound method:
class MyClass(object):
def setter_fun(self, name, value):
print('setting', name, value)
self.__dict__[name] = value
if name is 'problematic_prop' and value is 'problematicValue':
traceback.print_stack()
def set_my_function(self):
# won't work, the function is bound to the current instance (self)
some.instace.__class__.__setattr__ = self.setter_fun

Importing class-type global variables

I'm trying to implement a configuration system contained within a module. The core configuration variable is a class instance and a global variable in this module. It seems that when I import this variable, I cannot use it as a class for some reason.
Consider this minimal example:
foomodule.py:
class FooClass:
number = 5
def bar (self):
return self.number
foo = FooClass
foo.number = 5
main.py
from foomodule import foo
print foo.bar()
Running main.py results in a cryptic error message:
Traceback (most recent call last):
File "main.py", line 2, in <module>
print foo.bar()
TypeError: unbound method bar() must be called with FooClass instance as first argument (got nothing instead)
But I am calling it with a FooClass instance which I'd think should be the self argument like it usually is. What am I doing wrong here?
You only bound foo to the class; you didn't make it an instance:
foo = FooClass # only creates an additional reference
Call the class:
foo = FooClass() # creates an instance of FooClass
In Python you usually don't use accessor methods; just reference foo.number in your main module, rather than use foo.bar() to obtain it.
In your example foo is just an alias for FooClass. I assume that your actual problem is more complicated than your snippet. However, if you really need a class method, you can annotate it with #classmethod decorator.
class FooClass(object):
number = 5
#classmethod
def bar(cls):
return cls.number
To use your the class you could do:
from foomodule import Foo
Foo.bar()
Or you can access the class member directly
Foo.number

How to create a non-instantiable class?

For one of the project I am currently working I was thinking of creating a class that could not be instantiate by a client and only be supplied an instance of through a particular interface i.e. the client would not be able create further instance out of it by some hackery such as:
>>> try:
... raise WindowsError
... except:
... foo = sys.exc_info()
...
>>> foo
(<type 'exceptions.WindowsError'>, WindowsError(), <traceback object at 0x0000000005503A48>)
>>> type(foo[2])()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot create 'traceback' instances
once he has one.
I was successfully able to create a class that couldn't be instantiated. i.e.
>>> class Foo():
... def __init__(self):
... raise TypeError("cannot create 'Foo' instances")
...
>>> bar = Foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
TypeError: cannot create 'Foo' instances
>>> bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined
But how could I use this every same definition to create an instance of the class?
Of course I could do something like this:
>>> class Foo():
... def __init__(self, instantiate = False):
... if not instantiate:
... raise TypeError("cannot create 'Foo' instances")
but I don't find it elegant enough nor does it completely prevent the client from further instantiating it. And no I aint going down the road of building a C++ module for it.
Any suggestions on how to achieve such a thing? import abc?
A brief rational to answer Martijn's question and for completeness:
Actual you could consider the instance of the particular, and related, classes, in question, as nodes in a tree and that both the parent and the children to remain connected, dependent on and cognizant of each other and have a single unique root throughout any instance of python(insured by the use package). Any state changes in a particular node would cause others to update themselves and the database to which they are connect, accordingly. Apart from that I was being curious to know how such a thing could be put in place (the traceback class was teasing me).
What you're doing is a bad idea, you shouldn't do it.
I'm sure there's an other, better solution.
If you do decide to go with your way anyways (you shouldn't), here's how you can create an object without using __init__():
Objects in python are created with the __new__() method. The method __init__() only edits the object which was created by __new__(). For example, __init__() usually initializes some attributes for the object.
When declaring something like x = Foo() what happens is this:
x = object.__new__(Foo) gets called first and creates the object.
Foo.__init__(x) gets called second, it simply initializes some attributes etc. to the already existing object.
This means that you are not required to call Foo() (and as a result, call __init__() too). Instead, you can just call __new__() directly:
class Foo(object):
def __init__(self):
raise TypeError("Cannot create 'Foo' instances.")
>>> x = object.__new__(Foo)
>>> x
<__main__.Foo object at 0x02B074F0>
Our x is now an instance of Foo, without any attributes that is, and it can use any methods defined in Foo class.
If you want, you can create your own replacement function of __init__ for initializing attributes:
def init_foo(foo, name):
foo.name = name
>>> init_foo(x, "Mike")
>>> x.name
'Mike'
This could of course be Foo's instance method too:
class Foo(object):
def __init__(self):
raise TypeError("Cannot create 'Foo' instances.")
def init(self, name):
self.name = name
>>> x = object.__new__(Foo)
>>> x.init("Mike")
>>> x.name
'Mike'
Going even step further, you can even use a classmethod for creating your object with only one call:
class Foo(object):
def __init__(self):
raise TypeError("Cannot create 'Foo' instances.")
#classmethod
def new(cls, name):
obj = object.__new__(cls)
obj.name = name
return obj
>>> x = Foo.new("Mike")
>>> x.name
'Mike'

Categories

Resources