min/max based on property (not attribute) of class object in python - python

Consider the following snippet of codes.
class MyClass(object):
#property
def foo(self):
return self._foo
l = [my_class1, my_class2]
min(l, key=MyClass.foo) # doesn't work because foo is not callable.
# "TypeError: 'property' object is not callable"
Is there a way to make it work?

Using operator.attrgetter:
min(l, key=operator.attrgetter('foo'))
Example:
>>> class MyClass(object):
... def __init__(self, val):
... self._foo = val
... def __repr__(self):
... return 'MyClass({})'.format(self._foo)
... #property
... def foo(self):
... return self._foo
...
>>> import operator
>>> min([MyClass(3), MyClass(1), MyClass(2)], key=operator.attrgetter('foo'))
MyClass(1)

You can use a lambda expression to access foo just as though it were an attribute:
min(l, key=lambda o: o.foo)

Related

Add decorator to a method from inherited class?

I want to inherit from class just to add decorators to its methods.
Is there a shortcut to do this without redefining each base class method?
You can use a class decorator to encapsulate the whole work
Example code:
def deco(func):
"""Function decorator"""
def inner(*args, **kwargs):
print("decorated version")
return func(*args, **kwargs)
return inner
def decoclass(decorator):
"""Class decorator: decorates public methods with decorator"""
def outer(cls):
class inner(cls):
pass
for name in dir(cls):
if not name.startswith("_"): # ignore hidden and private members
# print("decorating", name) # uncomment for tests
attr = getattr(inner, name)
setattr(inner, name, decorator(attr))
return inner
return outer
class Foo:
"""Sample class""
def foo(self):
return "foo in Foo"
You can then use it:
>>> #decoclass(deco)
class Foo2(Foo):
pass
>>> f = Foo2()
>>> f.foo()
decorated version
'foo in Foo'
Sure, you can do this dynamically. Suppose you have some class:
>>> class Foo:
... def bar(self): print('bar')
... def baz(self): print('baz')
...
And a decorator:
>>> def deco(f):
... def wrapper(self):
... print('decorated')
... return f(self)
... return wrapper
...
Then simply inherit:
>>> class Foo2(Foo):
... pass
...
Then loop over your original class, and apply the decorator to your new child-class:
>>> for name, attr in vars(Foo).items():
... if callable(attr):
... setattr(Foo2, name, deco(attr))
...
So...
>>> x = Foo2()
>>> x.bar()
decorated
bar
>>> x.baz()
decorated
baz
Now, using if callable(attr) might not be restrictive enough. You might want to ignore "dunder" methods, so instead:
for name, attr in vars(Foo):
if callable(attr) and not name.startswith('__'):
setattr(Foo2, name, attr)
might be more appropriate. Depends on your use-case.
And just for fun, here we can also use the type constructor:
In [17]: class Foo:
...: def bar(self): print('bar')
...: def baz(self): print('baz')
...:
In [18]: def deco(f):
...: def wrapper(self):
...: print('decorated')
...: return f(self)
...: return wrapper
...:
In [19]: Foo3 = type(
...: 'Foo3',
...: (Foo,),
...: {name:deco(attr) for name, attr in vars(Foo).items() if callable(attr)}
...: )
In [20]: y = Foo3()
In [21]: y.bar()
decorated
bar
In [22]: y.baz()
decorated
baz

Getting property named `foo`

I have
class A:
foo = 'f'
baa = 'b'
#property
def foo(self):
return self.foo
#property
def baa(self):
return self.baa
I want to make this procedure:
get(myclass, prop):
which gets the property of the class.
For example a = A() and get(a, 'foo') gives me f. And a = 2 and gets(a, 'imag') gives me 0.
The build-in is called getattr.
Also you need to call the property and the variable differently:
You cannot access a property with getattr
class A:
def __init__(self):
self._foo = 'f'
self._bar = 'b'
#property
def foo(self):
return self._foo
#property
def bar(self):
return self._bar
a = A()
print(a.foo)
print(getattr(a, '_foo'))
As stated by #MaxNoe, the method you want is getattr(). However, you could create an alias for it, if you want to just use get() instead. Also works for class instances, obviously.
#accepts class name (c) and attribute (attr)
def get(c,attr):
#returns the attribute
return getattr(c,attr)
Flask usage (obligatory?)
from flask import Flask
app=Flask(__name__)
#app.route("/")
def get(c,attr):
return getattr(c,attr)

Cached properties for classes

I like the cached_property module: https://pypi.python.org/pypi/cached-property
Is there a way to get cached properties for classes?
Here is an example for "properties for classes"
class Foo(object):
#classmethod
def get_bar(cls):
return 'bar'
#cached_class_property
def bar(cls):
return 'bar'
Usage:
assert Foo.bar == Foo.get_bar()
With "cached" I mean that the second (and later) calls to the property returns the value of the first call.
Properties are nothing but descriptors, and when we define a descriptor it is always looked up on the type of the object. For instances a descriptor will be looked up on its class and similarly for a class it is going to be looked up on its type, i.e Metaclass.
import random
class cached_class_property(object):
def __init__(self, func):
self.func = func
self.name = '_' + func.__name__
def __get__(self, obj, type):
if obj is None:
return self
sentinel = object()
value = getattr(obj, self.name, sentinel)
if value is sentinel:
value = self.func(obj)
setattr(obj, self.name, value)
return value
class Meta(type):
#cached_class_property
def bar(cls):
value = random.random()
return value
class Foo(object):
__metaclass__ = Meta
Demo:
>>> %run so.py
>>> Foo.bar
0.3896508798298206
>>> Foo.bar
0.3896508798298206
>>> Foo.bar
0.3896508798298206
>>> class Bar(Foo):
... pass
...
>>> Bar.bar
0.3896508798298206
>>> Bar.bar
0.3896508798298206

Add #property method to a class

One can add a method to a python class with:
class foo(object):
pass
def donothing(self):
pass
foo.y = donothing
Then one would call the method with:
f = foo()
f.y()
Is there a way to add #property to the def as well, so to call it with
f.y
?
Assign the return value of the property:
>>> class foo(object):
... pass
...
>>> def donothing(self):
... print('donothing is called')
...
>>> foo.y = property(donothing) # <----
>>> f = foo()
>>> f.y
donothing is called
You can just add the #property before the method definition
... class Foo(object):
... pass
...
>>> #property
... def bar(self):
... print("bar is called")
...
>>> Foo.bar = bar
>>> f = Foo()
>>> f.bar
bar is called
Absolutely, It can be specified as :
class foo(object):
def __int__(self):
self._y = None
#property
def y(self):
return self._y
#y.setter
def y(self, value):
self._y = value
>>>>x = foo()
>>>>x.y = str
>>>>print type(x.y(12.345)), x.y(12.345)
<type 'str'> 12.345
Here, I'm just saying that the attribute y (yes an attribute and not a method !), is set to value. Since everything is an object in Python, I can perfectly assign a function to a variable. The method associated with the attribute y (there as a property), returns the value of the attribute, which turns to be a function (str in this case). The returned value is used as a callable, which is exactly what we expected. Though, accessing the attribute y returns as a callable, effectively calling str()
I can assign any fucntion to y like this :
def double(x):
return 2 * x
...
>>>>x.y = double
>>>>print x.y(33)
66
And so on...

i have '__contains__' ,why error

class a(object):
def a(self):
return True
__contains__=a
b=a()
print 2 in b#why error
__contains__ is meant to take an argument. a doesn't accept an argument.
The following is your example with a working __contains__:
>>> class a(object):
... def a(self, item):
... return True
... __contains__=a
...
>>> b=a()
>>> print 2 in b
True
The signature of __contains__ is:
object.__contains__(self, item)
as per documentation. You need to extend your "a" method:
def a(self, item)
class a(object):
def a(self, item):
return True
__contains__=a

Categories

Resources