I have a class with two class methods (using the classmethod() function) for getting and setting what is essentially a static variable. I tried to use the property() function with these, but it results in an error. I was able to reproduce the error with the following in the interpreter:
class Foo(object):
_var = 5
#classmethod
def getvar(cls):
return cls._var
#classmethod
def setvar(cls, value):
cls._var = value
var = property(getvar, setvar)
I can demonstrate the class methods, but they don't work as properties:
>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
Is it possible to use the property() function with #classmethod decorated functions?
3.8 < Python < 3.11
Can use both decorators together. See this answer.
Python < 3.9
A property is created on a class but affects an instance. So if you want a classmethod property, create the property on the metaclass.
>>> class foo(object):
... _var = 5
... class __metaclass__(type): # Python 2 syntax for metaclasses
... pass
... #classmethod
... def getvar(cls):
... return cls._var
... #classmethod
... def setvar(cls, value):
... cls._var = value
...
>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
But since you're using a metaclass anyway, it will read better if you just move the classmethods in there.
>>> class foo(object):
... _var = 5
... class __metaclass__(type): # Python 2 syntax for metaclasses
... #property
... def var(cls):
... return cls._var
... #var.setter
... def var(cls, value):
... cls._var = value
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
or, using Python 3's metaclass=... syntax, and the metaclass defined outside of the foo class body, and the metaclass responsible for setting the initial value of _var:
>>> class foo_meta(type):
... def __init__(cls, *args, **kwargs):
... cls._var = 5
... #property
... def var(cls):
... return cls._var
... #var.setter
... def var(cls, value):
... cls._var = value
...
>>> class foo(metaclass=foo_meta):
... pass
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
In Python 3.9 You could use them together, but (as noted in #xgt's comment) it was deprecated in Python 3.11, so it is not recommended to use it.
Check the version remarks here:
https://docs.python.org/3.11/library/functions.html#classmethod
However, it used to work like so:
class G:
#classmethod
#property
def __doc__(cls):
return f'A doc for {cls.__name__!r}'
Order matters - due to how the descriptors interact, #classmethod has to be on top.
I hope this dead-simple read-only #classproperty decorator would help somebody looking for classproperties.
class classproperty(property):
def __get__(self, owner_self, owner_cls):
return self.fget(owner_cls)
class C(object):
#classproperty
def x(cls):
return 1
assert C.x == 1
assert C().x == 1
Reading the Python 2.2 release notes, I find the following.
The get method [of a property] won't be called when
the property is accessed as a class
attribute (C.x) instead of as an
instance attribute (C().x). If you
want to override the __get__ operation
for properties when used as a class
attribute, you can subclass property -
it is a new-style type itself - to
extend its __get__ method, or you can
define a descriptor type from scratch
by creating a new-style class that
defines __get__, __set__ and
__delete__ methods.
NOTE: The below method doesn't actually work for setters, only getters.
Therefore, I believe the prescribed solution is to create a ClassProperty as a subclass of property.
class ClassProperty(property):
def __get__(self, cls, owner):
return self.fget.__get__(None, owner)()
class foo(object):
_var=5
def getvar(cls):
return cls._var
getvar=classmethod(getvar)
def setvar(cls,value):
cls._var=value
setvar=classmethod(setvar)
var=ClassProperty(getvar,setvar)
assert foo.getvar() == 5
foo.setvar(4)
assert foo.getvar() == 4
assert foo.var == 4
foo.var = 3
assert foo.var == 3
However, the setters don't actually work:
foo.var = 4
assert foo.var == foo._var # raises AssertionError
foo._var is unchanged, you've simply overwritten the property with a new value.
You can also use ClassProperty as a decorator:
class foo(object):
_var = 5
#ClassProperty
#classmethod
def var(cls):
return cls._var
#var.setter
#classmethod
def var(cls, value):
cls._var = value
assert foo.var == 5
Is it possible to use the property() function with classmethod decorated functions?
No.
However, a classmethod is simply a bound method (a partial function) on a class accessible from instances of that class.
Since the instance is a function of the class and you can derive the class from the instance, you can can get whatever desired behavior you might want from a class-property with property:
class Example(object):
_class_property = None
#property
def class_property(self):
return self._class_property
#class_property.setter
def class_property(self, value):
type(self)._class_property = value
#class_property.deleter
def class_property(self):
del type(self)._class_property
This code can be used to test - it should pass without raising any errors:
ex1 = Example()
ex2 = Example()
ex1.class_property = None
ex2.class_property = 'Example'
assert ex1.class_property is ex2.class_property
del ex2.class_property
assert not hasattr(ex1, 'class_property')
And note that we didn't need metaclasses at all - and you don't directly access a metaclass through its classes' instances anyways.
writing a #classproperty decorator
You can actually create a classproperty decorator in just a few lines of code by subclassing property (it's implemented in C, but you can see equivalent Python here):
class classproperty(property):
def __get__(self, obj, objtype=None):
return super(classproperty, self).__get__(objtype)
def __set__(self, obj, value):
super(classproperty, self).__set__(type(obj), value)
def __delete__(self, obj):
super(classproperty, self).__delete__(type(obj))
Then treat the decorator as if it were a classmethod combined with property:
class Foo(object):
_bar = 5
#classproperty
def bar(cls):
"""this is the bar attribute - each subclass of Foo gets its own.
Lookups should follow the method resolution order.
"""
return cls._bar
#bar.setter
def bar(cls, value):
cls._bar = value
#bar.deleter
def bar(cls):
del cls._bar
And this code should work without errors:
def main():
f = Foo()
print(f.bar)
f.bar = 4
print(f.bar)
del f.bar
try:
f.bar
except AttributeError:
pass
else:
raise RuntimeError('f.bar must have worked - inconceivable!')
help(f) # includes the Foo.bar help.
f.bar = 5
class Bar(Foo):
"a subclass of Foo, nothing more"
help(Bar) # includes the Foo.bar help!
b = Bar()
b.bar = 'baz'
print(b.bar) # prints baz
del b.bar
print(b.bar) # prints 5 - looked up from Foo!
if __name__ == '__main__':
main()
But I'm not sure how well-advised this would be. An old mailing list article suggests it shouldn't work.
Getting the property to work on the class:
The downside of the above is that the "class property" isn't accessible from the class, because it would simply overwrite the data descriptor from the class __dict__.
However, we can override this with a property defined in the metaclass __dict__. For example:
class MetaWithFooClassProperty(type):
#property
def foo(cls):
"""The foo property is a function of the class -
in this case, the trivial case of the identity function.
"""
return cls
And then a class instance of the metaclass could have a property that accesses the class's property using the principle already demonstrated in the prior sections:
class FooClassProperty(metaclass=MetaWithFooClassProperty):
#property
def foo(self):
"""access the class's property"""
return type(self).foo
And now we see both the instance
>>> FooClassProperty().foo
<class '__main__.FooClassProperty'>
and the class
>>> FooClassProperty.foo
<class '__main__.FooClassProperty'>
have access to the class property.
Python 3!
See #Amit Portnoy's answer for an even cleaner method in python >= 3.9
Old question, lots of views, sorely in need of a one-true Python 3 way.
Luckily, it's easy with the metaclass kwarg:
class FooProperties(type):
#property
def var(cls):
return cls._var
class Foo(object, metaclass=FooProperties):
_var = 'FOO!'
Then, >>> Foo.var
'FOO!'
There is no reasonable way to make this "class property" system to work in Python.
Here is one unreasonable way to make it work. You can certainly make it more seamless with increasing amounts of metaclass magic.
class ClassProperty(object):
def __init__(self, getter, setter):
self.getter = getter
self.setter = setter
def __get__(self, cls, owner):
return getattr(cls, self.getter)()
def __set__(self, cls, value):
getattr(cls, self.setter)(value)
class MetaFoo(type):
var = ClassProperty('getvar', 'setvar')
class Foo(object):
__metaclass__ = MetaFoo
_var = 5
#classmethod
def getvar(cls):
print "Getting var =", cls._var
return cls._var
#classmethod
def setvar(cls, value):
print "Setting var =", value
cls._var = value
x = Foo.var
print "Foo.var = ", x
Foo.var = 42
x = Foo.var
print "Foo.var = ", x
The knot of the issue is that properties are what Python calls "descriptors". There is no short and easy way to explain how this sort of metaprogramming works, so I must point you to the descriptor howto.
You only ever need to understand this sort of things if you are implementing a fairly advanced framework. Like a transparent object persistence or RPC system, or a kind of domain-specific language.
However, in a comment to a previous answer, you say that you
need to modify an attribute that in such a way that is seen by all instances of a class, and in the scope from which these class methods are called does not have references to all instances of the class.
It seems to me, what you really want is an Observer design pattern.
Setting it only on the meta class doesn't help if you want to access the class property via an instantiated object, in this case you need to install a normal property on the object as well (which dispatches to the class property). I think the following is a bit more clear:
#!/usr/bin/python
class classproperty(property):
def __get__(self, obj, type_):
return self.fget.__get__(None, type_)()
def __set__(self, obj, value):
cls = type(obj)
return self.fset.__get__(None, cls)(value)
class A (object):
_foo = 1
#classproperty
#classmethod
def foo(cls):
return cls._foo
#foo.setter
#classmethod
def foo(cls, value):
cls.foo = value
a = A()
print a.foo
b = A()
print b.foo
b.foo = 5
print a.foo
A.foo = 10
print b.foo
print A.foo
Half a solution, __set__ on the class does not work, still. The solution is a custom property class implementing both a property and a staticmethod
class ClassProperty(object):
def __init__(self, fget, fset):
self.fget = fget
self.fset = fset
def __get__(self, instance, owner):
return self.fget()
def __set__(self, instance, value):
self.fset(value)
class Foo(object):
_bar = 1
def get_bar():
print 'getting'
return Foo._bar
def set_bar(value):
print 'setting'
Foo._bar = value
bar = ClassProperty(get_bar, set_bar)
f = Foo()
#__get__ works
f.bar
Foo.bar
f.bar = 2
Foo.bar = 3 #__set__ does not
Because I need to modify an attribute that in such a way that is seen by all instances of a class, and in the scope from which these class methods are called does not have references to all instances of the class.
Do you have access to at least one instance of the class? I can think of a way to do it then:
class MyClass (object):
__var = None
def _set_var (self, value):
type (self).__var = value
def _get_var (self):
return self.__var
var = property (_get_var, _set_var)
a = MyClass ()
b = MyClass ()
a.var = "foo"
print b.var
Give this a try, it gets the job done without having to change/add a lot of existing code.
>>> class foo(object):
... _var = 5
... def getvar(cls):
... return cls._var
... getvar = classmethod(getvar)
... def setvar(cls, value):
... cls._var = value
... setvar = classmethod(setvar)
... var = property(lambda self: self.getvar(), lambda self, val: self.setvar(val))
...
>>> f = foo()
>>> f.var
5
>>> f.var = 3
>>> f.var
3
The property function needs two callable arguments. give them lambda wrappers (which it passes the instance as its first argument) and all is well.
Here's a solution which should work for both access via the class and access via an instance which uses a metaclass.
In [1]: class ClassPropertyMeta(type):
...: #property
...: def prop(cls):
...: return cls._prop
...: def __new__(cls, name, parents, dct):
...: # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
...: dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
...: dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
...: return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
...:
In [2]: class ClassProperty(object):
...: __metaclass__ = ClassPropertyMeta
...: _prop = 42
...: def __getattr__(self, attr):
...: raise Exception('Never gets called')
...:
In [3]: ClassProperty.prop
Out[3]: 42
In [4]: ClassProperty.prop = 1
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-4-e2e8b423818a> in <module>()
----> 1 ClassProperty.prop = 1
AttributeError: can't set attribute
In [5]: cp = ClassProperty()
In [6]: cp.prop
Out[6]: 42
In [7]: cp.prop = 1
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-7-e8284a3ee950> in <module>()
----> 1 cp.prop = 1
<ipython-input-1-16b7c320d521> in <lambda>(cls, attr, val)
6 # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
7 dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
----> 8 dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
9 return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
AttributeError: can't set attribute
This also works with a setter defined in the metaclass.
I found one clean solution to this problem. It's a package called classutilities (pip install classutilities), see the documentation here on PyPi.
Consider example:
import classutilities
class SomeClass(classutilities.ClassPropertiesMixin):
_some_variable = 8 # Some encapsulated class variable
#classutilities.classproperty
def some_variable(cls): # class property getter
return cls._some_variable
#some_variable.setter
def some_variable(cls, value): # class property setter
cls._some_variable = value
You can use it on both class level and instance level:
# Getter on class level:
value = SomeClass.some_variable
print(value) # >>> 8
# Getter on instance level
inst = SomeClass()
value = inst.some_variable
print(value) # >>> 8
# Setter on class level:
new_value = 9
SomeClass.some_variable = new_value
print(SomeClass.some_variable) # >>> 9
print(SomeClass._some_variable) # >>> 9
# Setter on instance level
inst = SomeClass()
inst.some_variable = new_value
print(SomeClass.some_variable) # >>> 9
print(SomeClass._some_variable) # >>> 9
print(inst.some_variable) # >>> 9
print(inst._some_variable) # >>> 9
As you can see, it works correctly under all circumstances.
Based on https://stackoverflow.com/a/1800999/2290820
class MetaProperty(type):
def __init__(cls, *args, **kwargs):
super()
#property
def praparty(cls):
return cls._var
#praparty.setter
def praparty(cls, val):
cls._var = val
class A(metaclass=MetaProperty):
_var = 5
print(A.praparty)
A.praparty = 6
print(A.praparty)
For a functional approach pre Python 3.9 you can use this:
def classproperty(fget):
return type(
'classproperty',
(),
{'__get__': lambda self, _, cls: fget(cls), '__module__': None}
)()
class Item:
a = 47
#classproperty
def x(cls):
return cls.a
Item.x
After searching different places, I found a method to define a classproperty
valid with Python 2 and 3.
from future.utils import with_metaclass
class BuilderMetaClass(type):
#property
def load_namespaces(self):
return (self.__sourcepath__)
class BuilderMixin(with_metaclass(BuilderMetaClass, object)):
__sourcepath__ = 'sp'
print(BuilderMixin.load_namespaces)
Hope this can help somebody :)
A code completion friendly solution for Python < 3.9
from typing import (
Callable,
Generic,
TypeVar,
)
T = TypeVar('T')
class classproperty(Generic[T]):
"""Converts a method to a class property.
"""
def __init__(self, f: Callable[..., T]):
self.fget = f
def __get__(self, instance, owner) -> T:
return self.fget(owner)
Here is my solution that also caches the class property
class class_property(object):
# this caches the result of the function call for fn with cls input
# use this as a decorator on function methods that you want converted
# into cached properties
def __init__(self, fn):
self._fn_name = fn.__name__
if not isinstance(fn, (classmethod, staticmethod)):
fn = classmethod(fn)
self._fn = fn
def __get__(self, obj, cls=None):
if cls is None:
cls = type(obj)
if (
self._fn_name in vars(cls) and
type(vars(cls)[self._fn_name]).__name__ != "class_property"
):
return vars(cls)[self._fn_name]
else:
value = self._fn.__get__(obj, cls)()
setattr(cls, self._fn_name, value)
return value
Here's my suggestion. Don't use class methods.
Seriously.
What's the reason for using class methods in this case? Why not have an ordinary object of an ordinary class?
If you simply want to change the value, a property isn't really very helpful is it? Just set the attribute value and be done with it.
A property should only be used if there's something to conceal -- something that might change in a future implementation.
Maybe your example is way stripped down, and there is some hellish calculation you've left off. But it doesn't look like the property adds significant value.
The Java-influenced "privacy" techniques (in Python, attribute names that begin with _) aren't really very helpful. Private from whom? The point of private is a little nebulous when you have the source (as you do in Python.)
The Java-influenced EJB-style getters and setters (often done as properties in Python) are there to facilitate Java's primitive introspection as well as to pass muster with the static language compiler. All those getters and setters aren't as helpful in Python.
Related
I have a class with two class methods (using the classmethod() function) for getting and setting what is essentially a static variable. I tried to use the property() function with these, but it results in an error. I was able to reproduce the error with the following in the interpreter:
class Foo(object):
_var = 5
#classmethod
def getvar(cls):
return cls._var
#classmethod
def setvar(cls, value):
cls._var = value
var = property(getvar, setvar)
I can demonstrate the class methods, but they don't work as properties:
>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
Is it possible to use the property() function with #classmethod decorated functions?
3.8 < Python < 3.11
Can use both decorators together. See this answer.
Python < 3.9
A property is created on a class but affects an instance. So if you want a classmethod property, create the property on the metaclass.
>>> class foo(object):
... _var = 5
... class __metaclass__(type): # Python 2 syntax for metaclasses
... pass
... #classmethod
... def getvar(cls):
... return cls._var
... #classmethod
... def setvar(cls, value):
... cls._var = value
...
>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
But since you're using a metaclass anyway, it will read better if you just move the classmethods in there.
>>> class foo(object):
... _var = 5
... class __metaclass__(type): # Python 2 syntax for metaclasses
... #property
... def var(cls):
... return cls._var
... #var.setter
... def var(cls, value):
... cls._var = value
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
or, using Python 3's metaclass=... syntax, and the metaclass defined outside of the foo class body, and the metaclass responsible for setting the initial value of _var:
>>> class foo_meta(type):
... def __init__(cls, *args, **kwargs):
... cls._var = 5
... #property
... def var(cls):
... return cls._var
... #var.setter
... def var(cls, value):
... cls._var = value
...
>>> class foo(metaclass=foo_meta):
... pass
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
In Python 3.9 You could use them together, but (as noted in #xgt's comment) it was deprecated in Python 3.11, so it is not recommended to use it.
Check the version remarks here:
https://docs.python.org/3.11/library/functions.html#classmethod
However, it used to work like so:
class G:
#classmethod
#property
def __doc__(cls):
return f'A doc for {cls.__name__!r}'
Order matters - due to how the descriptors interact, #classmethod has to be on top.
I hope this dead-simple read-only #classproperty decorator would help somebody looking for classproperties.
class classproperty(property):
def __get__(self, owner_self, owner_cls):
return self.fget(owner_cls)
class C(object):
#classproperty
def x(cls):
return 1
assert C.x == 1
assert C().x == 1
Reading the Python 2.2 release notes, I find the following.
The get method [of a property] won't be called when
the property is accessed as a class
attribute (C.x) instead of as an
instance attribute (C().x). If you
want to override the __get__ operation
for properties when used as a class
attribute, you can subclass property -
it is a new-style type itself - to
extend its __get__ method, or you can
define a descriptor type from scratch
by creating a new-style class that
defines __get__, __set__ and
__delete__ methods.
NOTE: The below method doesn't actually work for setters, only getters.
Therefore, I believe the prescribed solution is to create a ClassProperty as a subclass of property.
class ClassProperty(property):
def __get__(self, cls, owner):
return self.fget.__get__(None, owner)()
class foo(object):
_var=5
def getvar(cls):
return cls._var
getvar=classmethod(getvar)
def setvar(cls,value):
cls._var=value
setvar=classmethod(setvar)
var=ClassProperty(getvar,setvar)
assert foo.getvar() == 5
foo.setvar(4)
assert foo.getvar() == 4
assert foo.var == 4
foo.var = 3
assert foo.var == 3
However, the setters don't actually work:
foo.var = 4
assert foo.var == foo._var # raises AssertionError
foo._var is unchanged, you've simply overwritten the property with a new value.
You can also use ClassProperty as a decorator:
class foo(object):
_var = 5
#ClassProperty
#classmethod
def var(cls):
return cls._var
#var.setter
#classmethod
def var(cls, value):
cls._var = value
assert foo.var == 5
Is it possible to use the property() function with classmethod decorated functions?
No.
However, a classmethod is simply a bound method (a partial function) on a class accessible from instances of that class.
Since the instance is a function of the class and you can derive the class from the instance, you can can get whatever desired behavior you might want from a class-property with property:
class Example(object):
_class_property = None
#property
def class_property(self):
return self._class_property
#class_property.setter
def class_property(self, value):
type(self)._class_property = value
#class_property.deleter
def class_property(self):
del type(self)._class_property
This code can be used to test - it should pass without raising any errors:
ex1 = Example()
ex2 = Example()
ex1.class_property = None
ex2.class_property = 'Example'
assert ex1.class_property is ex2.class_property
del ex2.class_property
assert not hasattr(ex1, 'class_property')
And note that we didn't need metaclasses at all - and you don't directly access a metaclass through its classes' instances anyways.
writing a #classproperty decorator
You can actually create a classproperty decorator in just a few lines of code by subclassing property (it's implemented in C, but you can see equivalent Python here):
class classproperty(property):
def __get__(self, obj, objtype=None):
return super(classproperty, self).__get__(objtype)
def __set__(self, obj, value):
super(classproperty, self).__set__(type(obj), value)
def __delete__(self, obj):
super(classproperty, self).__delete__(type(obj))
Then treat the decorator as if it were a classmethod combined with property:
class Foo(object):
_bar = 5
#classproperty
def bar(cls):
"""this is the bar attribute - each subclass of Foo gets its own.
Lookups should follow the method resolution order.
"""
return cls._bar
#bar.setter
def bar(cls, value):
cls._bar = value
#bar.deleter
def bar(cls):
del cls._bar
And this code should work without errors:
def main():
f = Foo()
print(f.bar)
f.bar = 4
print(f.bar)
del f.bar
try:
f.bar
except AttributeError:
pass
else:
raise RuntimeError('f.bar must have worked - inconceivable!')
help(f) # includes the Foo.bar help.
f.bar = 5
class Bar(Foo):
"a subclass of Foo, nothing more"
help(Bar) # includes the Foo.bar help!
b = Bar()
b.bar = 'baz'
print(b.bar) # prints baz
del b.bar
print(b.bar) # prints 5 - looked up from Foo!
if __name__ == '__main__':
main()
But I'm not sure how well-advised this would be. An old mailing list article suggests it shouldn't work.
Getting the property to work on the class:
The downside of the above is that the "class property" isn't accessible from the class, because it would simply overwrite the data descriptor from the class __dict__.
However, we can override this with a property defined in the metaclass __dict__. For example:
class MetaWithFooClassProperty(type):
#property
def foo(cls):
"""The foo property is a function of the class -
in this case, the trivial case of the identity function.
"""
return cls
And then a class instance of the metaclass could have a property that accesses the class's property using the principle already demonstrated in the prior sections:
class FooClassProperty(metaclass=MetaWithFooClassProperty):
#property
def foo(self):
"""access the class's property"""
return type(self).foo
And now we see both the instance
>>> FooClassProperty().foo
<class '__main__.FooClassProperty'>
and the class
>>> FooClassProperty.foo
<class '__main__.FooClassProperty'>
have access to the class property.
Python 3!
See #Amit Portnoy's answer for an even cleaner method in python >= 3.9
Old question, lots of views, sorely in need of a one-true Python 3 way.
Luckily, it's easy with the metaclass kwarg:
class FooProperties(type):
#property
def var(cls):
return cls._var
class Foo(object, metaclass=FooProperties):
_var = 'FOO!'
Then, >>> Foo.var
'FOO!'
There is no reasonable way to make this "class property" system to work in Python.
Here is one unreasonable way to make it work. You can certainly make it more seamless with increasing amounts of metaclass magic.
class ClassProperty(object):
def __init__(self, getter, setter):
self.getter = getter
self.setter = setter
def __get__(self, cls, owner):
return getattr(cls, self.getter)()
def __set__(self, cls, value):
getattr(cls, self.setter)(value)
class MetaFoo(type):
var = ClassProperty('getvar', 'setvar')
class Foo(object):
__metaclass__ = MetaFoo
_var = 5
#classmethod
def getvar(cls):
print "Getting var =", cls._var
return cls._var
#classmethod
def setvar(cls, value):
print "Setting var =", value
cls._var = value
x = Foo.var
print "Foo.var = ", x
Foo.var = 42
x = Foo.var
print "Foo.var = ", x
The knot of the issue is that properties are what Python calls "descriptors". There is no short and easy way to explain how this sort of metaprogramming works, so I must point you to the descriptor howto.
You only ever need to understand this sort of things if you are implementing a fairly advanced framework. Like a transparent object persistence or RPC system, or a kind of domain-specific language.
However, in a comment to a previous answer, you say that you
need to modify an attribute that in such a way that is seen by all instances of a class, and in the scope from which these class methods are called does not have references to all instances of the class.
It seems to me, what you really want is an Observer design pattern.
Setting it only on the meta class doesn't help if you want to access the class property via an instantiated object, in this case you need to install a normal property on the object as well (which dispatches to the class property). I think the following is a bit more clear:
#!/usr/bin/python
class classproperty(property):
def __get__(self, obj, type_):
return self.fget.__get__(None, type_)()
def __set__(self, obj, value):
cls = type(obj)
return self.fset.__get__(None, cls)(value)
class A (object):
_foo = 1
#classproperty
#classmethod
def foo(cls):
return cls._foo
#foo.setter
#classmethod
def foo(cls, value):
cls.foo = value
a = A()
print a.foo
b = A()
print b.foo
b.foo = 5
print a.foo
A.foo = 10
print b.foo
print A.foo
Half a solution, __set__ on the class does not work, still. The solution is a custom property class implementing both a property and a staticmethod
class ClassProperty(object):
def __init__(self, fget, fset):
self.fget = fget
self.fset = fset
def __get__(self, instance, owner):
return self.fget()
def __set__(self, instance, value):
self.fset(value)
class Foo(object):
_bar = 1
def get_bar():
print 'getting'
return Foo._bar
def set_bar(value):
print 'setting'
Foo._bar = value
bar = ClassProperty(get_bar, set_bar)
f = Foo()
#__get__ works
f.bar
Foo.bar
f.bar = 2
Foo.bar = 3 #__set__ does not
Because I need to modify an attribute that in such a way that is seen by all instances of a class, and in the scope from which these class methods are called does not have references to all instances of the class.
Do you have access to at least one instance of the class? I can think of a way to do it then:
class MyClass (object):
__var = None
def _set_var (self, value):
type (self).__var = value
def _get_var (self):
return self.__var
var = property (_get_var, _set_var)
a = MyClass ()
b = MyClass ()
a.var = "foo"
print b.var
Give this a try, it gets the job done without having to change/add a lot of existing code.
>>> class foo(object):
... _var = 5
... def getvar(cls):
... return cls._var
... getvar = classmethod(getvar)
... def setvar(cls, value):
... cls._var = value
... setvar = classmethod(setvar)
... var = property(lambda self: self.getvar(), lambda self, val: self.setvar(val))
...
>>> f = foo()
>>> f.var
5
>>> f.var = 3
>>> f.var
3
The property function needs two callable arguments. give them lambda wrappers (which it passes the instance as its first argument) and all is well.
Here's a solution which should work for both access via the class and access via an instance which uses a metaclass.
In [1]: class ClassPropertyMeta(type):
...: #property
...: def prop(cls):
...: return cls._prop
...: def __new__(cls, name, parents, dct):
...: # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
...: dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
...: dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
...: return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
...:
In [2]: class ClassProperty(object):
...: __metaclass__ = ClassPropertyMeta
...: _prop = 42
...: def __getattr__(self, attr):
...: raise Exception('Never gets called')
...:
In [3]: ClassProperty.prop
Out[3]: 42
In [4]: ClassProperty.prop = 1
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-4-e2e8b423818a> in <module>()
----> 1 ClassProperty.prop = 1
AttributeError: can't set attribute
In [5]: cp = ClassProperty()
In [6]: cp.prop
Out[6]: 42
In [7]: cp.prop = 1
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-7-e8284a3ee950> in <module>()
----> 1 cp.prop = 1
<ipython-input-1-16b7c320d521> in <lambda>(cls, attr, val)
6 # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
7 dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
----> 8 dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
9 return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
AttributeError: can't set attribute
This also works with a setter defined in the metaclass.
I found one clean solution to this problem. It's a package called classutilities (pip install classutilities), see the documentation here on PyPi.
Consider example:
import classutilities
class SomeClass(classutilities.ClassPropertiesMixin):
_some_variable = 8 # Some encapsulated class variable
#classutilities.classproperty
def some_variable(cls): # class property getter
return cls._some_variable
#some_variable.setter
def some_variable(cls, value): # class property setter
cls._some_variable = value
You can use it on both class level and instance level:
# Getter on class level:
value = SomeClass.some_variable
print(value) # >>> 8
# Getter on instance level
inst = SomeClass()
value = inst.some_variable
print(value) # >>> 8
# Setter on class level:
new_value = 9
SomeClass.some_variable = new_value
print(SomeClass.some_variable) # >>> 9
print(SomeClass._some_variable) # >>> 9
# Setter on instance level
inst = SomeClass()
inst.some_variable = new_value
print(SomeClass.some_variable) # >>> 9
print(SomeClass._some_variable) # >>> 9
print(inst.some_variable) # >>> 9
print(inst._some_variable) # >>> 9
As you can see, it works correctly under all circumstances.
Based on https://stackoverflow.com/a/1800999/2290820
class MetaProperty(type):
def __init__(cls, *args, **kwargs):
super()
#property
def praparty(cls):
return cls._var
#praparty.setter
def praparty(cls, val):
cls._var = val
class A(metaclass=MetaProperty):
_var = 5
print(A.praparty)
A.praparty = 6
print(A.praparty)
For a functional approach pre Python 3.9 you can use this:
def classproperty(fget):
return type(
'classproperty',
(),
{'__get__': lambda self, _, cls: fget(cls), '__module__': None}
)()
class Item:
a = 47
#classproperty
def x(cls):
return cls.a
Item.x
After searching different places, I found a method to define a classproperty
valid with Python 2 and 3.
from future.utils import with_metaclass
class BuilderMetaClass(type):
#property
def load_namespaces(self):
return (self.__sourcepath__)
class BuilderMixin(with_metaclass(BuilderMetaClass, object)):
__sourcepath__ = 'sp'
print(BuilderMixin.load_namespaces)
Hope this can help somebody :)
A code completion friendly solution for Python < 3.9
from typing import (
Callable,
Generic,
TypeVar,
)
T = TypeVar('T')
class classproperty(Generic[T]):
"""Converts a method to a class property.
"""
def __init__(self, f: Callable[..., T]):
self.fget = f
def __get__(self, instance, owner) -> T:
return self.fget(owner)
Here is my solution that also caches the class property
class class_property(object):
# this caches the result of the function call for fn with cls input
# use this as a decorator on function methods that you want converted
# into cached properties
def __init__(self, fn):
self._fn_name = fn.__name__
if not isinstance(fn, (classmethod, staticmethod)):
fn = classmethod(fn)
self._fn = fn
def __get__(self, obj, cls=None):
if cls is None:
cls = type(obj)
if (
self._fn_name in vars(cls) and
type(vars(cls)[self._fn_name]).__name__ != "class_property"
):
return vars(cls)[self._fn_name]
else:
value = self._fn.__get__(obj, cls)()
setattr(cls, self._fn_name, value)
return value
Here's my suggestion. Don't use class methods.
Seriously.
What's the reason for using class methods in this case? Why not have an ordinary object of an ordinary class?
If you simply want to change the value, a property isn't really very helpful is it? Just set the attribute value and be done with it.
A property should only be used if there's something to conceal -- something that might change in a future implementation.
Maybe your example is way stripped down, and there is some hellish calculation you've left off. But it doesn't look like the property adds significant value.
The Java-influenced "privacy" techniques (in Python, attribute names that begin with _) aren't really very helpful. Private from whom? The point of private is a little nebulous when you have the source (as you do in Python.)
The Java-influenced EJB-style getters and setters (often done as properties in Python) are there to facilitate Java's primitive introspection as well as to pass muster with the static language compiler. All those getters and setters aren't as helpful in Python.
This question already has answers here:
Using property() on classmethods
(19 answers)
Closed 3 years ago.
In python I can add a method to a class with the #classmethod decorator. Is there a similar decorator to add a property to a class? I can better show what I'm talking about.
class Example(object):
the_I = 10
def __init__( self ):
self.an_i = 20
#property
def i( self ):
return self.an_i
def inc_i( self ):
self.an_i += 1
# is this even possible?
#classproperty
def I( cls ):
return cls.the_I
#classmethod
def inc_I( cls ):
cls.the_I += 1
e = Example()
assert e.i == 20
e.inc_i()
assert e.i == 21
assert Example.I == 10
Example.inc_I()
assert Example.I == 11
Is the syntax I've used above possible or would it require something more?
The reason I want class properties is so I can lazy load class attributes, which seems reasonable enough.
Here's how I would do this:
class ClassPropertyDescriptor(object):
def __init__(self, fget, fset=None):
self.fget = fget
self.fset = fset
def __get__(self, obj, klass=None):
if klass is None:
klass = type(obj)
return self.fget.__get__(obj, klass)()
def __set__(self, obj, value):
if not self.fset:
raise AttributeError("can't set attribute")
type_ = type(obj)
return self.fset.__get__(obj, type_)(value)
def setter(self, func):
if not isinstance(func, (classmethod, staticmethod)):
func = classmethod(func)
self.fset = func
return self
def classproperty(func):
if not isinstance(func, (classmethod, staticmethod)):
func = classmethod(func)
return ClassPropertyDescriptor(func)
class Bar(object):
_bar = 1
#classproperty
def bar(cls):
return cls._bar
#bar.setter
def bar(cls, value):
cls._bar = value
# test instance instantiation
foo = Bar()
assert foo.bar == 1
baz = Bar()
assert baz.bar == 1
# test static variable
baz.bar = 5
assert foo.bar == 5
# test setting variable on the class
Bar.bar = 50
assert baz.bar == 50
assert foo.bar == 50
The setter didn't work at the time we call Bar.bar, because we are calling
TypeOfBar.bar.__set__, which is not Bar.bar.__set__.
Adding a metaclass definition solves this:
class ClassPropertyMetaClass(type):
def __setattr__(self, key, value):
if key in self.__dict__:
obj = self.__dict__.get(key)
if obj and type(obj) is ClassPropertyDescriptor:
return obj.__set__(self, value)
return super(ClassPropertyMetaClass, self).__setattr__(key, value)
# and update class define:
# class Bar(object):
# __metaclass__ = ClassPropertyMetaClass
# _bar = 1
# and update ClassPropertyDescriptor.__set__
# def __set__(self, obj, value):
# if not self.fset:
# raise AttributeError("can't set attribute")
# if inspect.isclass(obj):
# type_ = obj
# obj = None
# else:
# type_ = type(obj)
# return self.fset.__get__(obj, type_)(value)
Now all will be fine.
If you define classproperty as follows, then your example works exactly as you requested.
class classproperty(object):
def __init__(self, f):
self.f = f
def __get__(self, obj, owner):
return self.f(owner)
The caveat is that you can't use this for writable properties. While e.I = 20 will raise an AttributeError, Example.I = 20 will overwrite the property object itself.
[answer written based on python 3.4; the metaclass syntax differs in 2 but I think the technique will still work]
You can do this with a metaclass...mostly. Dappawit's almost works, but I think it has a flaw:
class MetaFoo(type):
#property
def thingy(cls):
return cls._thingy
class Foo(object, metaclass=MetaFoo):
_thingy = 23
This gets you a classproperty on Foo, but there's a problem...
print("Foo.thingy is {}".format(Foo.thingy))
# Foo.thingy is 23
# Yay, the classmethod-property is working as intended!
foo = Foo()
if hasattr(foo, "thingy"):
print("Foo().thingy is {}".format(foo.thingy))
else:
print("Foo instance has no attribute 'thingy'")
# Foo instance has no attribute 'thingy'
# Wha....?
What the hell is going on here? Why can't I reach the class property from an instance?
I was beating my head on this for quite a while before finding what I believe is the answer. Python #properties are a subset of descriptors, and, from the descriptor documentation (emphasis mine):
The default behavior for attribute access is to get, set, or delete the
attribute from an object’s dictionary. For instance, a.x has a lookup chain
starting with a.__dict__['x'], then type(a).__dict__['x'], and continuing
through the base classes of type(a) excluding metaclasses.
So the method resolution order doesn't include our class properties (or anything else defined in the metaclass). It is possible to make a subclass of the built-in property decorator that behaves differently, but (citation needed) I've gotten the impression googling that the developers had a good reason (which I do not understand) for doing it that way.
That doesn't mean we're out of luck; we can access the properties on the class itself just fine...and we can get the class from type(self) within the instance, which we can use to make #property dispatchers:
class Foo(object, metaclass=MetaFoo):
_thingy = 23
#property
def thingy(self):
return type(self).thingy
Now Foo().thingy works as intended for both the class and the instances! It will also continue to do the right thing if a derived class replaces its underlying _thingy (which is the use case that got me on this hunt originally).
This isn't 100% satisfying to me -- having to do setup in both the metaclass and object class feels like it violates the DRY principle. But the latter is just a one-line dispatcher; I'm mostly okay with it existing, and you could probably compact it down to a lambda or something if you really wanted.
If you use Django, it has a built in #classproperty decorator.
from django.utils.decorators import classproperty
For Django 4, use:
from django.utils.functional import classproperty
I think you may be able to do this with the metaclass. Since the metaclass can be like a class for the class (if that makes sense). I know you can assign a __call__() method to the metaclass to override calling the class, MyClass(). I wonder if using the property decorator on the metaclass operates similarly.
Wow, it works:
class MetaClass(type):
def getfoo(self):
return self._foo
foo = property(getfoo)
#property
def bar(self):
return self._bar
class MyClass(object):
__metaclass__ = MetaClass
_foo = 'abc'
_bar = 'def'
print MyClass.foo
print MyClass.bar
Note: This is in Python 2.7. Python 3+ uses a different technique to declare a metaclass. Use: class MyClass(metaclass=MetaClass):, remove __metaclass__, and the rest is the same.
As far as I can tell, there is no way to write a setter for a class property without creating a new metaclass.
I have found that the following method works. Define a metaclass with all of the class properties and setters you want. IE, I wanted a class with a title property with a setter. Here's what I wrote:
class TitleMeta(type):
#property
def title(self):
return getattr(self, '_title', 'Default Title')
#title.setter
def title(self, title):
self._title = title
# Do whatever else you want when the title is set...
Now make the actual class you want as normal, except have it use the metaclass you created above.
# Python 2 style:
class ClassWithTitle(object):
__metaclass__ = TitleMeta
# The rest of your class definition...
# Python 3 style:
class ClassWithTitle(object, metaclass = TitleMeta):
# Your class definition...
It's a bit weird to define this metaclass as we did above if we'll only ever use it on the single class. In that case, if you're using the Python 2 style, you can actually define the metaclass inside the class body. That way it's not defined in the module scope.
def _create_type(meta, name, attrs):
type_name = f'{name}Type'
type_attrs = {}
for k, v in attrs.items():
if type(v) is _ClassPropertyDescriptor:
type_attrs[k] = v
return type(type_name, (meta,), type_attrs)
class ClassPropertyType(type):
def __new__(meta, name, bases, attrs):
Type = _create_type(meta, name, attrs)
cls = super().__new__(meta, name, bases, attrs)
cls.__class__ = Type
return cls
class _ClassPropertyDescriptor(object):
def __init__(self, fget, fset=None):
self.fget = fget
self.fset = fset
def __get__(self, obj, owner):
if self in obj.__dict__.values():
return self.fget(obj)
return self.fget(owner)
def __set__(self, obj, value):
if not self.fset:
raise AttributeError("can't set attribute")
return self.fset(obj, value)
def setter(self, func):
self.fset = func
return self
def classproperty(func):
return _ClassPropertyDescriptor(func)
class Bar(metaclass=ClassPropertyType):
__bar = 1
#classproperty
def bar(cls):
return cls.__bar
#bar.setter
def bar(cls, value):
cls.__bar = value
bar = Bar()
assert Bar.bar==1
Bar.bar=2
assert bar.bar==2
nbar = Bar()
assert nbar.bar==2
I happened to come up with a solution very similar to #Andrew, only DRY
class MetaFoo(type):
def __new__(mc1, name, bases, nmspc):
nmspc.update({'thingy': MetaFoo.thingy})
return super(MetaFoo, mc1).__new__(mc1, name, bases, nmspc)
#property
def thingy(cls):
if not inspect.isclass(cls):
cls = type(cls)
return cls._thingy
#thingy.setter
def thingy(cls, value):
if not inspect.isclass(cls):
cls = type(cls)
cls._thingy = value
class Foo(metaclass=MetaFoo):
_thingy = 23
class Bar(Foo)
_thingy = 12
This has the best of all answers:
The "metaproperty" is added to the class, so that it will still be a property of the instance
Don't need to redefine thingy in any of the classes
The property works as a "class property" in for both instance and class
You have the flexibility to customize how _thingy is inherited
In my case, I actually customized _thingy to be different for every child, without defining it in each class (and without a default value) by:
def __new__(mc1, name, bases, nmspc):
nmspc.update({'thingy': MetaFoo.services, '_thingy': None})
return super(MetaFoo, mc1).__new__(mc1, name, bases, nmspc)
If you only need lazy loading, then you could just have a class initialisation method.
EXAMPLE_SET = False
class Example(object):
#classmethod
def initclass(cls):
global EXAMPLE_SET
if EXAMPLE_SET: return
cls.the_I = 'ok'
EXAMPLE_SET = True
def __init__( self ):
Example.initclass()
self.an_i = 20
try:
print Example.the_I
except AttributeError:
print 'ok class not "loaded"'
foo = Example()
print foo.the_I
print Example.the_I
But the metaclass approach seems cleaner, and with more predictable behavior.
Perhaps what you're looking for is the Singleton design pattern. There's a nice SO QA about implementing shared state in Python.
I am trying to make a python decorator that adds attributes to methods of a class so that I can access and modify those attributes from within the method itself. The decorator code is
from types import MethodType
class attribute(object):
def __init__(self, **attributes):
self.attributes = attributes
def __call__(self, function):
class override(object):
def __init__(self, function, attributes):
self.__function = function
for att in attributes:
setattr(self, att, attributes[att])
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, owner):
return MethodType(self, instance, owner)
retval = override(function, self.attributes)
return retval
I tried this decorator on the toy example that follows.
class bar(object):
#attribute(a=2)
def foo(self):
print self.foo.a
self.foo.a = 1
Though I am able to access the value of attribute 'a' from within foo(), I can't set it to another value. Indeed, when I call bar().foo(), I get the following AttributeError.
AttributeError: 'instancemethod' object has no attribute 'a'
Why is this? More importantly how can I achieve my goal?
Edit
Just to be more specific, I am trying to find a simple way to implement static variable that are located within class methods. Continuing from the example above, I would like instantiate b = bar(), call both foo() and doo() methods and then access b.foo.a and b.doo.a later on.
class bar(object):
#attribute(a=2)
def foo(self):
self.foo.a = 1
#attribute(a=4)
def doo(self):
self.foo.a = 3
The best way to do this is to not do it at all.
First of all, there is no need for an attribute decorator; you can just assign it yourself:
class bar(object):
def foo(self):
print self.foo.a
self.foo.a = 1
foo.a = 2
However, this still encounters the same errors. You need to do:
self.foo.__dict__['a'] = 1
You can instead use a metaclass...but that gets messy quickly.
On the other hand, there are cleaner alternatives.
You can use defaults:
def foo(self, a):
print a[0]
a[0] = 2
foo.func_defaults = foo.func_defaults[:-1] + ([2],)
Of course, my preferred way is to avoid this altogether and use a callable class ("functor" in C++ words):
class bar(object):
def __init__(self):
self.foo = self.foo_method(self)
class foo_method(object):
def __init__(self, bar):
self.bar = bar
self.a = 2
def __call__(self):
print self.a
self.a = 1
Or just use classic class attributes:
class bar(object):
def __init__(self):
self.a = 1
def foo(self):
print self.a
self.a = 2
If it's that you want to hide a from derived classes, use whatever private attributes are called in Python terminology:
class bar(object):
def __init__(self):
self.__a = 1 # this will be implicitly mangled as __bar__a or similar
def foo(self):
print self.__a
self.__a = 2
EDIT: You want static attributes?
class bar(object):
a = 1
def foo(self):
print self.a
self.a = 2
EDIT 2: If you want static attributes visible to only the current function, you can use PyExt's modify_function:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
#wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
It's slightly ugly and hackish. But it works.
My recommendation would be just to use double underscores:
class bar(object):
__a = 1
def foo(self):
print self.__a
self.__a = 2
Although this is visible to the other functions, it's invisible to anything else (actually, it's there, but it's mangled).
FINAL EDIT: Use this:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
#wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
foo.a = foo.func_globals['a']
b = bar()
b.foo() # prints 1
b.foo() # prints 2
# external access
b.foo.a[0] = 77
b.foo() # prints 77
While You can accomplish Your goal by replacing self.foo.a = 1 with self.foo.__dict__['a'] = 1 it is generally not recommended.
If you are using Python2 - (and not Python3) - whenever you retrieve a method from an instance, a new instance method object is created which is a wrapper to the original function defined in the class body.
The instance method is a rather transparent proxy to the function - you can retrieve the function's attributes through it, but not set them - that is why setting an item in self.foo.__dict__ works.
Alternatively you can reach the function object itself using: self.foo.im_func - the im_func attribute of instance methods point the underlying function.
Based on other contributors's answers, I came up with the following workaround. First, wrap a dictionnary in a class resolving non-existant attributes to the wrapped dictionnary such as the following code.
class DictWrapper(object):
def __init__(self, d):
self.d = d
def __getattr__(self, key):
return self.d[key]
Credits to Lucas Jones for this code.
Then implement a addstatic decorator with a statics attribute that will store the static attributes.
class addstatic(object):
def __init__(self, **statics):
self.statics = statics
def __call__(self, function):
class override(object):
def __init__(self, function, statics):
self.__function = function
self.statics = DictWrapper(statics)
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, objtype):
from types import MethodType
return MethodType(self, instance)
retval = override(function, self.statics)
return retval
The following code is an example of how the addstatic decorator can be used on methods.
class bar(object):
#attribute(a=2, b=3)
def foo(self):
self.foo.statics.a = 1
self.foo.statics.b = 2
Then, playing with an instance of the bar class yields :
>>> b = bar()
>>> b.foo.statics.a
2
>>> b.foo.statics.b
3
>>> b.foo()
>>> b.foo.statics.a
3
>>> b.foo.statics.b
5
The reason for using this statics dictionnary follows jsbueno's answer which suggest that what I want would require overloading the dot operator of and instance method wrapping the foo function, which I am not sure is possible. Of course, the method's attribute could be set in self.foo.__dict__, but since it not recommended (as suggested by brainovergrow), I came up with this workaround. I am not certain this would be recommended either and I guess it is up for comments.
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'
I'm learning Python and i've been trying to implement a Singleton-type class as a test. The code i have is as follows:
_Singleton__instance = None
class Singleton:
def __init__(self):
global __instance
if __instance == None:
self.name = "The one"
__instance = self
else:
self = __instance
This works in part but the self = __instance part seems to be failing. I've included some output from the interpretor to demonstrate (the code above is saved in singleton.py):
>>> import singleton
>>> x = singleton.Singleton()
>>> x.name
'The one'
>>> singleton._Singleton__instance.name
'The one'
>>> y = singleton.Singleton()
>>> y.name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Singleton instance has no attribute 'name'
>>> type(y)
<type 'instance'>
>>> dir(y)
['__doc__', '__init__', '__module__']
Is it possible to do what i'm trying? If not is there another way of doing this?
Any suggestions welcome.
Cheers.
Assigning to an argument or any other local variable (barename) cannot ever, possibly have ANY effect outside the function; that applies to your self = whatever as it would to ANY other assignment to a (barename) argument or other local variable.
Rather, override __new__:
class Singleton(object):
__instance = None
def __new__(cls):
if cls.__instance == None:
cls.__instance = object.__new__(cls)
cls.__instance.name = "The one"
return cls.__instance
I've done other enhancements here, such as uprooting the global, the old-style class, etc.
MUCH better is to use Borg (aka monostate) instead of your chosen Highlander (aka singleton), but that's a different issue from the one you're asking about;-).
Bruce Eckel's code snippet from Design Pattern: I'm confused on how it works
class Borg:
_shared_state = {}
def __init__(self):
self.__dict__ = self._shared_state
class MySingleton(Borg):
def __init__(self, arg):
Borg.__init__(self)
self.val = arg
def __str__(self): return self.val
x = MySingleton('sausage')
print x
y = MySingleton('eggs')
print y
z = MySingleton('spam')
print z
print x
print y
print ´x´
print ´y´
print ´z´
output = '''
sausage
eggs
spam
spam
spam
<__main__. MySingleton instance at 0079EF2C>
<__main__. MySingleton instance at 0079E10C>
<__main__. MySingleton instance at 00798F9C>
'''
From Singleton Pattern (Python):
class Singleton(type):
def __init__(self, name, bases, dict):
super(Singleton, self).__init__(name, bases, dict)
self.instance = None
def __call__(self, *args, **kw):
if self.instance is None:
self.instance = super(Singleton, self).__call__(*args, **kw)
return self.instance
class MyClass(object):
__metaclass__ = Singleton
print MyClass()
print MyClass()
This is about the most basic Singleton you can make. It uses a class method to check whether the singleton has been created and makes a new one if it hasn't. There are more advanced ways of going about this, such as overriding the __new__ method.
class Singleton:
instance = None
#classmethod
def get(cls):
if cls.instance is None:
cls.instance = cls()
return cls.instance
def __init__(self):
self.x = 5 # or whatever you want to do
sing = Singleton.get()
print sing.x # prints 5
As for why your code fails, there are several reasons. First, by the time __init__ is called, a new object has already been created, defeating the purpose of the singleton pattern. Second, when you say self = __instance, that simply resets the local variable self; this would be akin to saying
def f(x):
x = 7 # changes the value of our local variable
y = 5
f(y)
print y # this is still 5
Since variables in Python are passed by value and not reference, you can't say self = blah and have it be meaningful in the way you want. The above Singleton class is more what you want, unless you want to get fancy and look into overriding the __new__ operator.
self = _instance
This wont do what you are expecting it to do. Read about how Python treats names.