I have a class which has its own methods, for example:
class Original():
def __init__(self, dummy=False):
self.dummy = dummy
def funcA(self):
print('funcA')
And I want that, in case the variable dummy is true, all the custom made functions from class Original (e.g., funcA) become dummy (i.e., don't do nothing and return nothing).
I have managed to do a dummy class like this:
class Dummy(object):
def dummy(*args, **kwargs):
pass
def __getattr__(self, _):
return self.dummy
a = Dummy()
a.asd() # returns nothing
However, I can't manage to make a class in which the writen functions work in case the variable dummy is False, and they don't if the variable is True.
Any help please?
Managed to figure it out based on Alex Hall's comment. Hope this helps anyone out there:
class Dummy(object):
def __init__(self, isDummy):
self.isDummy = isDummy
def dummy(*args, **kwargs):
pass
def __getattribute__(self, item):
if item in ['isDummy', 'dummy'] or self.isDummy is False:
attr = object.__getattribute__(self, item)
return attr
else:
return self.dummy
def funcA(self):
print('funcA')
print('Dummy:')
dummy = Dummy(isDummy=True)
dummy.funcA() # returns nothing
print('---')
print('nonDummy:')
nonDummy = Dummy(isDummy=False)
nonDummy.funcA() # prints 'funcA'
Related
I have the next code:
class PythagoreanProof(Scene):
CONFIG={
"color_triangulos":YELLOW,
"color_rect_c":RED,
"color_rect_b":ORANGE,
"color_rect_a":ORANGE,
"color_cuadrado_c":ORANGE,
"opacidad_triangulos":0.6,
"opacidad_cuadradro_a":0.6,
"opacidad_cuadradro_b":0.6,
"opacidad_cuadradro_c":0.6,
"grosor_lineas":1,
"l_a":5/5,
"l_b":12/5,
"l_c":13/5,
}
def construct(self):
self.wait()
self.pre_cuadrado()
self.pos_cuadrado()
self.tran_pre_pos_cuadrado()
self.wait()
def pre_cuadrado(self):
cuadro=Square(side_length=self.l_a+self.l_b)
As you can see, I can access the key "l_a" through self.l_a
But in this much simpler code I get the following error
class Example():
CONFIG = {'spam':25}
def __init__(self, value):
self.data = value
def display(self):
print(self.data, self.spam)
x=Example(2)
x.display()
AttributeError: 'Example' object has no attribute 'spam'
Why does it work in the first example? How does it actually work?
Thanks!
As for why is works when Scene is inherited to the class PythagoreanProof you need to have a look at the code of Scene to see what it is actually doing.
In the class Example you have defined CONFIG as a class level object. Your method display needs to point to this object with self.CONFIG and then use the key 'spam' to get its value '25'.
In order ro make the keys in CONFIG attributes you can use the #poperty wrapper.
See the example below
class Example():
CONFIG = {'spam': 25}
def __init__(self, value):
self.data = value
def display(self):
print(self.data, self.CONFIG['spam'])
#property
def spam(self):
return self.CONFIG['spam']
x = Example(2)
x.display()
print(x.spam)
2 25
25
Note some of you idents are incorrect. Method display should not be a function under __init__ but a method under class Example.
I suspect there's some magic in the Scene class that plays with the __getattr__ method. Like this :
class Scene:
# Minimalistic example.
# See https://docs.python.org/3.8/reference/datamodel.html#object.__getattr__
def __getattr__(self, name):
return self.CONFIG[name]
class Example(Scene):
CONFIG = {'spam': 25}
def __init__(self, value):
self.data = value
def display(self):
print(self.data, self.spam)
x = Example(2)
x.display()
# -> 2 25
I have a property that returns list of names with "ash" in it
class BaseClass(object):
def __init__(self):
self.filter_key = ""
self.name = ""
def filter_names(self, filter_key):
self.filter_key = filter_key
#property
def student_names(self):
return self.names
def callable_function_names(self):
return names
and then student class that inherits BaseClass
class StudentClass(BaseClass):
#property
def student_names(self):
names = super(StudentClass, self).student_names
return [name for name in names if self.filter_students in name]
#property
def filter_key(self):
"""Gets """
return self.filter_key
#slot_key.setter
def filter_key(self, key):
"""Sets name filter"""
self.filter_names(key)
# or by doing :
def callable_function_names(self):
names = super(StudentClass, self).callable_function_names()
return [name for name in names if self.filter_students in name]
So if I create obj of the student class.
studentclsObj = StudentClass()
studentclsObj.filter_key = "ash"
print studentclsObj.student_names
print studentclsObj.callable_function_names()
I can achieve the same result with both above prints, is there any difference and what is preferred and right way to do ?
One use case of properties is not breaking API. This is one of main strengths of python IMO. You can take a function, make transform it in a callable object, add new functionality without breaking old code, now the property
I see three main uses of properties over attributes,
Read only attributes
Is easy to create read only attributes with properties. They are non verbose, self documenting and simple
class Foo:
def __init__(self, bar):
self._bar = bar
#property
def bar(self):
return self._bar
Validation on writable properties
class Foo:
def __init__(self, bar):
self._bar = bar
#property
def bar(self):
return self._bar
#bar.setter
def bar(self, val):
if valid(val):
self._bar = val
This is a kind of defensive programming
Keep API compatibility
Imagine that you have a class for a bank account, with
a balance property
class BankAccount:
def __init__(self):
self.balance = 0
You have this code and it works fine. But know your client
says, I need you to log every balance lookup. You can replace
the attribute by a property without breaking old code
class BankAccount:
def __init__(self):
self._balance = 0
#property
def balance(self):
self.log_balance_read()
return self._balance
There is no difference between a property and a method which return the same value. Go for the simpler, use method for actions and state changes and attributes for real attributes, if you need to add logic to attribute lookup, python will let you do it
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.
So I'm looking into having a main class that defines a specific method and an extended class that adds some functionality to that method, such as:
class SuperClass:
def __init__(self):
self._data = {}
#abc.abstractmethod
def _get_obj(self, id):
pass
def get(self, obj_id):
# do stuff that should be done for all methods, eg.
if obj_id not in self.data:
obj= self._get_obj(obj_id)
self.data[obj_id] = obj
return self.data[obj_id]
class SubClass(SuperClass):
def _get_obj(self, obj_id):
pass
The idea is that the get method is the only "public" one. Is there a better way to do this?
For clarity I've only shown one of the "public" methods, but there may be many.
For reference, this is using Python 3.6. And any other comments regarding the code are welcome.
Update (also code cleanup): Another approach is to use super to call the original get which may be clearer, but forces the coder to always need to add the call there:
class SuperClass:
def __init__(self):
self._data = {}
def get(self, obj_id):
# do stuff that should be done for all methods, eg.
if obj_id in self.data:
return self.data[obj_id]
pass
class SubClass(SuperClass):
def get_from_db(self, obj_id):
# Code to get from db
return obj
def get(self, obj_id):
obj = super().get(obj_id
if None:
obj= self.get_from_db(obj_id)
self.data[obj_id] = obj
return obj
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.