Properties for classes possible?
I think it would be great to have properties for classes in Python2 and Python3 There are some "patterns" to get this working: http://stackoverflow.com/questions/5189699/how-can-i-make-a-class-property-i... http://stackoverflow.com/questions/128573/using-property-on-classmethods ... but an official solution would be more "zen of python". Do you think properties for classes would be useful? If it works for classes, then it could be used for modules, too? Regards, Thomas Güttler PS: my first post via google groups web interface did not arrive here. That's the second try. Now via mail. -- Thomas Guettler http://www.thomas-guettler.de/
You can define a property on the metaclass for this effect. On Thu, Aug 20, 2015 at 2:54 AM, Thomas Güttler < guettliml@thomas-guettler.de> wrote:
I think it would be great to have properties for classes in Python2 and Python3
There are some "patterns" to get this working:
http://stackoverflow.com/questions/5189699/how-can-i-make-a-class-property-i...
http://stackoverflow.com/questions/128573/using-property-on-classmethods
... but an official solution would be more "zen of python".
Do you think properties for classes would be useful?
If it works for classes, then it could be used for modules, too?
Regards, Thomas Güttler
PS: my first post via google groups web interface did not arrive here. That's the second try. Now via mail.
-- Thomas Guettler http://www.thomas-guettler.de/ _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Aug 19, 2015, at 23:54, Thomas Güttler <guettliml@thomas-guettler.de> wrote:
I think it would be great to have properties for classes in Python2 and Python3
Well, Python 2 has been closed to new features for years now. Anyway, if you add a property to a metaclass, it does exactly what you want. (After all, a metaclass is the type of a class object, which is where you put class descriptors.)
There are some "patterns" to get this working:
http://stackoverflow.com/questions/5189699/how-can-i-make-a-class-property-i...
http://stackoverflow.com/questions/128573/using-property-on-classmethods
... but an official solution would be more "zen of python".
Do you think properties for classes would be useful?
If it works for classes, then it could be used for modules, too?
Modules are a more serious problem, because there's no immediate way to specify the type for a module object. You can work around it by, e.g., declaring a module subclass, copying the module's dict to an instance of that subclass, then replacing the entry in sys.modules, but this is more than a little ugly. There have been proposals to allow modules to specify a type (e.g., something similar to the way __metaclass__ worked in 2.x), and to make it easier to hook the import machinery to create modules of a custom type, and probably other variations on this. You might want to search this list and -dev for previous ideas, to find one you think should be reconsidered.
Regards, Thomas Güttler
PS: my first post via google groups web interface did not arrive here. That's the second try. Now via mail.
-- Thomas Guettler http://www.thomas-guettler.de/ _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Thu, Aug 20, 2015 at 12:20 AM, Andrew Barnert via Python-ideas <python-ideas@python.org> wrote:
Modules are a more serious problem, because there's no immediate way to specify the type for a module object. You can work around it by, e.g., declaring a module subclass, copying the module's dict to an instance of that subclass, then replacing the entry in sys.modules, but this is more than a little ugly.
There have been proposals to allow modules to specify a type (e.g., something similar to the way __metaclass__ worked in 2.x), and to make it easier to hook the import machinery to create modules of a custom type, and probably other variations on this. You might want to search this list and -dev for previous ideas, to find one you think should be reconsidered.
This is already done :-). Python 3.5 allows a module to contain code like: class MetaModule(types.ModuleType): @property def some_attribute(self): print("Accessing module.some_attribute") return 1 sys.modules[__name__].__class__ = MetaModule See also https://pypi.python.org/pypi/metamodule for utility code and a polyfill back to ancient Pythons. -n -- Nathaniel J. Smith -- http://vorpus.org
Sounds more like Thomas is looking for an Pythonic solution without messing around with sys.modules or metaclasses. I personally like the proposals on StackOverflow and don't see why it couldn't be made to work out of the box: class MyClass: @classproperty def prop(cls): return '42' # module property @property def prop(mod): return '42' On 20.08.2015 09:47, Nathaniel Smith wrote:
On Thu, Aug 20, 2015 at 12:20 AM, Andrew Barnert via Python-ideas <python-ideas@python.org> wrote:
Modules are a more serious problem, because there's no immediate way to specify the type for a module object. You can work around it by, e.g., declaring a module subclass, copying the module's dict to an instance of that subclass, then replacing the entry in sys.modules, but this is more than a little ugly.
There have been proposals to allow modules to specify a type (e.g., something similar to the way __metaclass__ worked in 2.x), and to make it easier to hook the import machinery to create modules of a custom type, and probably other variations on this. You might want to search this list and -dev for previous ideas, to find one you think should be reconsidered. This is already done :-). Python 3.5 allows a module to contain code like:
class MetaModule(types.ModuleType): @property def some_attribute(self): print("Accessing module.some_attribute") return 1
sys.modules[__name__].__class__ = MetaModule
See also
https://pypi.python.org/pypi/metamodule
for utility code and a polyfill back to ancient Pythons.
-n
How are metaclasses unpythonic? This is one of the more defining features of python. There will be no way to properly implement this without moving the descriptor up to the metaclass. When thinking about metaclasses, it is often best to just think of them as classes and other types as instances. On Thu, Aug 20, 2015 at 11:20 AM, Sven R. Kunze <srkunze@mail.de> wrote:
Sounds more like Thomas is looking for an Pythonic solution without messing around with sys.modules or metaclasses.
I personally like the proposals on StackOverflow and don't see why it couldn't be made to work out of the box:
class MyClass: @classproperty def prop(cls): return '42'
# module property @property def prop(mod): return '42'
On 20.08.2015 09:47, Nathaniel Smith wrote:
On Thu, Aug 20, 2015 at 12:20 AM, Andrew Barnert via Python-ideas <python-ideas@python.org> wrote:
Modules are a more serious problem, because there's no immediate way to specify the type for a module object. You can work around it by, e.g., declaring a module subclass, copying the module's dict to an instance of that subclass, then replacing the entry in sys.modules, but this is more than a little ugly.
There have been proposals to allow modules to specify a type (e.g., something similar to the way __metaclass__ worked in 2.x), and to make it easier to hook the import machinery to create modules of a custom type, and probably other variations on this. You might want to search this list and -dev for previous ideas, to find one you think should be reconsidered.
This is already done :-). Python 3.5 allows a module to contain code like:
class MetaModule(types.ModuleType): @property def some_attribute(self): print("Accessing module.some_attribute") return 1
sys.modules[__name__].__class__ = MetaModule
See also
https://pypi.python.org/pypi/metamodule
for utility code and a polyfill back to ancient Pythons.
-n
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Am 20.08.2015 um 17:27 schrieb Joseph Jevnik:
How are metaclasses unpythonic? This is one of the more defining features of python. There will be no way to properly implement this without moving the descriptor up to the metaclass. When thinking about metaclasses, it is often best to just think of them as classes and other types as instances.
Yes, metaclasses are a great feature for experts. For me this syntax is the most readable:
class MyClass: @classproperty def prop(cls): return '42'--
I think that syntax would be fine, but then `type.__new__` would need to do something special with that to implement the setter protocol for the types. On Thu, Aug 20, 2015 at 11:34 AM, Thomas Güttler < guettliml@thomas-guettler.de> wrote:
Am 20.08.2015 um 17:27 schrieb Joseph Jevnik:
How are metaclasses unpythonic? This is one of the more defining features of python. There will be no way to properly implement this without moving the descriptor up to the metaclass. When thinking about metaclasses, it is often best to just think of them as classes and other types as instances.
Yes, metaclasses are a great feature for experts.
For me this syntax is the most readable:
class MyClass:
@classproperty def prop(cls): return '42'--
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Am 20.08.2015 um 17:20 schrieb Sven R. Kunze:
Sounds more like Thomas is looking for an Pythonic solution without messing around with sys.modules or metaclasses.
I personally like the proposals on StackOverflow and don't see why it couldn't be made to work out of the box:
class MyClass: @classproperty def prop(cls): return '42'
The following solution provides an @classproperty: http://stackoverflow.com/a/5191224/633961 I have not tried setting the value yet, but getting the value works very fine. It would be great to have "@classproperty" even in Python2. Or at least installable via pip. I am just a user in this case. I don't know about the best, cleanest, most efficient way to implement this. Regards, Thomas -- Thomas Guettler http://www.thomas-guettler.de/
On 20.08.2015 17:31, Thomas Güttler wrote:
The following solution provides an @classproperty: http://stackoverflow.com/a/5191224/633961
I have not tried setting the value yet, but getting the value works very fine.
It would be great to have "@classproperty" even in Python2. Or at least installable via pip.
I am just a user in this case. I don't know about the best, cleanest, most efficient way to implement this.
Reminds me of cached_property: https://pypi.python.org/pypi/cached-property/0.1.5 I feel it could be useful to have a holistic solution (property + cached + instance,classes,modules) in the stdlib/Python somehow. Best, Sven
Cached properties are trivially implemented class C: @property @lru_cache(None) def p(self): ... On Thu, Aug 20, 2015 at 11:57 AM, Sven R. Kunze <srkunze@mail.de> wrote:
On 20.08.2015 17:31, Thomas Güttler wrote:
The following solution provides an @classproperty: http://stackoverflow.com/a/5191224/633961
I have not tried setting the value yet, but getting the value works very fine.
It would be great to have "@classproperty" even in Python2. Or at least installable via pip.
I am just a user in this case. I don't know about the best, cleanest, most efficient way to implement this.
Reminds me of cached_property: https://pypi.python.org/pypi/cached-property/0.1.5
I feel it could be useful to have a holistic solution (property + cached + instance,classes,modules) in the stdlib/Python somehow.
Best, Sven
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
On Thu, Aug 20, 2015 at 11:57 AM, Sven R. Kunze <srkunze@mail.de> wrote:
On 20.08.2015 17:31, Thomas Güttler wrote:
The following solution provides an @classproperty: http://stackoverflow.com/a/5191224/633961
I have not tried setting the value yet, but getting the value works very fine.
It would be great to have "@classproperty" even in Python2. Or at least installable via pip.
I am just a user in this case. I don't know about the best, cleanest, most efficient way to implement this.
Reminds me of cached_property: https://pypi.python.org/pypi/cached-property/0.1.5
I feel it could be useful to have a holistic solution (property + cached + instance,classes,modules) in the stdlib/Python somehow.
Having something like a cached-property (or the lazy=True option in my classproperty implementation) is rather nice, but as Guido points out it's out of scope for a general implementation of @classproperty (it's also easy enough to implement memoization patterns outside the stdlib). However, for (settable) @classproperty to work seamlessly, without having to involve custom metaclasses, would require a CPython implementation and probably a PEP. For in order for this to work it would have to be special-cased, since assignments to a class attribute don't normally go through <descriptor>.__set__. Erik
What about 'staticproperties'? On 20.08.2015 18:07, Erik Bray wrote:
On Thu, Aug 20, 2015 at 11:57 AM, Sven R. Kunze <srkunze@mail.de> wrote:
On 20.08.2015 17:31, Thomas Güttler wrote:
The following solution provides an @classproperty: http://stackoverflow.com/a/5191224/633961
I have not tried setting the value yet, but getting the value works very fine.
It would be great to have "@classproperty" even in Python2. Or at least installable via pip.
I am just a user in this case. I don't know about the best, cleanest, most efficient way to implement this.
Reminds me of cached_property: https://pypi.python.org/pypi/cached-property/0.1.5
I feel it could be useful to have a holistic solution (property + cached + instance,classes,modules) in the stdlib/Python somehow. Having something like a cached-property (or the lazy=True option in my classproperty implementation) is rather nice, but as Guido points out it's out of scope for a general implementation of @classproperty (it's also easy enough to implement memoization patterns outside the stdlib).
However, for (settable) @classproperty to work seamlessly, without having to involve custom metaclasses, would require a CPython implementation and probably a PEP. For in order for this to work it would have to be special-cased, since assignments to a class attribute don't normally go through <descriptor>.__set__.
Erik
Am 20.08.2015 um 18:42 schrieb Sven R. Kunze:
What about 'staticproperties'?
Yes, that sound good. In my case a read-only classproperty is all I need. I guess that is what you mean with "staticproperty". Regards, Thomas Güttler -- Thomas Guettler http://www.thomas-guettler.de/
The thinking was more like: instancemethod -> property classmethod -> classproperty staticmethod -> staticproperty On 21.08.2015 09:01, Thomas Güttler wrote:
Am 20.08.2015 um 18:42 schrieb Sven R. Kunze:
What about 'staticproperties'?
Yes, that sound good. In my case a read-only classproperty is all I need.
I guess that is what you mean with "staticproperty".
Regards, Thomas Güttler
On Thu, Aug 20, 2015 at 2:54 AM, Thomas Güttler <guettliml@thomas-guettler.de> wrote:
I think it would be great to have properties for classes in Python2 and Python3
There are some "patterns" to get this working:
http://stackoverflow.com/questions/5189699/how-can-i-make-a-class-property-i...
http://stackoverflow.com/questions/128573/using-property-on-classmethods
... but an official solution would be more "zen of python".
I recently added my own implementation of this here: https://github.com/astropy/astropy/blob/master/astropy/utils/decorators.py#L... (which I think is pretty elegant--moreso than the ones on those SO links, but I'm biased :) However, my version is only for read-only properties. It could easily be extended to support writeable properties, but as pointed out elsewhere that requires the container class to have a custom metaclass :/
Do you think properties for classes would be useful?
Yes--given my recent experience in trying to implement this I feel like it should be supported in Python. Just as Python ships with a builtin classmethod, I think there should be a builtin classproperty that is special-cased to work without a custom metaclass. I think it's a special case that's special enough IMO.
If it works for classes, then it could be used for modules, too?
With a ModuleType subclass, sure, but that's a separate, and thornier issue :) Erik
I think it's reasonable to propose @classproperty as a patch to CPython. It needs to be C code. Not sure about the writable version. The lazy=True part is not appropriate for th he stdlib (it's just a memoize pattern). --Guido (on mobile)
Am 20.08.2015 um 17:29 schrieb Guido van Rossum:
I think it's reasonable to propose @classproperty as a patch to CPython. It needs to be C code. Not sure about the writable version. The lazy=True part is not appropriate for th he stdlib (it's just a memoize pattern).
What's the next step? My knowledge of the programming language C is very limited. I am not able to write a patch for CPython. I could write a patch which looks like this: {{{ # From http://stackoverflow.com/a/5192374/633961 class classproperty(object): def __init__(self, f): self.f = f def __get__(self, obj, owner): return self.f(owner) }}} -- Thomas Guettler http://www.thomas-guettler.de/
On 8/24/2015 6:07 AM, Thomas Güttler wrote:
Am 20.08.2015 um 17:29 schrieb Guido van Rossum:
I think it's reasonable to propose @classproperty as a patch to CPython. It needs to be C code. Not sure about the writable version. The lazy=True part is not appropriate for th he stdlib (it's just a memoize pattern).
What's the next step?
Open an issue on the tracker. Quote Guido's message above with list name, date, and thread name -- or pipermail archive url. Add python code below, or revision thereof, for someone to translate to C.
My knowledge of the programming language C is very limited. I am not able to write a patch for CPython.
I could write a patch which looks like this:
{{{ # From http://stackoverflow.com/a/5192374/633961
class classproperty(object): def __init__(self, f): self.f = f def __get__(self, obj, owner): return self.f(owner)
}}}
-- Terry Jan Reedy
Here is the created issue: http://bugs.python.org/issue24941 Please let me know if something is missing. Thomas Güttler Am 24.08.2015 um 19:17 schrieb Terry Reedy:
On 8/24/2015 6:07 AM, Thomas Güttler wrote:
Am 20.08.2015 um 17:29 schrieb Guido van Rossum:
I think it's reasonable to propose @classproperty as a patch to CPython. It needs to be C code. Not sure about the writable version. The lazy=True part is not appropriate for th he stdlib (it's just a memoize pattern).
What's the next step?
Open an issue on the tracker. Quote Guido's message above with list name, date, and thread name -- or pipermail archive url. Add python code below, or revision thereof, for someone to translate to C.
My knowledge of the programming language C is very limited. I am not able to write a patch for CPython.
I could write a patch which looks like this:
{{{ # From http://stackoverflow.com/a/5192374/633961
class classproperty(object): def __init__(self, f): self.f = f def __get__(self, obj, owner): return self.f(owner)
}}}
-- Thomas Guettler http://www.thomas-guettler.de/
On 8/26/2015 3:07 AM, Thomas Güttler wrote:
Here is the created issue: http://bugs.python.org/issue24941
Please let me know if something is missing.
How would a reviewer know that your Python code works properly? How would a C translator know that the translation is correct? Write a unittest for the proposed builtin. (I would start with the current test for property.) If possible, submit it as a patch to whatever file has the unittest for property. If you cannot create .diffs, post the code in a message. -- Terry Jan Reedy
On Thu, Aug 20, 2015 at 12:54 AM, Thomas Güttler <guettliml@thomas-guettler.de> wrote:
I think it would be great to have properties for classes in Python2 and Python3
As always there's a rich history to which we can turn: on the mailing lists and the issue tracker. The addition of a "class property" is not a new idea, which implies it *might* be worth pursuing, but only if the previous obstacles/objections are resolved. [1] Furthermore, composition of abc.abstractmethod and property/classmethod/staticmethod was added not that long ago. The evolution of that composition provides some context for what is appropriate here. [2] Note that first we added abc.abstractmethod, then abc.abstractclassmethod, and then proper composition (abc.abstractmethod + classmethod). Though it's subtly different than the abstractmethod case, I suggest we avoid adding "classproperty" and skip straight to getting the composition approach working in a similar way to abstractmethod [3]: class Spam: @classmethod @property def eggs(cls): return 42 [Note that the alternate composition order doesn't work out since property is a descriptor that resolves strictly against instances. Would that be obvious enough or a point of confusion?] Unfortunately, there is a problem with applying classmethod onto property. Obviously a property isn't a function such that "classmethod" is an accurately described modifier. This is more concretely problematic because the classmethod implementation directly wraps the decorated object in a method object. [4] In Python it would look like this: class classmethod: def __init__(self, func): self.func = func def __get__(self, obj, cls): return types.MethodType(self.func, cls) I expect that this is an optimization over calling self.func.__get__, which optimization was likely supported by the sensible assumption that only functions would be passed to classmethod. The naive implementation of classmethod would look more like this: class classmethod: def __init__(self, func): self.func = func def __get__(self, obj, cls): return self.func.__get__(cls, type(cls)) If that were the actual implementation then we wouldn't be having this conversation. :) So to get composition to work correctly we have 3 options: 1. switch to the less efficient, naive implementation of classmethod.__get__ 2. add "classproperty", which does the right thing 3. add "classresolved" (or similarly named), which resolves wrapped descriptors to the class rather than the instance I advocate for #3 over the others. It provides for broader application while not impacting the optimizations in classmethod (and it has a more accurate name). It would work similarly to the naive classmethod implementation (and work as a less efficient replacement for classmethod): class classresolved: def __init__(self, wrapped): self.wrapped = wrapped def __get__(self, obj, cls): try: getter = self.wrapped.__get__ except AttributeError: return self.wrapped return getter(cls, type(cls)) Note that wrapped data descriptors (like property) would behave as non-data descriptors since classresolved is itself a non-data descriptor. The case for making it a data descriptor can be treated separately, but I don't think that case is as strong. All this leads to some broader observations about useful, generic descriptors in the stdlib. I'll open a new thread for that conversation.
There are some "patterns" to get this working:
http://stackoverflow.com/questions/5189699/how-can-i-make-a-class-property-i...
http://stackoverflow.com/questions/128573/using-property-on-classmethods
... but an official solution would be more "zen of python".
Do you think properties for classes would be useful?
I think so. Here are use cases off the top of my head: * read-only class attrs * dynamically generated class attrs * lazily generated class attrs * class attrs that track access * class attrs that interact with a class registry * class attrs that replace themselves on the class upon first use * ... So basically stick in nearly all the use cases for properties, but applied to classes. The main difference is that a "class property" would be a non-data descriptor. Pursuing a data descriptor approach is debatably overreaching and potentially problematic. Note that normally bound class attrs still meet most needs, so any solution here should be cognizant of the possibility of providing an attractive nuisance here (and avoid it!).
If it works for classes, then it could be used for modules, too?
Module attribute access does not involve the descriptor protocol. There are ways to work around that to support descriptors (e.g. the module-replaces-itself-in-sys-modules trick), but that is an orthogonal issue. Furthermore, using some other mechanism than the descriptor protocol to achieve module "properties" isn't worth it ("special cases aren't special enough..."). -eric [1] Some examples from the history of the idea: (oct2005) https://mail.python.org/pipermail/python-list/2005-October/321426.html an attempt to implement classproperty (jan2011) https://mail.python.org/pipermail/python-ideas/2011-January/008950.html Enumeration of many permutations of decorators; proposal to add classproperty; Guido in favor; Michael shows a simple implementation (feb2014) http://bugs.python.org/issue20659 "To get the behaviour you're requesting, you need to use a custom metaclass and define the property there." [2] Changes relative to abc.abstractmethod: (apr2009) http://bugs.python.org/issue5867 Compose abc.abstractmethod and classmethod (changed to abc.abstractclassmethod)...Guido said "I object to making changes to the classmethod implementation." (mar2011) http://bugs.python.org/issue11610 Compose abc.abstractmethod and property/classmethod/staticmethod/ [3] https://docs.python.org/3/library/abc.html#abc.abstractmethod [4] https://hg.python.org/cpython/file/default/Objects/funcobject.c (cm_descr_get)
participants (10)
-
Andrew Barnert
-
Eric Snow
-
Erik Bray
-
Guido van Rossum
-
Joseph Jevnik
-
Nathaniel Smith
-
Steven D'Aprano
-
Sven R. Kunze
-
Terry Reedy
-
Thomas Güttler