Using property() on classmethods
python property object
python property setter
python property with arguments
how is a property created?
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?
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
>>> 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
11. Methods and @property, addStatic(10) # staticmethod : 30 if __name__ == '__main__': main(). Below is will break. But we can solve this problem using 'classmethod' as shown next. A property may be declared as a static property by using the static keyword. This makes the property available to callers at any time, even if no instance of the class exists. This makes the property available to callers at any time, even if no instance of the class exists.
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
Issue 20659: Want to make a class method a property by combining , The problems is that it is quite possible to define a property using method, using @classmethod annotation, the @property annotation will fail to work. property back to method invocations, with a "()" 2) Change the name, Python classmethod() The classmethod() method returns a class method for the given function. The syntax of classmethod() method is: classmethod() is considered un-Pythonic so in newer Python versions, you can use the @classmethod decorator for classmethod definition.
I hope this dead-simple read-only
@classproperty decorator would help somebody looking for classproperties.
class classproperty(object): def __init__(self, fget): self.fget = fget 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
Python classmethod(), classmethod() is considered un-Pythonic so in newer Python versions, you can use the @classmethod decorator for classmethod definition. The syntax is: @ Normally, we use accessor methods to modify and retrieve values in C++ and Visual Basic. If you have programmed using Visual Basic's ActiveX technology, this concept is not new to you. Visual Basic extensively uses accessor methods such as getXXX () and setXXX () to create user-defined properties.
Is it possible to use the property() function with classmethod decorated functions?
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
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.
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
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.
property() function in Python, Python - property() function. Traditional object-oriented languages like Java and C# use properties in a class to encapsulate data. Property includes the getter Classes, objects, methods and properties. Object-oriented programming is a programming style in which it is customary to group all of the variables and functions of a particular topic into a single class. Object-oriented programming is considered to be more advanced and efficient than the procedural style of programming.
Old question, lots of views, sorely in need of a one-true Python 3 way.
Luckily, it's easy with the
class FooProperties(type): @property def var(cls): return cls._var class Foo(object, metaclass=FooProperties): _var = 'FOO!'
Chapter 25, A function is a block of code that begins with the Python keyword def followed "1+1" if __name__ == "__main__": value = a_function() print(value) decorator The @classmethod decorator can be called with with an instance of a class or One of the simplest ways to use a property is to use it as a decorator of a method. In conclusion, @classmethod decorator convert a conventional method to a factory method,Using classmethods makes it possible to add as many alternative constructors as necessary.
Python's @classmethod and @staticmethod Explained, While I could be referring to quite a few different things with this statement, in this This decorator exists so you can create class methods that are passed the 0 or g > 100: raise Exception() try: # Try out some valid grades class_grades_valid class Shape(object): # this is an abstract class that is primarily used for inheritance defaults # here is where you would define classmethods that can be overridden by inherited classes @classmethod def from_square(cls, square): # return a default instance of cls return cls()
Python's Instance, Class, and Static Methods Demystified – Real , Delicious Pizza Factories With @classmethod; When To Use Static Methods; Key Calling classmethod() showed us it doesn't have access to the <MyClass also be a good candidate for an @property — but hey, this is just a toy example). A property is a member that provides a flexible mechanism to read, write, or compute the value of a private field. Properties can be used as if they are public data members, but they are actually special methods called accessors .
Python tricks: properties, staticmethods, and classmethods, classmethod() methods are bound to class rather than an object. Class methods can be called by both class and object. These methods can be call with class or Using the Write-* cmdlets, you can still write to PowerShell's output streams from within a class method. However, this should be avoided so that the method emits objects using only the return statement. Method output. This example demonstrates no accidental output to the pipeline from class methods, except on the return statement.
- This doesn't seem to work for me in Python 3.2. If I change foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func) to foo.__metaclass__.var = property(foo.getvar.__func__, foo.setvar.__func__) I get "AttributeError: type object 'foo' has no attribute 'var'" when executing "foo.var".
- SIGH double correction: this works in Python 2.7, but not Python 3.2.
- @MichaelKelley - That's because the syntax for metaclasses has changed in Python 3.x
- I am not quite sure to understand, what would be the Python 3.x way to write this then ?
- @Josay: You'd need to define the metaclass first, then define the class using the new
- I don't think the setter part of the ClassProperty actually works as described: while the example's assertions all pass, at the end foo._var == 4 (not 3, as implied). Setting the property clobbers the property itself. When class-properties were discussed on python-dev it was pointed out that, while getters are trivial, setters are difficult (impossible?) without a metaclass
- @Gabriel Totally correct. I can't believe no one pointed that out for two years.
- I'm also not sure why you don't not just use
self.fget(owner)and remove the need to have to use a
@classmethodat all here? (that's what
.__get__(instance, owner)(*args, **kwargs)to
function(owner, *args, **kwargs)calls, via an intermediary; properties don't need the intermediary).
- Your demonstration is lacking any actual transformation in either the getter or the setter that would neatly demonstrate that your
foo.var = 3assignment doesn't actually go through the property, and instead has simply replaced the property object on
foowith an integer. If you added
assert isinstance(foo.__dict__['var'], ClassProperty)calls between your assertions you'd see that fail after
foo.var = 3is executed.
- Python classes don't support descriptor binding on setting on the class itself, only on getting (so
instance.attr = valueand
del instance.attrwill all bind the descriptor found on
type(instance), but while
classobj.attr = valueand
del classobj.attrdo not and instead replace or delete the descriptor object itself). You need a metaclass to support setting and deleting (making the class object the instance, and the metaclass the type).
- Does this work with subclasses? (can a subclass override classproperties?)
- Umm yes?
class D(C): x = 2; assert D.x == 2