Derived class doesn't recognise arguments of method from parent - python

I'm trying to make a set of functions to operate easily through some data.
The problem I'm facing is: it seems to recognize and use methods from the parent class, except one: show(), giving me errors about unexpected arguments.
Here's a sample of the classes:
from treelib import Tree, Node
class Join(Tree):
def __init__(self, id, desc, childs=(), *args, **kwargs):
Tree.__init__(self, *args, **kwargs)
self.id = id
self.desc = desc
self.value = None
self.parent = None
self.childs = None
self.create_node(tag=desc, identifier=id)
for i in childs:
self.paste(self.id, i)
def getSons(self):
sons = self.children(self.id)
return sons
def getID(self):
return self.id
def getDesc(self):
return self.desc
def show(self):
self.show(key=lambda x: x.tag, reverse=True, line_type='ascii-em')
class Get(Tree):
def __init__(self, id, desc, primitive, *args, **kwargs):
Tree.__init__(self, *args, **kwargs)
self.id = id
self.desc = desc
self.parent = None
self.primitive = primitive
self.create_node(tag=desc, identifier=id, data=primitive)
def getID(self):
return self.id
def getDesc(self):
return self.desc
def show(self):
self.show(key=lambda x: x.tag, reverse=True, line_type='ascii-em')
class Primitive():
def __init__(self, value):
self.value = value
def getValue(self):
return self.value
def show(self):
pass
#print '\t -> ' + str(self.value)
If, for example, I do this on another .py
prim = Primitive(0)
get1 = Get("get1", "Some random thing", prim)
get1.show()
it tells me that key is an unexpected argument. I even checked the library's .py file, the argument is there:
def show(self, nid=None, level=ROOT, idhidden=True, filter=None,
key=None, reverse=False, line_type='ascii-ex'):
The create_node() method works just fine! That's what's weird. Any suggestions?
I'm using treelib in Python 2.7

Your method show() calls itself:
def show(self):
self.show(key=lambda x: x.tag, reverse=True, line_type='ascii-em')
Removed it in Get and change it in Join to:
def show(self):
super(Join, self).show(key=lambda x: x.tag, reverse=True, line_type='ascii-em')

Related

Can I change the default behavior of my parent class method in my subclass method?

I'm learning simple python inheritance and I want that one of my parent class method default argument is changed conditionally to one of my subclass argument value, and I don't know if this is possible.
Here is an example of what I'd like to do:
class Parent(object):
def __init__(self, name):
self.name = name
def doSomething(self, name, strict = True):
if strict:
return self.name
else:
return name
class Child(Parent):
def __init__(self, name, **kwargs):
super(Child, self).__init__(name)
if 'changeBehavior' in kwargs:
# Here is the thing:
# Can I change the default value of strict to kwargs['changeBehavior']
# in a way that when I later call doSomething(), it will behave according
# to its new default behavior?
def doSomething(self, name, strict = kwargs['changeBehavior']):
super(Child, self).doSomething(strict = kwargs['changeBehavior'])
If this can be done in this way, is there any other method to do so?
Thanks
You can use partial.
from functools import partial
class Parent(object):
def __init__(self, name):
self.name = name
def doSomething(self, name, strict=True):
print('Got strict={}'.format(strict))
if strict:
return self.name
else:
return name
class Child(Parent):
def __init__(self, name, **kwargs):
super().__init__(name)
change_behavior = kwargs.get('changeBehavior')
if change_behavior is not None:
self.doSomething = partial(self.doSomething, strict=change_behavior)
p = Parent('name')
c = Child('name', changeBehavior=False)
p.doSomething('name')
c.doSomething('name')
outputs
Got strict=True
Got strict=False

Using decorators to implement Observer Pattern in Python3

This question is not in general about the observer pattern. It is focused on the use of decorators in that pattern. The question is based on the answer of a similar question.
#!/usr/bin/env python3
class Observable:
"""
The object that need to be observed. Alternative names are 'Subject'.
In the most cases it is a data object.
"""
def __init__(self):
self._observers = []
def register_observer(self, callback):
self._observers.append(callback)
return callback
def _broadcast_observers(self, *args, **kwargs):
for callback in self._observers:
callback(*args, **kwargs)
class TheData(Observable):
"""
Example of a data class just for demonstration.
"""
def __init__(self, data):
Observable.__init__(self)
self._data = data
#property
def data(self):
return self._data
#data.setter
def data(self, data):
self._data = data
self._broadcast_observers()
class TheGUIElement:
"""
Example of a gui class (Widget) just for demonstration.
e. g. it could be a text field in GUI.
"""
def __init__(self, data):
self._data = data
#data.register_observer(self._data_updated)
self._redraw()
def _redraw(self):
print('in _redraw(): ' + data.data)
#Observable.register_observer
def _data_updated(self, **kwargs):
"""
This is the callback that is called by the Observable if the
data changed.
"""
print('in _data_updated() - kwargs: {}'.format(kwargs))
self._redraw()
if __name__ == '__main__':
data = TheData('DATA')
gui = TheGUIElement(data)
data.data = 'SECOND DATA'
This code doesn't work because of this error.
Traceback (most recent call last):
File "./o.py", line 42, in <module>
class TheGUIElement:
File "./o.py", line 55, in TheGUIElement
#Observable.register_observer
TypeError: register_observer() missing 1 required positional argument: 'callback'
It is unclear to me how to use a decorator for to register the observers (e.g. TheGUIElement).
To register the callback, you need to have an actual object. In your code, how is #Observable.register_observer supposed to find which instance is should register on?
Please drop that Observable thing that's a javaism, cumbersome in python.
Look at this.
#!/usr/bin/env python
class SomeData(object):
def __init__(self, value):
self.callbacks = []
self.foo = value
def register(self, callback):
self.callbacks.append(callback)
return callback
def notify(self, *args, **kwargs):
for callback in self.callbacks:
callback(self, *args, **kwargs)
class SomeGUI(object):
def redraw(self, obj, key, newvalue):
print('redrawing %s with value %s' % (self, newvalue))
if __name__ == '__main__':
my_data = SomeData(42)
# Register some function using decorator syntax
#my_data.register
def print_it(obj, key, value):
print('Key %s changed to %s' % (key, value))
# Register the SomeGUI element
my_gui = SomeGUI()
my_data.register(my_gui.redraw)
# Try changing it. Note my_data is dumb for now, notify manually.
my_data.foo = 10
my_data.notify("foo", 10)
I intentionally removed automatic notifications to illustrate registration by itself.
Let's add it back. But there is no point using that Observable class. Let's make it lighter, simply defining an event class.
#!/usr/bin/env python3
class Event(object):
def __init__(self):
self.callbacks = []
def notify(self, *args, **kwargs):
for callback in self.callbacks:
callback(*args, **kwargs)
def register(self, callback):
self.callbacks.append(callback)
return callback
class SomeData(object):
def __init__(self, foo):
self.changed = Event()
self._foo = foo
#property
def foo(self):
return self._foo
#foo.setter
def foo(self, value):
self._foo = value
self.changed.notify(self, 'foo', value)
class SomeGUI(object):
def redraw(self, obj, key, newvalue):
print('redrawing %s with value %s' % (self, newvalue))
if __name__ == '__main__':
my_data = SomeData(42)
# Register some function using decorator syntax
#my_data.changed.register
def print_it(obj, key, value):
print('Key %s changed to %s' % (key, value))
# Register the SomeGUI element
my_gui = SomeGUI()
my_data.changed.register(my_gui.redraw)
# Try changing it.
my_data.foo = 10
As you probably noted now, the decorator syntax is useful in those circumstances:
You have a single registry. Either a singleton or the class itself class are first-order objects, and most are singletons.
You dynamically define the function and register it as you go.
Now, those manual getters/setters you have are cumbersome as well, if you have many why not factor them out?
#!/usr/bin/env python3
class Event(object):
def __init__(self):
self.callbacks = []
def notify(self, *args, **kwargs):
for callback in self.callbacks:
callback(*args, **kwargs)
def register(self, callback):
self.callbacks.append(callback)
return callback
#classmethod
def watched_property(cls, event_name, key):
actual_key = '_%s' % key
def getter(obj):
return getattr(obj, actual_key)
def setter(obj, value):
event = getattr(obj, event_name)
setattr(obj, actual_key, value)
event.notify(obj, key, value)
return property(fget=getter, fset=setter)
class SomeData(object):
foo = Event.watched_property('changed', 'foo')
def __init__(self, foo):
self.changed = Event()
self.foo = foo
class SomeGUI(object):
def redraw(self, obj, key, newvalue):
print('redrawing %s with value %s' % (self, newvalue))
if __name__ == '__main__':
my_data = SomeData(42)
# Register some function using decorator syntax
#my_data.changed.register
def print_it(obj, key, value):
print('Key %s changed to %s' % (key, value))
# Register the SomeGUI element
my_gui = SomeGUI()
my_data.changed.register(my_gui.redraw)
# Try changing it.
my_data.foo = 10
For reference, all three programs output the exact same thing:
$ python3 test.py
Key foo changed to 10
redrawing <__main__.SomeGUI object at 0x7f9a90d55fd0> with value 10
Even though the thread is kinda old (probably the problem is already solved), I would like to share a solution of mine to the "Decorated Observer Pattern" problem:
https://pypi.org/project/notifyr/
I created a package that implements decorators which add the observer-observed methods/attributes to python classes. I managed to use the package in a Django project too, but with a few adaptations (the .observers attribute is not persisted in the database, so I had to load the list of observers into it every time I expected to notify them).
Here is an implementation example:
Original Code:
class Dog(object):
def __init__(self, name):
self.name = name
def bark(self):
print('Woof')
def sleep(self):
print(self.name, 'is now asleep: ZZzzzzZzzZ...')
class Person(object):
def __init__(self, name):
self.name = name
def educate_dog(self, dog):
print(self.name + ':','Sleep,', dog.name)
dog.sleep()
Suppose we want a person to educate a dog every time the animal barks:
from notifyr.agents import observed, observer
from notifyr.functions import target
#observed
class Dog(object):
def __init__(self, name):
self.name = name
#target
def bark(self):
print('Woof')
def sleep(self):
print(self.name, 'is now asleep: ZZzzzzZzzZ...')
#observer('educate_dog')
class Person(object):
def __init__(self, name):
self.name = name
def educate_dog(self, dog):
print(self.name + ':','Sleep,', dog.name)
dog.sleep()
Given the decorated classes, it is possible to achieve the following result:
d = Dog('Tobby')
p = Person('Victor')
d.attach(p) # Victor is now observing Tobby
d.bark()
# Woof
# Victor: Sleep, Tobby
# Tobby is now asleep: ZZzzzzZzzZ...
The package is still very primitive, but it presents a working solution to this type of situation.
I was recently looking for something similar and here's what I came up with. It works by intercepting the __setattr__ method -- a useful stunt I plan on keeping in my pocket for later.
def watchableClass(cls):
"""
Class Decorator!
* If the class has a "dirty" member variable, then it will be
automatically set whenever any class value changes
* If the class has an "onChanged()" method, it will be called
automatically whenever any class value changes
* All this only takes place if the value is different from what it was
that is, if myObject.x is already 10 and you set myObject.x=10
nothing happens
* DOES NOT work with getter/setter functions. But then, you are
already in a function, so do what you want!
EXAMPLE:
#watchableClass
class MyClass:
def __init__(self):
self.dirty=False
def onChanged(self):
print('class has changed')
"""
if hasattr(cls,'__setattr__'):
cls.__setattr_unwatched__=cls.__setattr__
cls.__setattr__=_setObjValueWatchedCascade
else:
cls.__setattr__=_setObjValueWatched
return cls
def _setObjValueWatched(ob,k,v):
"""
called when an object value is set
"""
different=not k in ob.__dict__ or ob.__dict__[k]!=v
if different:
ob.__dict__[k]=v
if k not in ('dirty'):
if hasattr(ob,'dirty'):
ob.dirty=True
if hasattr(ob,'onChanged'):
ob.onChanged()
def _setObjValueWatchedCascade(ob,k,v):
"""
called when an object value is set
IF the class had its own __setattr__ member defined!
"""
different=not k in ob.__dict__ or ob.__dict__[k]!=v
ob.__setattr_unwatched__(k,v)
if different:
if k not in ('dirty'):
if hasattr(ob,'dirty'):
ob.dirty=True
if hasattr(ob,'onChanged'):
ob.onChanged()

Notify parent instance about property change

I have these two classes:
class Status(object):
def __init__(self):
self._message = ''
#property
def message(self):
return self._message
#message.setter
def message(self, value):
self._message = value
class Buddy(object):
def __init__(self, name):
self.name = name
self.status = Status()
def status_updated(self):
# this should be called when self.status.message is changed
and I use them like this:
buddy = Buddy('John')
buddy.status.message = 'Hello world!' # this should call Buddy.status_updated
I want Buddy.status_updated to be called when I modify the message property of Status. How to achieve this?
You'll have to store a reference back to the parent; python values do not track where they are stored (there can be multiple places that refer to your Status() instances):
class Status(object):
def __init__(self, parent=None):
self._message = ''
self._parent = parent
#property
def message(self):
return self._message
#message.setter
def message(self, value):
self._message = value
if self._parent is not None:
self._parent.status_updated()
class Buddy(object):
def __init__(self, name):
self.name = name
self.status = Status(self)
def status_updated(self):
# this should be called when self.status.message is changed
In each case you need somehow to register you want to "listen" to other's object property changes. I would suggest simple solution like this:
class Status(object):
def __init__(self, on_message_change=None):
self._message, self._on_message_change = '', on_message_change
#property
def message(self):
return self._message
#message.setter
def message(self, value):
if self._on_message_change:
self._on_message_change(self._message, value)
self._message = value
class Buddy(object):
def __init__(self, name):
self.name = name
self.status = Status(self.status_updated)
def status_updated(self, old_value, new_value):
print("status changed '%s' -> '%s'" % (old_value, new_value))
b = Buddy("someone")
b.status.message = "init"
b.status.message = "new"
output is:
status changed '' -> 'init'
status changed 'init' -> 'new'

Expanding the class from object

I have some classes:
class Window(object):
def __init__(self, name):
self.wind_name = name
def getWindowName(self):
return 'wnd' + self.wind_name
class Control(object):
def __init__(self, name, wnd):
self.contrl_name = name
setattr(self, 'getWindowName', wnd.getWindowName)
setattr(self, 'wind_name', wnd.wind_name)
def getControlName(self):
return (self.getWindowName(), 'unk' + self.contrl_name)
class Button(Control):
def __init__(self, name, wnd):
super(Button, self).__init__(name, wnd)
def getControlName(self):
return (self.getWindowName(), 'btn' + self.contrl_name)
wnd = Window('MyApp')
btnOK = Button('OK', wnd)
btnOK.getControlName() # work ok., return ('wndMyApp', 'btnOK')
btnOK.wind_name = 'NewApp'
btnOK.getControlName() # does not work properly., return ('wndMyApp', 'btnOK')
How can I extend the class Control|Button from the object of class Window to access the functions getWindowName and field wind_name in objects btnOK?
Is there a way without creating a field self.wnd = wnd in class Control, or add method setWindowName in Window...?
I can not inherit class Control from the class Window! This is not logical.
Python allows inheriting from multiple classes, i.e.
class Button(Control, Window):
...
But in this case you should know exactly what you are doing (speaking of Pythons Method Resolution Order (MRO)). I'd recommend reading this small book: Python Attributes and Methods.
You can use property for attributes
class Window(object):
def __init__(self, name):
self.wind_name = name
def getWindowName(self):
return 'wnd' + self.wind_name
class Control(object):
def __init__(self, name, wnd):
self.contrl_name = name
self.wnd = wnd
setattr(self, 'getWindowName', wnd.getWindowName)
def get_wind_name(self):
return self.wnd.wind_name
def set_wind_name(self, v):
self.wnd.wind_name = v
wind_name = property(get_wind_name, set_wind_name)
def getControlName(self):
return (self.getWindowName(), 'unk' + self.contrl_name)
class Button(Control):
def __init__(self, name, wnd):
super(Button, self).__init__(name, wnd)
def getControlName(self):
return (self.getWindowName(), 'btn' + self.contrl_name)
wnd = Window('MyApp')
btnOK = Button('OK', wnd)
print btnOK.getControlName() # work ok., return ('wndMyApp', 'btnOK')
btnOK.wind_name = 'NewApp'
print btnOK.getControlName()

python how to create different instances of the same class into an iteration

My problem is:
I would like to add to a Composite class Leaf objects created at runtime inside
a Composite routine like this:
def update(self, tp, msg, stt):
"""It updates composite objects
"""
d = Leaf()
d.setDict(tp, msg, stt)
self.append_child(d)
return self.status()
Inside main:
import lib.composite
c = Composite()
for i in range(0,10):
c.update(str(i), msg, stt)
and the Composite is:
class Composite(Component):
def __init__(self, *args, **kw):
super(Composite, self).__init__()
self.children = []
def append_child(self, child):
self.children.append(child)
def update(self, tp, msg, stt):
d = Leaf()
d.setDict(tp, msg, stt)
self.append_child(d)
return self.status()
def status(self):
for child in self.children:
ret = child.status()
if type(child) == Leaf:
p_out("Leaf: %s has value %s" % (child, ret))
class Component(object):
def __init__(self, *args, **kw):
if type(self) == Component:
raise NotImplementedError("Component couldn't be "
"instantiated directly")
def status(self, *args, **kw):
raise NotImplementedError("Status method "
"must be implemented")
class Leaf(Component):
def __init__(self):
super(Leaf, self).__init__()
self._dict = {}
def setDict(self, type, key, value)
self._dict = { type : { key : value } }
def status(self):
return self._dict
But in this way I found always that my composite has just one leaf ("d") added even if
update was called many times.
How can I code such a routine such to be able to fill composite at runtime?
"But in this way I found always that my composite has just one leaf ("d") added even if update was called many times."
No, that code makes Composite having ten children.
>>> c.children
[<__main__.Leaf object at 0xb7da77ec>, <__main__.Leaf object at 0xb7da780c>,
<__main__.Leaf object at 0xb7da788c>, <__main__.Leaf object at 0xb7da78ac>,
<__main__.Leaf object at 0xb7da78cc>, <__main__.Leaf object at 0xb7da792c>,
<__main__.Leaf object at 0xb7da794c>, <__main__.Leaf object at 0xb7da798c>,
<__main__.Leaf object at 0xb7da79ac>, <__main__.Leaf object at 0xb7da79cc>]
So why you think it only has one is strange.
What is doing the append_child? I think it should store the leafs in a list. Does it?
Update: you shouldn't pass self as first argument in the main function. I think that it raises an exception.
See code below that seems to work ok
class Component(object):
def __init__(self, *args, **kw):
pass
def setDict(self, *args, **kw):
pass
class Leaf(Component):
def __init__(self, *args, **kw):
Component.__init__(self, *args, **kw)
class Composite(Component):
def __init__(self, *args, **kw):
Component.__init__(self, *args, **kw)
self.children = []
def update(self, tp, msg, stt):
"""It updates composite objects
"""
d = Leaf()
d.setDict(tp, msg, stt)
self.append_child(d)
return 0
def append_child(self, child):
self.children.append(child)
def remove_child(self, child):
self.children.remove(child)
c =Composite()
for i in range(0,10):
c.update(str(i), "", 0)
print len(c.children)

Categories