I use following class to define event:
class Event(object):
def __init__(self):
self.handlers = set()
def handle(self, handler):
self.handlers.add(handler)
return self
def unhandle(self, handler):
try:
self.handlers.remove(handler)
except:
raise ValueError("Handler is not handling this event, so cannot unhandle it.")
return self
def fire(self, *args, **kwargs):
for handler in self.handlers:
print(handler)
handler(*args, **kwargs)
def getHandlerCount(self):
return len(self.handlers)
__iadd__ = handle
__isub__ = unhandle
__call__ = fire
__len__ = getHandlerCount
I have some model class defined like this:
class SomeModel(object):
def __init__(self):
self._foo = 0
self.fooChanged = Event()
#property
def foo(self):
return self._foo
#foo.setter
def foo(self, value):
self._foo = value
self.fooChanged(value)
Now, suppose that I want to change foo like this:
model = SomeModel()
other_model = SomeModel()
model.fooChanged += other_model.foo
model.foo = 1
After model.foo = 1, I get following error:
TypeError: 'int' object is not callable
Now, suppose that I use this code for defining model:
class SomeModel(object):
def __init__(self):
self._foo = 0
self.fooChanged = Event()
def get_foo(self):
return self._foo
def set_foo(self, value):
self._foo = value
self.fooChanged(value)
foo = property(get_foo, set_foo)
and this code to change the value of foo:
model = SomeModel()
other_model = SomeModel()
model.fooChanged += other_model.set_foo
model.foo = 1
Second version works fine, however, it seems little un-Pythonic to me. I have to define get_foo method, which I'd like to avoid (since properties are available). Is there some other workaround here, so first version of code could run?
Note: error will depend on self._foo type. If it's None, it will return error stating that NoneType is not callable, if it's string, error will state that str object is not callable.
After a lot of digging, I found this answer to be very informative and it pushed me in the right direction.
Using this knowledge, I was able to solve this problem by using:
model.fooChanged += lambda value: type(other_model).foo.__set__(other_model, value)
or
model.fooChanged += lambda value: type(other_model).foo.fset(other_model, value)
The later line looks more Pythonic to me, since no calls for double-underscore functions are made.
while you write model.fooChanged += other_model.foo, I guess what you actually want is its setter method, but as other_model.foo is a property object, you have to get from its class other_model.__class__.foo.fset, write as:
model.fooChanged += lambda value: other_model.__class__.foo.fset(other_model, value)
OTOH, I think your second version is pythonic to me, as:
Explicit is better than implicit.
Related
I would like to know if there is an easy way to do some identical edits on several methods of a class. An example :
class Dog():
def __init__(self):
self.name = 'abc'
self.age = 1
def setName(self, newValue):
self.name = newValue
def setAge(self, newValue):
self.age = newValue
class TalkingDog(Dog):
def __init__(self):
super().__init__()
# The end is in pseudo code :
for method in TalkingDog.allMethods :
method = method + 'print('I have been edited !')'
I know that I can also overwrite each method but in a situation with tens of methods, that will be a little boring...
So I tried this :
class TalkingDog(Dog):
def __init__(self):
super().__init__()
for method in self.__dir__():
if method.startswith('set'):
oldMethod = getattr(self, method)
def _newMethod(newValue):
oldMethod(newValue)
print('I have been edited !')
setattr(self, method, _newMethod)
a = TalkingDog()
print(a.setName) >>> <function TalkingDog.__init__.<locals>._newMethod at 0x0000000002C350D0>
That almost works but setName is not anymore a method. It's an attribute which contains a function. I completely understand why but I'm trying to get a cleaner result. With that result, I risk of having problems later. For example I can't use the library pickle with that object (got the error _pickle.PicklingError: Can't pickle <function TalkingDog.__init__.<locals>._newMethod at 0x00000000003DCBF8>: attribute lookup _newMethod on __main__ failed).
The Pythonic way to do this is probably to use the descriptor protocol, which is also what properties use:
class VocalAttribute:
def __init__(self, name, feedback):
"""Called when you first create the descriptor."""
self.name = name # the name of the attribute 'behind' the property
self.feedback = feedback # the feedback to show when the value changes
def __get__(self, obj):
"""Called when you get the descriptor value."""
return getattr(obj, self.name)
def __set__(self, obj, value):
"""Called when you set the descriptor value."""
prev = getattr(obj, self.name, None)
if value != prev:
setattr(obj, self.name, value)
print(self.feedback)
def __delete__(self, obj):
"""Called when you delete the descriptor value."""
delattr(obj, self.name)
class Foo:
bar = VocalAttribute('_bar', 'I have been edited!')
foo = Foo()
print('1.')
foo.bar = 'hello'
print('2.')
foo.bar = 'hello'
print('3.')
foo.bar = 'world'
Output:
1.
I have been edited!
2.
3.
I have been edited!
Note that this only gives feedback when the new value is different to the old one - you can tweak the behaviour as needed in __set__. It also means you can directly read from and assign to foo.bar, rather than needing to call getters and setters (what is this, Java?)
since decorator could explicit called here a way to use it:
def updater(obj, call_back, call_back_args=(), call_back_kw=None, replace=False):
# ability to be called on the fly with different args and kw for the callback
# now it returns the updated obj (instance or class)
# but could a be factory returning a new obj in this case make a copy of obj, update this coy and return it
def update_function(fn, *args, **kw):
def wrapper(*args, **kw):
if replace:
# call only the callback
res = call_back(*call_back_args, **call_back_kw)
else:
res = fn(*args, **kw)
call_back(*call_back_args, **call_back_kw)
return res
return wrapper
# get all methods of the obj
# and apply update_function (a decorator) to all methods
for name, m in inspect.getmembers(
obj, predicate=lambda x: inspect.isfunction(x) or inspect.ismethod(x)):
# make the selection here
# could be made on the name for instance
if not name.startswith('_'):
new_m = update_function(m)
setattr(obj, name, new_m)
return obj
# declare a callback
def call_back(*args, **kw):
# simple callback
print("I have been edited and called with %r args and %r kw " % (args, kw))
a = Dog()
# could be called on instance or class
# apply the callback on all "public" methods
updater(
a,
call_back,
call_back_args=(2, 3, 4),
call_back_kw={"kw1": "v_1"}
)
So I have essentially created a dictionary Class that uses classmethods for all of its magic methods that looks like this:
class ClassDict(object):
_items = {}
#classmethod
def __getitem__(cls, key):
return cls._items[key]
#classmethod
def __setitem__(cls, key, val):
cls._items[key] = val
#classmethod
def __len__(cls):
return len(cls._items)
#classmethod
def __delitem__(cls, key):
cls._items.__delitem__(key)
#classmethod
def __iter__(cls):
return iter(cls._items)
And so when I try to assign an item to it:
ClassDict['item'] = 'test'
I get an error saying TypeError: 'type' object does not support item assignment, but if I call the actual method, __setitem__ like so it works fine:
ClassDict.__setitem__('item', 'test')
And this also works:
ClassDict().__setitem__('item', 'test')
Is there anything I am doing wrong here that would prevent the first example from working? Is there any way I can fix this issue?
To get the behavior desired of being able to do:
ClassDict['item'] = 'test'
I had to implement the special methods as a metaclass instead as Martijn pointed out.
So my final implementation looks like this:
class MetaClassDict(type):
_items = {}
#classmethod
def __getitem__(cls, key):
return cls._items[key]
#classmethod
def __setitem__(cls, key, val):
cls._items[key] = val
#classmethod
def __len__(cls):
return len(cls._items)
#classmethod
def __delitem__(cls, key):
cls._items.__delitem__(key)
#classmethod
def __iter__(cls):
return iter(cls._items)
class ClassDict(object):
__metaclass__ = MetaClassDict
In a class, I want to define N persistent properties. I can implement them as follow:
#property
def prop1(self):
return self.__prop1
#prop1.setter
def prop1(self, value):
self.__prop1 = value
persistenceManagement()
#property
def prop2(self):
return self.__prop2
#prop2.setter
def prop2(self, value):
self.__prop2 = value
persistenceManagement()
[...]
#property
def propN(self):
return self.__propN
#propN.setter
def propN(self, value):
self.__propN = value
persistenceManagement()
Of course, the only different thing between these blocks is the property name (prop1, prop2, ..., propN). persistenceManagement() is a function that has to be called when the value of one of these property changes.
Since these blocks of code are identical except for a single information (i.e., the property name), I suppose there must be some way to replace each of these blocks by single lines declaring the existence of a persistent property with a given name. Something like
def someMagicalPatternFunction(...):
[...]
someMagicalPatternFunction("prop1")
someMagicalPatternFunction("prop2")
[...]
someMagicalPatternFunction("propN")
...or maybe some decorating trick that I cannot see at the moment. Is someone has an idea how this could be done?
Properties are just descriptor classes and you can create your own and use them:
class MyDescriptor(object):
def __init__(self, name, func):
self.func = func
self.attr_name = '__' + name
def __get__(self, instance, owner):
return getattr(self, self.attr_name)
def __set__(self, instance, value):
setattr(self, self.attr_name, value)
self.func(self.attr_name)
def postprocess(attr_name):
print 'postprocess called after setting', attr_name
class Example(object):
prop1 = MyDescriptor('prop1', postprocess)
prop2 = MyDescriptor('prop2', postprocess)
obj = Example()
obj.prop1 = 'answer' # prints 'postprocess called after setting __prop1'
obj.prop2 = 42 # prints 'postprocess called after setting __prop2'
Optionally you can make it a little easier to use with something like this:
def my_property(name, postprocess=postprocess):
return MyDescriptor(name, postprocess)
class Example(object):
prop1 = my_property('prop1')
prop2 = my_property('prop2')
If you like the decorator # syntax, you could do it this way (which also alleviates having to type the name of the property twice) -- however the dummy functions it requires seem a little weird...
def my_property(method):
name = method.__name__
return MyDescriptor(name, postprocess)
class Example(object):
#my_property
def prop1(self): pass
#my_property
def prop2(self): pass
The property class (yes it's a class) is just one possible implementation of the descriptor protocol (which is fully documented here: http://docs.python.org/2/howto/descriptor.html). Just write your own custom descriptor and you'll be done.
Is it possible to write an exception handler to catch the run-time errors generated by ALL the methods in class? I can do it by surrounding each one with try/except:
class MyError(Exception):
def __init__(self, obj, method):
print 'Debug info:', repr(obj.data), method.__name__
raise
class MyClass:
def __init__(self, data):
self.data = data
def f1(self):
try:
all method code here, maybe failing at run time
except:
raise MyError(self, self.f1)
I wonder if is there a more general way to achieve the same - for any error raising anywhere in the class. I would like to be able to access the class data to print some debug info.
Also, how do I get the failing method name (f1 in the example)?
Update: thanks to all for the insighful answers, the decorator idea looks like the way to go.
About the risk of trapping ALL the exceptions: a raise statement in the except branch should re-raise the exception without losing any information, doesn't it? That's why I put it in MyError also...
Warning: if you want something like this, it's likely you don't... but if you really want to...
Something like:
import functools
def catch_exception(f):
#functools.wraps(f)
def func(*args, **kwargs):
try:
return f(*args, **kwargs)
except Exception as e:
print 'Caught an exception in', f.__name__
return func
class Test(object):
def __init__(self, val):
self.val = val
#catch_exception
def calc():
return self.val / 0
t = Test(3)
t.calc()
shows how to decorate individual functions. You can then create a class decorator to apply this decorator to each method (be careful of classmethod's/staticmethod's/properties etc...)
Assuming you've got a decorator catch_exception as in #Jon Clement's answer...
class ErrorCatcher(type):
def __new__(cls, name, bases, dct):
for m in dct:
if hasattr(dct[m], '__call__'):
dct[m] = catch_exception(dct[m])
return type.__new__(cls, name, bases, dct)
class Test(object):
__metaclass__ = ErrorCatcher
def __init__(self, val):
self.val = val
def calc(self):
return self.val / 0
The metaclass applies catch_exception to everything that appears to be a method while it is defining Test.
In response to a comment regarding custom messages for each method, one could attach such a message (or even a callback function to generate a message) as an attribute:
class Test(object):
__metaclass__ = ErrorCatcher
def __init__(self, val):
self.val = val
def calc(self):
return self.val / 0
calc.msg = "Dividing by 0 is ill-advised"
The catch_exception decorator would look for a msg attribute on its argument and use it, if found, in handling the exception.
This approach could be extended; instead of a string, msg could be a mapping of exception types to strings. In either case, the string could be replaced (with support from catch_exception, of course) with an arbitrary callback function that takes, say, the raised exception as an argument.
def calc_handler(exc):
# ...
calc.callback = calc_handler
A decorator would be a good solution here.
Here's an example of how you could do it:
import inspect
def catch_exception_decorator(function):
def decorated_function:
try:
function()
except:
raise MyError(self.__class__, inspect.stack()[1][3])
return decorated_function
class MyClass(object):
def __init__(self):
...
#catch_exception_decorator
def f1(self):
...
#catch_exception_decorator on top of the function is a shortcut for f1 = catch_exception_decorator(f1).
Instead of doing self.class, you could also access class data from the instance, as long as you're not shadowing variables. inspect.stack()[1][3] is the function name of the current function. You can use these to create the exception attributes.
I have a class with an __init__ function.
How can I return an integer value from this function when an object is created?
I wrote a program, where __init__ does command line parsing and I need to have some value set. Is it OK set it in global variable and use it in other member functions? If so how to do that? So far, I declared a variable outside class. and setting it one function doesn't reflect in other function ??
If you want to return some other object when a class is called, then use the __new__() method:
class MyClass:
def __init__(self):
print("never called in this case")
def __new__(cls):
return 42
obj = MyClass()
print(obj)
# Output: 42
__init__ is required to return None. You cannot (or at least shouldn't) return something else.
Try making whatever you want to return an instance variable (or function).
>>> class Foo:
... def __init__(self):
... return 42
...
>>> foo = Foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __init__() should return None
From the documentation of __init__:
As a special constraint on constructors, no value may be returned; doing so will cause a TypeError to be raised at runtime.
As a proof, this code:
class Foo(object):
def __init__(self):
return 2
f = Foo()
Gives this error:
Traceback (most recent call last):
File "test_init.py", line 5, in <module>
f = Foo()
TypeError: __init__() should return None, not 'int'
Sample Usage of the matter in question can be like:
class SampleObject(object):
def __new__(cls, item):
if cls.IsValid(item):
return super(SampleObject, cls).__new__(cls)
else:
return None
def __init__(self, item):
self.InitData(item) #large amount of data and very complex calculations
...
ValidObjects = []
for i in data:
item = SampleObject(i)
if item: # in case the i data is valid for the sample object
ValidObjects.append(item)
The __init__ method, like other methods and functions returns None by default in the absence of a return statement, so you can write it like either of these:
class Foo:
def __init__(self):
self.value=42
class Bar:
def __init__(self):
self.value=42
return None
But, of course, adding the return None doesn't buy you anything.
I'm not sure what you are after, but you might be interested in one of these:
class Foo:
def __init__(self):
self.value=42
def __str__(self):
return str(self.value)
f=Foo()
print f.value
print f
prints:
42
42
__init__ doesn't return anything and should always return None.
You can just set it to a class variable and read it from the main program:
class Foo:
def __init__(self):
#Do your stuff here
self.returncode = 42
bar = Foo()
baz = bar.returncode
We can not return value from init. But we can return value using new.
class Car:
def __new__(cls, speed, unit):
return (f"{speed} with unit {unit}")
car = Car(42, "km")
print(car)
init() return none value solved perfectly
class Solve:
def __init__(self,w,d):
self.value=w
self.unit=d
def __str__(self):
return str("my speed is "+str(self.value)+" "+str(self.unit))
ob=Solve(21,'kmh')
print (ob)
output:
my speed is 21 kmh
Just wanted to add, you can return classes in __init__
#property
def failureException(self):
class MyCustomException(AssertionError):
def __init__(self_, *args, **kwargs):
*** Your code here ***
return super().__init__(*args, **kwargs)
MyCustomException.__name__ = AssertionError.__name__
return MyCustomException
The above method helps you implement a specific action upon an Exception in your test
Met this case when tried to parse some string data into a recursive data structure, and had a counter to be passed through.
Python does not allow to return anything from __init__, but you may write a factory function, or a class method, or a Parser class, depending on the code structure and complexity of parsing, which will parse your data into data objects.
Global variable is not a good solution, as it may be changed somewhere else, breaking the parsing logic.
Function example:
class MyClass():
def __init__(self, a, b, c):
# only assignments here
self.a = a
self.b = b
self.c = c
# return None
def parse(data):
# parsing here
a = ...
b = ...
c = ...
# status, counter, etc.
i = ...
# create an object
my_obj = MyClass(a, b, c)
# return both
return my_obj, i
# get data and parse
data = ...
my_obj, i = parse(data)
Class method example:
class MyClass():
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
#classmethod
def parse(cls, data):
a = ...
b = ...
c = ...
i = ...
obj = cls(a, b, c)
return obj, i
data = ...
my_obj, i = MyClass.parse(data)
solution here
Yes,
trying to return from the init method in python returns errors as it is a constructor of the class you can only assign values for the scope of the class but not return a specific value.
if you want to return a value but do not wish to create a method, you can use
str method
def __init__(self,a):
self.value=a
def __str__(self):
return str("all my return values are possible here")`
Well, if you don't care about the object instance anymore ... you can just replace it!
class MuaHaHa():
def __init__(self, ret):
self=ret
print MuaHaHa('foo')=='foo'