Python: test descriptors assigned correctly - python

Considering this example:
>>> class Bar(object):
...
... def __init__(self, name):
... self.name = name
... def __set__(self, instance, value):
... setattr(instance, self.name, value)
... def __get__(self, instance, owner):
... return getattr(instance, self.name, owner)
...
>>> class Foo(object):
... bat = Bar('bat')
...
>>> Foo.bat
<class 'Foo'>
>>> type(Foo.bat)
<class 'type'> # how would you get <class 'Bar'> ?
I want to write some pytests that assert the correct descriptor has been assigned to the correct attribute.
But I don't seem to be able to check the type of a descriptor once it has been assigned

I'm not sure what you're trying to do with your descriptor, but typically you want to pass back the descriptor itself when an instance is not passed:
class Bar(object):
def __init__(self, name):
self.name = name
def __set__(self, obj, value):
setattr(obj, self.name, value)
def __get__(self, obj, cls):
if obj is None:
return self
return getattr(obj, self.name)
class Foo(object):
bat = Bar('bat')
Foo.bat
# <__main__.Bar at 0x7f202accbf50>

You can override the usual lookup (which uses the very descriptor you're trying to see, whether or not you call type on the result) with vars(Foo)['bat'].

Related

How to determine the class of a descriptor?

In this example code, I would like to determine if x is an instance of TestProperty:
class TestProperty(object):
def __init__(self, name):
self._name = name
def __get__(self, instance, cls):
return getattr(instance, self._name)
def __set_(self, instance, value):
setattr(instance, self._name, value)
class Test(object):
x = TestProperty("x")
print isinstance(Test.x, TestProperty)
However, I get the following exception:
Traceback (most recent call last):
File "/home/zenoss/testproperties.py", line 14, in <module>
print isinstance(Test.x, TestProperty)
File "/home/zenoss/testproperties.py", line 6, in __get__
return getattr(instance, self._name)
AttributeError: 'NoneType' object has no attribute 'x'
Is there anyway to tell if an attribute is an instance of a class when it is a descriptor?
With the current __get__, Test.x causes the AttributeError because when the code accessing the descriptor using class, instance is passed None; (=> getattr(None, 'x') => None.x)
You should modify __get__ to handle such case:
>>> class TestProperty(object):
... def __init__(self, name):
... self._name = name
... def __get__(self, instance, cls):
... if instance is None: # To handle access through class, not instance
... return self # returns the TestProperty instance itself.
... return getattr(instance, self._name)
... def __set_(self, instance, value):
... setattr(instance, self._name, value)
...
>>> class Test(object):
... x = TestProperty("x")
...
>>> isinstance(Test.x, TestProperty)
True
BTW, as you may know, with x = TestProperty("x"), accessing x attribute through an instance will cause another exception, because it will call the __get__ (-> getattr(..) -> __get__ -> getattr(..) -> ...) recursively until stack overflow.
The best way to implement a property is with the #property decorator:
class TestProperty(object):
def __init__(self, name):
self._name = name
#property
def name(self):
"""Getter for '_name'."""
return self._name
#name.setter
def name(self, value):
"""Setter for '_name'."""
self._name = value
class Test(object):
x = TestProperty("x")
print(isinstance(Test.x, TestProperty))
It returns True when I run it.
See the documentation for #property at https://docs.python.org/3/library/functions.html#property.

Can create a def in python class which can be called what ever the def name even if the def didn't exist

I'm looking to do something like this:
class MyClass(Object):
def ****(self):
print self.__name __
MyClass.test()
->test
MyClass.whatever()
->whatever
So you can call any method and it prints the name.
Implement a __getattr__() method on your class to intercept access attempts on unknown attributes, and return a function (which you could bind to the class):
class MyClass(object):
def __getattr__(self, name):
def echo():
return name
return echo
This returns unbound functions, with no reference to the instance.
You do need to create an instance first for this to work:
>>> class MyClass(object):
... def __getattr__(self, name):
... def echo():
... return name
... return echo
...
>>> instance = MyClass()
>>> instance.test()
'test'
>>> instance.whatever()
'whatever'
You can bind the function to the instance (so it gets self passed in) by manually invoking the descriptor protocol, calling __get__ on the function before returning:
class MyClass(object):
def __getattr__(self, name):
def echo(self):
return '{}.{}'.format(type(self).__name__, name)
return echo.__get__(self, type(self))
With access to self we can print a little more information:
>>> class MyClass(object):
... def __getattr__(self, name):
... def echo(self):
... return '{}.{}'.format(type(self).__name__, name)
... return echo.__get__(self, type(self))
...
>>> instance = MyClass()
>>> instance.test()
'MyClass.test'
>>> instance.whatever()
'MyClass.whatever'

determine a class attribute is Property?

Is there a way to determine a class attribute is a Property (with __get__ and __set__ or not?
The method in
Determine if given class attribute is a property or not, Python object looks like only work for property decorator, which is not work in my case.
class Property(object):
_value = None
def __get__(self, instance, owner):
return self._value
def __set__(self, instance, value):
self._value = value * 2
class A(object):
b = Property()
>>> a = A()
>>> type(A.p)
<type 'NoneType'>
>>> type(a.p)
<type 'NoneType'>
Your descriptor returns None because it is also invoked for classes (the instance attribute is set to None when __get__ is called for that scenario).
You need to retrieve it without invoking the descriptor protocol, reaching into the class __dict__ attribute is the most direct path:
A.__dict__['p']
See the Python Descriptor HOWTO for more details on how and when descriptors are invoked.
Alternatively, do as the property object does and return self when instance is set to None (so when accessed on a class):
class Property(object):
_value = None
def __get__(self, instance, owner):
if instance is None:
return self
return self._value
def __set__(self, instance, value):
self._value = value * 2
Also see How does the #property decorator work?
Demo:
>>> class Property(object):
... def __get__(self, instance, owner):
... return self._value
... def __set__(self, instance, value):
... self._value = value * 2
...
>>> class A(object):
... b = Property()
...
>>> A.__dict__['b']
<__main__.Property object at 0x103097910>
>>> type(A.__dict__['b'])
<class '__main__.Property'>
>>> class Property(object):
... _value = None
... def __get__(self, instance, owner):
... if instance is None:
... return self
... return self._value
... def __set__(self, instance, value):
... self._value = value * 2
...
>>> class A(object):
... b = Property()
...
>>> A.b
<__main__.Property object at 0x10413d810>

__getattr__ equivalent for CLASS methods [duplicate]

Say there is:
class A(B):
...
where B could be object and ... is not:
#classmethod # or #staticmethod
def c(cls): print 'Hello from c!'
What do I have to do that calling A.c() wont trigger AttributeError?
In other words, I know it is possible to manually add class methods to a class at runtime. But is it possible to do so automatically, say every time a class method is missing it creates some dummy method?
In yet another words, only if I could replace A.__dict__ with my dict which handles __getitem__ - but A.__dict__ seems to be not writable...
You can achieve this by using a __getattr__ hook on a metaclass.
class DefaultClassMethods(type):
def __getattr__(cls, attr):
def _defaultClassMethod(cls):
print 'Hi, I am the default class method!'
setattr(cls, attr, classmethod(_defaultClassMethod))
return getattr(cls, attr)
Demo:
>>> class DefaultClassMethods(type):
... def __getattr__(cls, attr):
... def _defaultClassMethod(cls):
... print 'Hi, I am the default class method!'
... setattr(cls, attr, classmethod(_defaultClassMethod))
... return getattr(cls, attr)
...
>>> class A(object):
... __metaclass__ = DefaultClassMethods
...
>>> A.spam
<bound method DefaultClassMethods._defaultClassMethod of <class '__main__.A'>>
>>> A.spam()
Hi, I am the default class method!
Note that we set the result of the classmethod call straight onto the class, effectively caching it for future lookups.
If you need to regenerate the class method on every call instead, use the same method to bind a function to an instance but with the class and metaclass instead (using cls.__metaclass__ to be consistent with metaclass subclassing):
from types import MethodType
class DefaultClassMethods(type):
def __getattr__(cls, attr):
def _defaultClassMethod(cls):
print 'Hi, I am the default class method!'
return _defaultClassMethod.__get__(cls, cls.__metaclass__)
For static methods just return the function directly in all cases, no need to muck with the staticmethod decorator or the descriptor protocol.
The behaviors provided to instances by methods like __getattr__ and the descriptor protocol can work for classes as well, but in that case, you have to code them in the class's metaclass.
In this case, all one needs to do is to set the metaclass __getattr__ function to auto-generate the desired class attribute.
(The setattr, getattr trick is to let Python do the function->method transoform with no need to mess with it)
class AutoClassMethod(type):
def __getattr__(cls, attr):
default = classmethod(lambda cls: "Default class method for " + repr(cls))
setattr(cls, attr, default)
return getattr(cls, attr)
class A(object):
__metaclass__ = AutoClassMethod
#classmethod
def b(cls):
print cls
>>> class C(object):
... pass
...
>>> C.m = classmethod(lambda cls: cls.__name__)
>>> C.m()
'C'
Or you can use somethigs like this:
class Wrapper(object):
def __init__(self, clz, default=lambda cls: None):
self._clz = clz
self._default = default
def __getattr__(self, attr):
# __attrs__ will be getted from Wrapper
if attr.startswith('__'):
return self.__getattribute__(attr)
if not hasattr(self._clz, attr):
setattr(self._clz, attr, classmethod(self._default))
return getattr(self._clz, attr)
def __call__(self, *args, **kwargs):
return self._clz(*args, **kwargs)
>>> class C(object):
... pass
...
>>> C = Wrapper(C, default=lambda cls: cls.__name__)
>>> c = C()
>>> print C.m()
'C'
>>> print c.m() # now instance have method "m"
'C'

Python dynamic class methods

Say there is:
class A(B):
...
where B could be object and ... is not:
#classmethod # or #staticmethod
def c(cls): print 'Hello from c!'
What do I have to do that calling A.c() wont trigger AttributeError?
In other words, I know it is possible to manually add class methods to a class at runtime. But is it possible to do so automatically, say every time a class method is missing it creates some dummy method?
In yet another words, only if I could replace A.__dict__ with my dict which handles __getitem__ - but A.__dict__ seems to be not writable...
You can achieve this by using a __getattr__ hook on a metaclass.
class DefaultClassMethods(type):
def __getattr__(cls, attr):
def _defaultClassMethod(cls):
print 'Hi, I am the default class method!'
setattr(cls, attr, classmethod(_defaultClassMethod))
return getattr(cls, attr)
Demo:
>>> class DefaultClassMethods(type):
... def __getattr__(cls, attr):
... def _defaultClassMethod(cls):
... print 'Hi, I am the default class method!'
... setattr(cls, attr, classmethod(_defaultClassMethod))
... return getattr(cls, attr)
...
>>> class A(object):
... __metaclass__ = DefaultClassMethods
...
>>> A.spam
<bound method DefaultClassMethods._defaultClassMethod of <class '__main__.A'>>
>>> A.spam()
Hi, I am the default class method!
Note that we set the result of the classmethod call straight onto the class, effectively caching it for future lookups.
If you need to regenerate the class method on every call instead, use the same method to bind a function to an instance but with the class and metaclass instead (using cls.__metaclass__ to be consistent with metaclass subclassing):
from types import MethodType
class DefaultClassMethods(type):
def __getattr__(cls, attr):
def _defaultClassMethod(cls):
print 'Hi, I am the default class method!'
return _defaultClassMethod.__get__(cls, cls.__metaclass__)
For static methods just return the function directly in all cases, no need to muck with the staticmethod decorator or the descriptor protocol.
The behaviors provided to instances by methods like __getattr__ and the descriptor protocol can work for classes as well, but in that case, you have to code them in the class's metaclass.
In this case, all one needs to do is to set the metaclass __getattr__ function to auto-generate the desired class attribute.
(The setattr, getattr trick is to let Python do the function->method transoform with no need to mess with it)
class AutoClassMethod(type):
def __getattr__(cls, attr):
default = classmethod(lambda cls: "Default class method for " + repr(cls))
setattr(cls, attr, default)
return getattr(cls, attr)
class A(object):
__metaclass__ = AutoClassMethod
#classmethod
def b(cls):
print cls
>>> class C(object):
... pass
...
>>> C.m = classmethod(lambda cls: cls.__name__)
>>> C.m()
'C'
Or you can use somethigs like this:
class Wrapper(object):
def __init__(self, clz, default=lambda cls: None):
self._clz = clz
self._default = default
def __getattr__(self, attr):
# __attrs__ will be getted from Wrapper
if attr.startswith('__'):
return self.__getattribute__(attr)
if not hasattr(self._clz, attr):
setattr(self._clz, attr, classmethod(self._default))
return getattr(self._clz, attr)
def __call__(self, *args, **kwargs):
return self._clz(*args, **kwargs)
>>> class C(object):
... pass
...
>>> C = Wrapper(C, default=lambda cls: cls.__name__)
>>> c = C()
>>> print C.m()
'C'
>>> print c.m() # now instance have method "m"
'C'

Categories

Resources