How to pass outer function class to inner class? [duplicate] - python

This question already has an answer here:
How to access outer attribute class within inner class?
(1 answer)
Closed 3 years ago.
As a title, I have a versatility function in parent class that will share use in child class A.k.A inner class. In below, I need to pass outer_send function from parent class. then, use it with call inner_send function inside Identify class alias child class. The result will output Test.
class Device:
def __init__(self):
self.identify = self.Identify(self.outer_send())
def outer_send(message):
print(message)
def last_error(self):
return self.identify.error_info
class Identify:
def __init__(self, send):
self.inner_send() = send()
def set_error(self, error):
self.error_info = error
device = Device()
device.identify.inner_send('test')

I don't like the pattern and I would recommend designing it differently. However, this does what I think you want to do:
class Device:
def __init__(self):
self.identify = self.Identify(self._send)
def _send(self, message):
print(message)
class Identify:
def __init__(self, _send):
self.send = _send
device = Device()
device.identify.send('test')
A few notes: I renamed outer_send to _send, as I assume you don't want people calling that directly on the Device object - if you do, just rename it send and it still works; the error bit seemed superfluous, so left it out; your outer_send was missing self as a parameter - it doesn't need it, but if you do want to leave it out, annotate the method with #staticmethod to avoid warnings.

Related

Using callbacks to run function using the current values in a class

I struggled to think of a good title so I'll just explain it here. I'm using Python in Maya, which has some event callback options, so you can do something like on save: run function. I have a user interface class, which I'd like it to update when certain events are triggered, which I can do, but I'm looking for a cleaner way of doing it.
Here is a basic example similar to what I have:
class test(object):
def __init__(self, x=0):
self.x = x
def run_this(self):
print self.x
def display(self):
print 'load user interface'
#Here's the main stuff that used to be just 'test().display()'
try:
callbacks = [callback1, callback2, ...]
except NameError:
pass
else:
for i in callbacks:
try:
OpenMaya.MEventMessage.removeCallback(i)
except RuntimeError:
pass
ui = test(5)
callback1 = OpenMaya.MEventMessage.addEventCallback('SomeEvent', ui.run_this)
callback2 = OpenMaya.MEventMessage.addEventCallback('SomeOtherEvent', ui.run_this)
callback3 = ......
ui.display()
The callback persists until Maya is restarted, but you can remove it using removeCallback if you pass it the value that is returned from addEventCallback. The way I have currently is just check if the variable is set before you set it, which is a lot more messy than the previous one line of test().display()
Would there be a way that I can neatly do it in the function? Something where it'd delete the old one if I ran the test class again or something similar?
There are two ways you might want to try this.
You can an have a persistent object which represents your callback manager, and allow it to hook and unhook itself.
import maya.api.OpenMaya as om
import maya.cmds as cmds
om.MEventMessage.getEventNames()
class CallbackHandler(object):
def __init__(self, cb, fn):
self.callback = cb
self.function = fn
self.id = None
def install(self):
if self.id:
print "callback is currently installed"
return False
self.id = om.MEventMessage.addEventCallback(self.callback, self.function)
return True
def uninstall(self):
if self.id:
om.MEventMessage.removeCallback(self.id)
self.id = None
return True
else:
print "callback not currently installed"
return False
def __del__(self):
self.uninstall()
def test_fn(arg):
print "callback fired 2", arg
cb = CallbackHandler('NameChanged', test_fn)
cb.install()
# callback is active
cb.uninstall()
# callback not active
cb.install()
# callback on again
del(cb) # or cb = None
# callback gone again
In this version you'd store the CallbackHandlers you create for as long as you want the callback to persist and then manually uninstall them or let them fall out of scope when you don't need them any more.
Another option would be to create your own object to represent the callbacks and then add or remove any functions you want it to trigger in your own code. This keeps the management entirely on your side instead of relying on the api, which could be good or bad depending on your needs. You'd have an Event() class which was callable (using __call__() and it would have a list of functions to fire then its' __call__() was invoked by Maya. There's an example of the kind of event handler object you'd want here

Calling Class methods

I have 3 classes defined this way:
class Device:
Some method
class SSH:
def connect(self,type):
# code
def execute(self,cmd):
# code
class Netconf:
def connect(self,type):
# code
def execute(self,cmd):
# code
Note SSH and Netconf classes have same method names but they do things differently.
I have an instance of class Device and would like to access methods like this-
d = Device()
d.connect('cli') # <-- This should call SSH method and subsequently
# d.execute(cmd) should call execute method from SSH class
# too.
d.connect('netconf') # <-- This should call Netconf method and subsequently
# d.execute(cmd) should call execute method from
# Netconf class too.
The question is - how do I make it happen? I want to be able to use methods of SSH/Netconf class on Device class instance 'd' based on the input.
You can do this by storing the type of device connected in a private Device attribute and then forwarding most method calls to it by adding a custom __getattr__() method. This is a little tricky in the connect() method because that's were the target device is defined (as opposed to in the Device.__init__() initializer).
I also changed the variable you had named type to kind to avoid colliding with the built-in module of the same name.
class Device(object):
def connect(self, kind):
if kind == 'cli':
target = self._target = SSH()
elif kind == 'netconf':
target = self._target = Netconf()
else:
raise ValueError('Unknown device {!r}'.format(kind))
return target.connect(kind)
def __getattr__(self, name):
return getattr(self._target, name)
class SSH(object):
def connect(self, kind):
print('SSH.connect called with kind {!r}'.format(kind))
def execute(self, cmd):
print('SSH.execute called with cmd {!r}'.format(cmd))
class Netconf(object):
def connect(self, kind):
print('Netconf.connect called with kind {!r}'.format(kind))
def execute(self, cmd):
print('Netconf.execute called with cmd {!r}'.format(cmd))
d = Device()
d.connect('cli')
d.execute('cmd1')
d.connect('netconf')
d.execute('cmd2')
Output:
SSH.connect called with kind 'cli'
SSH.execute called with cmd 'cmd1'
Netconf.connect called with kind 'netconf'
Netconf.execute called with cmd 'cmd2'
You should implement the Strategy Pattern. The connect() method should instantiate the appropriate class (detach()ing from the previous if required) and store it, and then other methods should delegate to the stored object.

Override static member in DaemonRunner

I'm trying to override the DaemonRunner in the python standard daemon process library (found here https://pypi.python.org/pypi/python-daemon/)
The DaemonRunner responds to command line arguments for start, stop, and restart, but I want to add a fourth option for status.
The class I want to override looks something like this:
class DaemonRunner(object):
def _start(self):
...etc
action_funcs = {'start': _start}
I've tried to override it like this:
class StatusDaemonRunner(DaemonRunner):
def _status(self):
...
DaemonRunner.action_funcs['status'] = _status
This works to some extent, but the problem is that every instance of DaemonRunner now have the new behaviour. Is it possible to override it without modifying every instance of DaemonRunner?
I would override action_functs to make it a non-static member of class StatusDaemonRunner(DaemonRunner).
In terms of code I would do:
class StatusDaemonRunner(runner.DaemonRunner):
def __init__(self, app):
self.action_funcs = runner.DaemonRunner.action_funcs.copy()
self.action_funcs['status'] = StatusDaemonRunner._status
super(StatusDaemonRunner, self).__init__(app)
def _status(self):
pass # do your stuff
Indeed, if we look at the getter in the implementation of DaemonRunner (here) we can see that it acess the attribute using self
def _get_action_func(self):
""" Return the function for the specified action.
Raises ``DaemonRunnerInvalidActionError`` if the action is
unknown.
"""
try:
func = self.action_funcs[self.action]
except KeyError:
raise DaemonRunnerInvalidActionError(
u"Unknown action: %(action)r" % vars(self))
return func
Hence the previous code should do the trick.

How to initialize several methods inside a python object

In a Javascript object when I would want to initiate several functions inside an object, say myObject, I would have an init function that would call those methods to me initialized and I would simple call myObject.init(). How would I do this in python? Would the following be ok?
class Test(object):
def __init__(self, arg):
self.arg = arg
def init(self):
self.some_function()
self.some_other_function()
def some_function(self):
pass
def some_other_function(self):
pass
my_test = Test("test")
my_test.init()
Thanks for reading!
Yes. That should work fine. but I would give some other name than init(), as it would be explicit and different from default __init__

Share values between objects in the same Python module [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
File engine.py:
class Engine(object):
def __init__(self, variable):
self.variable = variable
class Event(object):
def process(self):
variable = '123' # this should be the value of engine.variable
Python
>>> from engine import Engine, Event
>>> engine = Engine('123')
>>> e = Event()
>>> e.process()
What's the best way to accomplish this? Because of limitations with the Event class (it's actually a subclass of a third-party library that I'm splicing new functionality into) I can't do something like e = Event(engine).
In depth explanation:
Why am I not using e = Event(engine)?
Because Event is actually a subclass of a third-party library. Additionally, process() is an internal method. So the class actually looks like this:
class Event(third_party_library_Event):
def __init__(*args, **kwargs):
super(Event, self).__init__(*args, **kwargs)
def _process(*args, **kwargs):
variable = engine.variable
# more of my functionality here
super(Event, self)._process(*args, **kwargs)
My new module also has to run seamlessly with existing code that uses the Event class already. So I can't add pass the engine object to each _process() call or to the init method either.
functools.partial might help:
#UNTESTED
class Engine(object):
def __init__(self, variable):
self.variable = variable
class Event(object):
def __init__(self, engine):
super().__init__()
self.engine = engine
def process(self):
print self.engine.variable
engine = Engine('123')
Event = functools.partial(Event, engine)
ThirdPartyApiThatNeedsAnEventClass(Event)
Now, when the 3rd-party library creates an Event, it is automatically passed engine.
"Because of limitations with the Event class (it's actually a subclass
of a third-party library that I'm splicing new functionality into) I
can't do something like e = Event(engine)."
It appears that you're concerned that Event is inheriting some other class and you are therefore unable to alter the constructor method for the class.
Your question is similar to this other one. Fortunately, the super().__init__() method does this for you.
Consider the following example:
>>> class C(object):
def __init__(self):
self.b = 1
>>> class D(C):
def __init__(self):
super().__init__()
self.a = 1
>>> d = D()
>>> d.a
1
>>> d.b # This works because of the call to super's init
1
Why not pass the variable in to the process function? You said the class's constructor can't be changed, but it seems like you are defining process. Just make it:
def process(self, engine):
variable = engine.variable
<do stuff>
or
def process(self, variable):
<do stuff>

Categories

Resources