logging module with setters in class - python

I have a question about logging module, I'm using it in some classes and I'm wondering how I can log setters or getters. For example I have a class :
class Item(object):
def __init__(self, name):
self.name = name
item_ = Item('object')
item_.name = 'New object'
I want here a log to say name of object has been changed. Of course, I would like avoid using #property and setters functions which will override my class.

This is relatively straightforward to implement:
class Item(object):
def __setattr__(self, name, value):
super(Item, self).__setattr__(name, value)
# put logging code here
Do not use vars() for this. It will not handle #property and other data descriptors correctly. It will also return a read-only dictionary-like-thing if you happen to be implementing a metaclass. If you don't know what that means, then you're not implementing a metaclass, so don't worry.
If you have multiple classes like this, you can factor this functionality out into a mixin class:
class LoggingMixin(object):
def __setattr__(self, name, value):
super(LoggingMixin, self).__setattr__(name, value)
# put logging code here
Now, when you want to create a new class that needs attribute logging, simply inherit from LoggingMixin, along with any other base classes if necessary.

Related

HasTraits overiding inherited getter/setter methods

I would like to mix a HasTraits with a standard python object using multiple inheritance. When i do this, the getter/setter methods of the standard object dont function as expected. The example below demonstrates this.
from traits.api import HasTraits
class A(object):
#property
def name(self):
print 'getter'
try:
return self._name
except(AttributeError):
return 'nobody'
#name.setter
def name(self, val):
print 'setter'
self._name = val.upper()
class B(A, HasTraits):
pass
b = B()
b.name #calls getter
b.name = 'name' # doesnt call setter
b.name # doesnt call getter
I assume this is because the HasTraits class intercepts the standard get/set methods. Is there a way around this?
I'm pretty sure there is not a way to make traits play nicely with the native python decorator #property. At least, not any reasonably clean way.
However traits has its own Property concept with getters and setters. You can define a Property trait which does what you want as a simple getter/setter.
class B(A, HasTraits):
this_name = Property
def _get_this_name(self):
return self.name
def _set_this_name(self, value):
self.name = value
And if you subclass a HasTraits which contains a Property, that traits-specific getter/setter effects will be preserved in the subclass. So there is no reason -- that is if you already want the type-checking of traits in your program -- to use the #property decorator and not the Property getter in the first place.

Python calling super constructor - am I doing it right?

I have a base class like so:
class Token:
def __init__(self, value):
self.value = value.strip()
self.tokens = None
def get_value(self):
return self.value
def tokenize(self):
pass # abstract stub
def __str__(self):
return type(self).__name__ + ': '+ re.sub(r'\s+', ' ', self.value)
And a ton of it's child classes:
class T_DefineDirective(Token):
def __init__(self, value):
super().__init__(value)
class T_IncludeDirective(Token):
def __init__(self, value):
super().__init__(value)
class T_IfdefDirective(Token):
def __init__(self, value):
super().__init__(value)
class T_Identifier(Token):
def __init__(self, value):
super().__init__(value)
class T_Rvalue(Token):
def __init__(self, value):
super().__init__(value)
def tokenize(self):
pass # stuff here
Now I'm a DRY programmer. I hate repetition. If you look at the code, the __init__ piece is copy-pasted in all the child classes.
My question, is there some way to avoid the repetition, or is this really the right way?
(note that the example is a bit shortened, so it may not make too much sense. But you can see the issue I mean).
If you do not have any additional setup work to do in the Token subclasses, then it is safe not to override __init__.
If you do have to perform some subclass-specific initialisation, then the patten that you're using is fine and 'pythonic'.
To clarify:
if __init__ is not defined on a class, then Python will use the __init__ method defined on (one of) its parent class(es), if possible
this is because there aren't any special rules for overriding 'magic' methods like __init__
even if the initialiser on a parent class is used, an instance of the subclass will be created
this is because the actual creation happens in __new__; the newly created object is then passed to __init__ for initialisation
If you really want to eliminate as much boilerplate as possible:
First, you don't need __init__ if all it does is call super(); special methods are inherited just like any other methods, as sapi's answer explains.
Second, you can dynamically create a bunch of classes:
token_classes = {
'T_{}'.format(name): type('T_{}'.format(name), (Token,), {})
for name in 'DefineDirective IncludeDirective IfdefDirective Identifier'.split()
}
And you can use them straight out of that dict, but if you really want to make them into globals you can:
globals().update(token_classes)
However, the whole goal of avoiding repetition is to make your code more readable and maintainable, and in this case, I think we're achieving the opposite. :)

How do I get a reference for the current class object?

In Python, how do I get a reference to the current class object within a class statement? Example:
def setup_class_members(cls, prefix):
setattr(cls, prefix+"_var1", "hello")
setattr(cls, prefix+"_var2", "goodbye")
class myclass(object):
setup_class_members(cls, "coffee") # How to get "cls"?
def mytest(self):
print(self.coffee_var1)
print(self.coffee_var2)
x = myclass()
x.mytest()
>>> hello
>>> goodbye
Alternatives that I've written off are:
Use locals(): This gives a dict in a class statement that can be written to. This seems to work for classes, however the documentation tells you not to do this. (I might be tempted to go with this alternative if someone can assure me that this will continue to work for some time.)
Add members to the class object after the class statement: My actual application is to derive a PyQt4 QWidget class with dynamically created pyqtProperty class attributes. QWidget is unusual in that it has a custom metaclass. Very roughly, the metaclass compiles a list of pyqtProperties and stores it as additional member. For this reason, properties that are added to the class after creation have no effect. An example to clear this up:
from PyQt4 import QtCore, QtGui
# works
class MyWidget1(QtGui.QWidget):
myproperty = QtCore.pyqtProperty(int)
# doesn't work because QWidget's metaclass doesn't get to "compile" myproperty
class MyWidget2(QtGui.QWidget):
pass
MyWidget2.myproperty = QtCore.pyqtProperty(int)
Please note that the above will work for most programming cases; my case just happens to be one of those unusual corner cases.
For Python 3, the class must be declared as
class myclass(object, metaclass = Meta):
prefix = "coffee"
...
A few other points:
The metaclass may be a callable, not just a class (Python 2&3)
If the base class of your class already has a non-standard metaclass, you have to make sure you call it's __init__() and __new__() methods instead of type's.
The class statement accepts keyword parameters that are passed on to the metaclass (Python 3 only)
A rewrite of mouad's solution in Python 3 using all of the above is...
def MetaFun(name, bases, attr, prefix=None):
if prefix:
attr[prefix+"_var1"] = "hello"
attr[prefix+"_var2"] = "goodbye"
return object.__class__(name, bases, attr)
class myclass(object, metaclass = MetaFun, prefix="coffee"):
def mytest(self):
print(self.coffee_var1)
print(self.coffee_var2)
AFAIK there is two way to do what you want:
Using metaclass, this will create your two variables in class creation time (which i think is what you want):
class Meta(type):
def __new__(mcs, name, bases, attr):
prefix = attr.get("prefix")
if prefix:
attr[prefix+"_var1"] = "hello"
attr[prefix+"_var2"] = "goodbye"
return type.__new__(mcs, name, bases, attr)
class myclass(object):
__metaclass__ = Meta
prefix = "coffee"
def mytest(self):
print(self.coffee_var1)
print(self.coffee_var2)
Create your two class variable in instantiation time:
class myclass(object):
prefix = "coffee"
def __init__(self):
setattr(self.__class__, self.prefix+"_var1", "hello")
setattr(self.__class__, self.prefix+"_var2", "goodbye")
def mytest(self):
print(self.coffee_var1)
print(self.coffee_var2)
N.B: I'm not sure what you want to achieve because if you want to create dynamic variables depending on the prefix variable why are you accessing like you do in your mytest method ?! i hope it was just an example.
Two more approaches you might use:
A class decorator.
def setup_class_members(prefix):
def decorator(cls):
setattr(cls, prefix+"_var1", "hello")
setattr(cls, prefix+"_var2", "goodbye")
return cls
return decorator
#setup_class_members("coffee")
class myclass(object):
# ... etc
Especially if you need to add attributes in various combinations, the decorator approach is nice because it does not have any effect on inheritance.
If you are dealing with a small set of of attributes that you wish to combine in various ways, you can use mixin classes. A mixin class is a regular class, it's just intended to "mix in" various attributes to some other class.
class coffee_mixin(object):
coffee_var1 = "hello"
coffee_var2 = "goodbye"
class tea_mixin(object):
tea_var1 = "good morning old bean"
tea_var2 = "pip pip cheerio"
class myclass(coffee_mixin, tea_mixin):
# ... etc
See zope.interface.declarations._implements for an example of doing this kind of magic. Just be warned that it's a serious maintainability and portability risk.

Python new-style-class-related question

I am a python learner and currently hacking up a class with variable number of fields as in the "Bunch of Named Stuff" example here.
class Bunch:
def __init__(self, **kwds):
self.__dict__.update(kwds)
I also want to write a __setattr__ in this class in order to check the input attribute name. But, the python documentation says,
If __setattr__() wants to assign to an
instance attribute, it should not
simply execute "self.name = value" --
this would cause a recursive call to
itself. Instead, it should insert the
value in the dictionary of instance
attributes, e.g., "self.__dict__[name]
= value".
For new-style classes, rather than
accessing the instance dictionary, it
should call the base class method with
the same name, for example,
"object.__setattr__(self, name,
value)".
In that case, should I also use object.__dict__ in the __init__ function to replace self.__dict__?
You can use
class Bunch:
def __init__(self, **kwds):
self.__dict__.update(kwds)
def __setattr__(self, name, value):
#do your verification stuff
self.__dict__[name] = value
or with new-style class :
class Bunch(object):
def __init__(self, **kwds):
self.__dict__.update(kwds)
def __setattr__(self, name, value):
#do your verification stuff
super(Bunch, self).__setattr__(name, value)
No. You should define your class as class Bunch(object), but continue to refer to self.__dict__.
You only need to use the object.__setattr__ method while you are defining the self.__setattr__ method to prevent infinite recursion. __dict__ is not a method, but is an attribute on the object itself, so object.__dict__ would not work.

Rename method in class body

Is it possible to rename method in Python?
Something like this
class Validation(unittest.TestCase):
def __init__(self, methodName='runTest'):
super(Validation, self).__init__(methodName)
#Doesn't work
setattr(self,'do_folders_equal','test_do_folders_equal')
Rename method 'do_folders_equal' to 'test_do_folders_equal'..
Usage above , obviously, is incorrect...How to do this hack?
You wouldn't rename it, you'd just assign it to another variable:
class Validation(unittest.TestCase):
def __init__(self, methodName='runTest'):
super(Validation, self).__init__(methodName)
self.test_do_folders_equal = self.do_folders_equal
However there can sometimes be some weird interplay with inherited methods etc, so it sort of depends what you are trying to do. Not sure how this behaves on old-style classes either...
EDIT: Or using a name read at runtime:
class Validation(unittest.TestCase):
def __init__(self, methodName='runTest'):
super(Validation, self).__init__(methodName)
setattr(self, 'test_do_folders_equal', getattr(self, 'do_folders_equal'))

Categories