Assign Constructor argument with static method pointer in python? - python

Getting undefined error with the below program
class SignalHandler(object): # pylint: disable=too-few-public-methods
"""
Handles various user generated signals
"""
def __init__(self,
sigint_signalhandler=SignalHandler.signal_handler,
sigquit_signalhandler=SignalHandler.signal_handler,
sighup_signalhandler=SignalHandler.signal_handler):
signal.signal(signal.SIGINT, sigint_signalhandler)
signal.signal(signal.SIGQUIT, sigquit_signalhandler)
signal.signal(signal.SIGHUP, sighup_signalhandler)
#staticmethod
def signal_handler(signalnum):
print ('Ignoring signal : ', signalnum)
This is what the error looks like
import signalhandler
File "/usr/local/sandvine/scripts/upgrade-assistance/signalhandler.py", line 10, in <module>
class SignalHandler(object): # pylint: disable=too-few-public-methods
File "/usr/local/sandvine/scripts/upgrade-assistance/signalhandler.py", line 22, in SignalHandler
sigint_signalhandler=SignalHandler.signal_handler,
NameError: name 'SignalHandler' is not defined
So eventually i want to pass some custom methods, if not i will use signal_handler method provided by SignalHandler class.

Define signal_handler above the class as a plain method, not inside it as a static method. You can't refer to a class before it's been defined, which is what your __init__ is trying to do.
Alternatively, use self.signal_handler in the init body instead of SignalHandler.signal_handler:
class Foo(object):
def __init__(self, bar_printer=None):
self.bar_printer = bar_printer if bar_printer else self._default_bar_printer
#staticmethod
def _default_bar_printer():
print("bar")
f = Foo()
f.bar_printer() # Prints "bar"
def better_bar_printer():
print("The best bar!")
f2 = Foo(better_bar_printer)
f2.bar_printer() # Prints "The best bar!"

Related

Python library using parent method instead of overriden method

I have extended the Parent class with the Override class. I have have overridden the method() method to fix a bug that occurs in the Parent class. I fixed the said bug and this fix has been tested in the Override class.
I use the Override class through an External class. By testing the External class to see if the previous bug is fixed, I discovered that it is not and that the traceback does not go through the Override class.
class Parent():
def method(self, param):
# Bugged
do_stuff()
class Override(Parent):
def method(self, param):
# Fixed (tested)
param = fix_param(param)
super(Parent, self).method(param)
class External():
def processing():
# Same bug as in `Parent`
param = get_param()
obj = Override()
obj.method(param)
It seems to me that the External class uses the Parent.method() method instead of the Override.method() method. Any clue on how to fix it or on where this problem comes from?
I'm a beginner and have not been confronted inheritance a lot so, please, forgive my ignorance and my lack of experience.
EDIT
Test that fails in External :
import os
import collections
import envtpl
from acquisition.configargparse_confparser import StepConfigFileParser
from configparser_extended import ExtendedConfigParser
from unittest import TestCase
from acquisition.utils import set_custom_environment
class ConfigFileParserTestCase(TestCase):
def test_parse_extended(self):
# x = StepConfigFileParser("test_plugin_name", "test")
plugin_name = "test_plugin_name"
step_name = "test"
set_custom_environment(plugin_name, step_name)
config = os.environ.get('MFCONFIG', 'GENERIC')
filename = os.path.dirname(os.path.realpath(__file__)) + "/test.ini"
with open(filename, 'r') as stream:
config_parser = ExtendedConfigParser(
config=config, inheritance='im', interpolation=None)
content = stream.read()
config_parser.read_string(content) # Fails here
section = "step_%s" % step_name
res = collections.OrderedDict()
for key in config_parser.options(section):
if not key.startswith('arg_'):
continue
res[key.replace('arg_', '', 1)] = envtpl.render_string(
config_parser.get(section, key))
self.assertEqual(res, {"venom": "snake", "revolver": "ocelot"})
Overridden method :
read_string() in https://github.com/thefab/configparser_extended/blob/master/configparser_extended/ecp.py line 573
Parent method :
read_string() from configparser
(https://docs.python.org/3/library/configparser.html#configparser.ConfigParser.read_string)
test.ini
[step_test]
arg_venom=snake
arg_revolver=ocelot
liquid=snake
Error :
ERROR: test_parse_extended (tests.test_confparser.ConfigFileParserTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/florian/metwork/mfdata/src/acquisition/tests/test_confparser.py", line 39, in test_parse_extended
config_parser.read_string(content)
File "/opt/metwork-mfext/opt/python2/lib/python2.7/site-packages/backports/configparser/__init__.py", line 728, in read_string
sfile = io.StringIO(string)
TypeError: initial_value must be unicode or None, not str
Your code is not a complete working example, but it should do as you suggest.
Here is an example you can run to prove the point:
class Parent():
def method(self):
print('parent')
class Child(Parent):
def method(self):
print('child')
class Other():
def call_method(self):
c = Child()
c.method()
o = Other()
o.call_method()
That prints 'child', proving the Child class has overridden method(self).

Python: How to fix, if a static class variable gets a different function reference pointer?

I wonder why my class calls the referenced function (assigned to a static class variable) with with an argument. If I assign the function reference to a normal class variable it works like expected.
Here my example code:
# This function is not editable, because it's imported from an API
def getStuff():
print "I do my stuff!!!"
class foo(object):
GET_STUFF = getStuff
def __init__(self):
print "static var: ",self.GET_STUFF
self.GET_STUFF()
print "outer func: ",getStuff
foo()
This comes up with the following error:
outer func: <function getStuff at 0x0000000003219908>
static var: <bound method foo.getStuff of <__main__.foo object at 0x00000000030AB358>>
Traceback (most recent call last):
File "C:/example.py", line 13, in <module>
foo()
File "C:/example.py", line 10, in __init__
self.GET_STUFF()
TypeError: getStuff() takes no arguments (1 given)
To fix this issue I point the function reference inside the constructor to the class variable:
class foo(object):
def __init__(self):
self.GET_STUFF = getStuff
print "static var: ",self.GET_STUFF
self.GET_STUFF()
The result is like expected and works fine:
outer func: <function getStuff at 0x000000000331F908>
static var: <function getStuff at 0x000000000331F908>
I do my stuff!!!
But:
I wanted to use a static class variable, because it makes it easy to read and simple to setup for different API's. So in the end I would come up with some wrapper classes like in the following:
from API01 import getStuff01
from API02 import getStuff02
# bar calculates stuff object from the API (it calls GET_STUFF)
# and stores the object into self.stuff
import bar
class foo01(bar):
GET_STUFF = getStuff01
def DoSomething(self, volume):
self.stuff.volume = volume
class foo02(bar):
GET_STUFF = getStuff02
def DoSomething(self, volume):
self.stuff.volume = volume
# [...] and so on..
Is there a way to bring it to work in the way I want to setup my wrapper classes, or do I really have to define a constructor for each wrapper class?
Thanks
The reason for the error is that
self.GET_STUFF()
actually means
tmp = getattr(self, 'GET_STUFF')
tmp(self)
That means these two classes are equivalent:
def foo(self): pass
class Foo(object):
a = foo
class Bar(object):
def a(self): pass
In both cases, a function object is added to the class as a member and that means for Python that the function wants self as the first parameter.
To achieve what you want:
from API01 import getStuff01
def wrapper01(self):
getStuff01()
class foo01(object):
GET_STUFF = wrapper01
Just for extend Aaron answer, if you want to have static methods you can use the #staticmethod decorator:
class Calc:
#staticmethod
def sum(x, y):
return x + y
print (Calc.sum(3,4))
>>> 7
I thought already that my object is calling the referenced function with itself as argument. After a bit of research I finally found a solution. When I use a class variable to point to a function it will not referencing a direct pointer. It references the function as a bounced method of it's class. To get rid of the default call of calling a method with getattr, the call function of getattr for the class itself has to be overwritten (in this case the class bar, because foo (the wrapper classes) inherits the functionalities of bar:
import inspect
class bar(object):
GET_STUFF = None
def __getattribute__(self, name):
attr = object.__getattribute__(self,name)
if name == "GET_STUFF":
# Check: is method and is bounced?
if inspect.ismethod(attr) and attr.im_self is not None:
return attr.__func__
return attr
getattr of bar is now pointing to the original function reference, but only for the class variable GET_STUFF, because I want to leave the default functionality for the rest of my variables.
So, when I now execute the following:
class foo(bar):
GET_STUFF = getStuff
def __init__(self):
print "inner func: ",self.GET_STUFF
self.GET_STUFF()
foo()
I get the expected result and can write my wrappers without producing additional code for each module with those wrapper classes:
outer func: <function getStuff at 0x00000000034259E8>
inner func: <function getStuff at 0x00000000034259E8>
I do my stuff!!!

making a function as an else inside an __init__

How to get a function inside if/else inside an __init__ :
class Foo(object):
def __init__(self, q, **keywords):
if a == "":
print "No empty strings"
else:
def on_g(self, response):
if response.error:
print "Check your internet settings"
else:
self.Bar()
http_client.fetch("http://www.google.com/", self.on_g)
because the program dont read the on_g() if i put an empty string!
If i use the on_g() outside in parallel with __init__() i need a declared variable, for example:
class Foo(object):
def __init__(self, q, **keywords):
if a == "":
print "No empty strings"
else:
self.on_g()
def on_g(self):
print 'hello there'
will return hello there
Your bug is in
http_client.fetch("http://www.google.com/", self.on_g)
which should be
http_client.fetch("http://www.google.com/", on_g)
since you defined a function, not a method.
self (the instance you're creating through __init__ ) doesn't have a on_g method.
Functions for the class-es need to be defined at the class level (as shown on your second chunk of code). They are evaluated when the class is first... erm... "looked-up"? "evaluated"?
That's why your second piece of code works. How come you can call self.on_g within the __init__ when the actual definition of the on_g method seems to come later in the code? It's an odd behavior (at a first glance) for an interpreter, right? Well... That's because when you run self.on_g(), the whole Foo class has already been evaluated and on_g has been added to the class (not to the instance!: To the class)
class Foo(object):
def __init__(self, q, **keywords):
[ . . . ]
else:
self.on_g() # I can use self.on_g() eventhough is defined... _
# |
# |
def on_g(self): # <------------ LATER ---------------------------|
print 'hello there'
Whereas if you define your method within the __init__, the interpreter will yell at you:
class Test(object):
def __init__(self):
def test(self):
print "Hello"
self.test()
a = Test()
Throws:
Traceback (most recent call last):
File "./test.py", line 10, in <module>
a = Test()
File "./test.py", line 8, in __init__
self.test()
AttributeError: 'Test' object has no attribute 'test'
Even if you think Oh, maybe the class doesn't have the test method because it's still within the __init__, and it will have it once the initialization is completed... Meeeck... Wrong:
class Test(object):
def __init__(self):
def test(self):
print "Hello"
a = Test()
a.test()
Same AttributeError.
If you still want to add on_g to the class at runtime (very bad idea, IMHO) you can do the interpreter's job by doing this:
class Test(object):
def __init__(self):
def test(self):
print "Hello"
self.__class__.test = test
self.test()
a = Test()
a.test()
... which correctly prints:
Hello
Hello
Now, the two most straightforward things to do I can think of are:
You move the def on_g(self) to the class level (as you showed in your second code snippet)
You call your http_client.fetch with on_g as a function local to the __init__'s scope (being picky with the language: on_g now is a function, not a method, since is not bound to an object anymore).
def __init__(self, q, **keywords):
if a == "":
print "No empty strings"
else:
def on_g(response):
if response.error:
print "Check your internet settings"
else:
self.Bar()
http_client.fetch("http://www.google.com/", on_g)

What does cls() function do inside a class method?

Today I'm viewing another's code, and saw this:
class A(B):
# Omitted bulk of irrelevant code in the class
def __init__(self, uid=None):
self.uid = str(uid)
#classmethod
def get(cls, uid):
o = cls(uid)
# Also Omitted lots of code here
what does this cls() function do here?
If I got some other classes inherit this A class, call it C, when calling this get method, would this o use C class as the caller of cls()?
cls is the constructor function, it will construct class A and call the __init__(self, uid=None) function.
If you enherit it (with C), the cls will hold 'C', (and not A), see AKX answer.
For classmethods, the first parameter is the class through which the class method is invoked with instead of the usual self for instancemethods (which all methods in a class implicitly are unless specified otherwise).
Here's an example -- and for the sake of exercise, I added an exception that checks the identity of the cls parameter.
class Base(object):
#classmethod
def acquire(cls, param):
if cls is Base:
raise Exception("Must be called via subclass :(")
return "this is the result of `acquire`ing a %r with %r" % (cls, param)
class Something(Base):
pass
class AnotherThing(Base):
pass
print Something.acquire("example")
print AnotherThing.acquire("another example")
print Base.acquire("this will crash")
this is the result of `acquire`ing a <class '__main__.Something'> with 'example'
this is the result of `acquire`ing a <class '__main__.AnotherThing'> with 'another example'
Traceback (most recent call last):
File "classmethod.py", line 16, in <module>
print Base.acquire("this will crash")
File "classmethod.py", line 5, in acquire
raise Exception("Must be called via subclass :(")
Exception: Must be called via subclass :(
It's a class factory.
Essentially it the same as calling:
o = A(uid)
cls in def get(...): is A.

Creating dynamic ABC class based on user defined class

I'm writing an plugin framework and I want to be able to write a decorator interface, which will convert user class to ABC class and substitute all methods with abstractmethods. I cannot get it working and I suppose the problem is connected with wrong mro, but I can be wrong.
I basically need to be albe to write:
#interface
class X:
def test(self):
pass
x = X() # should fail, because test will be abstract method.
substituting methods with their abstract versions is straightforward (you have to iterate over func's and replace them with abc.abstractmethod(func)), but I've got problem with creating dynamic type, which will be an ABCmeta metaclass.
Right now I've got something like:
from abc import ABCMeta
class Interface(metaclass=ABCMeta):
pass
def interface(cls):
newcls = type(cls.__name__, (Interface, cls), {})
# substitute all methods with abstract ones
for name, func in inspect.getmembers(newcls, predicate=inspect.isfunction):
setattr(newcls, name, abstractmethod(func))
return newcls
but it doesnot work - Ican initialize class X without errors.
With standard usage of ABC in Python, we can write:
class X(metaclass=ABCMeta):
#abstractmethod
def test(self):
pass
x = X() # it will fail
How can I create dynamic type in Python3, which will behave like it will have metaclass ABCmeta and will substitute all functions with abstract ones?
The trick is not to use setattr to reset each of the attributes, but instead to pass those modified attributes to the type function as a dictionary:
import inspect
from abc import ABCMeta, abstractmethod
class Interface(metaclass=ABCMeta):
pass
def interface(cls):
attrs = {n: abstractmethod(f)
for n, f in inspect.getmembers(cls, predicate=inspect.isfunction)}
return type(cls.__name__, (Interface, cls), attrs)
#interface
class X(metaclass=ABCMeta):
def test(self):
pass
x = X()
# does fail:
# Traceback (most recent call last):
# File "test.py", line 19, in <module>
# x = X() # should fail, because test will be abstract method.
# TypeError: Can't instantiate abstract class X with abstract methods test

Categories