Add a decorators called @staticproperty
In the following situations: class Data(object): @staticmethod @property def imagesTotal(): return 10 print(Data.imagesTotal) The "print(Data.imagesTotal)" can't print "10", it print "<property object at 0x...>". It might be a good idea to use "@staticproperty" to solve this problem. "@staticproperty" is a decorators, it mix the @staticmethod and @property. Then the static property has getter and setter.
On Sun, Dec 19, 2021 at 3:31 AM <me@chenjt.com> wrote:
I'm not sure that this is actually possible the way you're doing it. The descriptor protocol (which is what makes properties work) won't apply when you're looking up statically. Your best bet, if you really need this sort of thing, would probably be to make a metaclass. But I can't advise further without a good use-case (and the example you've shown above looks extremely unpythonic). ChrisA
I'm confused about what a staticproperty would even be. Usually, properties are a way to provide an interface that "looks like" a simple attribute, but does some computation under the hood. But that computation usually requires instance data to do its thing -- so a static one wouldn't be useful. In fact, in Python, a staticmethod is not very useful at all anyway, all it is is a function that lives in the class namespace. Making it a property would make it look like a class attribute. Hmm, I guess one use case would be to make a read only class attribute. Anyway, the thing is that both staticmethod and property are implimented using descriptors, which I think can only be invoked by instance attribute lookup. That is, the class attribute IS a descriptor instance. And Chris A says -- there may be a way to get a similar effect with Metaclasses, but we'd have to know what your goal is to advise on how to do that. Note: you can put a descriptor on class, and the __get__ will be called, to get part of what I think you want: In [52]: class Ten: ...: def __get__(self, obj, objtype=None): ...: return 10 ...: def __set__(self, obj, value): ...: raise AttributeError("attribute can not be set") ...: In [53]: class A: ...: y = Ten() ...: # attribute access does call the descriptor's __get__: In [54]: A.y Out[54]: 10 But setting the attribute replaces the descriptor, rather than raising an exception: In [55]: A.y = 12 In [56]: A.y Out[56]: 12 Honestly, I don't quite "get" how all this works, but the usual thing is for Descriptors to be invoked on instance attribute access. -CHB On Sat, Dec 18, 2021 at 8:30 AM <me@chenjt.com> wrote:
-- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
All that is needed is a descriptor which calls the decorated functiosn without any parameters. This could serve to use classes as namespaces for "live" globals - if one will do some sort of reactive programing, it might even find some use. A descriptor with a for that would be something like: class staticproperty: def __init__(self, func, setter=None): self.func = func self.setter = setter def __get__(self, instance, owner): return self.func # setter code (won't work statically) def __set__(self, instance, value): return self.setter(value) def setter(self, func): return type(self)(self.func, func) I wrote the "setter" code above, but actually it won't work statically - for the descriptor protocol to call __set__ it must be operating with an instance of the class. It could still work involving metaclasses - but if you want the setter only, the above snippet should work. Should it be on the stdlib? I don't think so - its usage would be too specific, and there are differing interpretations to what it should actually do. On Sat, 18 Dec 2021 at 14:23, Christopher Barker <pythonchb@gmail.com> wrote:
If the goal is to create a "property" that behaves like such but doesn't receive "self" as a parameter, the straightforward way to do so would be a simple descriptor. class StaticProperty: def __init__(self, fget=None, fset=None, fdel=None): self.fget = fget self.fset = fset self.fdel = fdel def setter(self, fset): self.fset = fset return self def deleter(self, fdel): self.fdel = fdel return self def __get__(self, instance, owner=None): return self.fget() def __set__(self, instance, value): return self.fset(value) def __delete__(self, instance): return self.fdel() Example: class A: @StaticProperty def number(): return 10 @number.setter def number(value): if value != 10: raise ValueError("Invalid assignment") @number.deleter def number(): raise AttributeError("Can't remove it!") For reading it, both from class and instance would work (A.number == a.number). However it behaves like a common property for attribute setting/deleting in the sense that an assignment to the class (e.g. A.number = 11) would replace it and a removal (del A.number) would indeed delete it from the class namespace. To avoid this, the change must happen in the metaclass, so it's no longer that simple. Is there an use case for this scenario, where an attribute assignment (and/or an attribute removal) should do the same thing on both class and instance? On Sat, 18 Dec 2021 at 14:41, Joao S. O. Bueno <jsbueno@python.org.br> wrote:
-- Danilo J. S. Bellini
By way of correcting misconceptions: On 12/18/21 8:39 AM, Chris Angelico wrote:
On 12/18/21 9:19 AM, Christopher Barker wrote:
Anyway, the thing is that both staticmethod and property are implimented using descriptors, which I think can only be invoked by instance attribute lookup. That is, the class attribute IS a descriptor instance.
While it is true that a descriptor does not get the chance to run its `__set__` and `__delete__` methods when called on the class, it does get to run its `__get__` method. In code: class descriptor_example: # def __get__(self, instance, owner=None): if owner is not None: print('called directly from the class, have a cookie!') return 'chocolate-chip cookie' # def __set__(self, instance, value): # never called from the class raise TypeError # def __delete__(self, instance, value): # never called from the class raise TypeError class Test: huh = descriptor_example() >>> Test.huh called directly from the class, have a cookie! chocolate-chip cookie >>> Test.huh = 7 # change `huh` >>> Test.huh 7 >>> Test.huh = descriptor_example() # put it back >>> Test.huh called directly from the class, have a cookie! chocolate-chip cookie >>> del Test.huh # remove huh >>> Test.huh AttributeError Having said that, I don't think it's needs direct support in the stdlib. -- ~Ethan~
Thank everyone! I just want to use a class that holds global variables and has a value that can be easily calculated. So I thought it would be more elegant to use "@staticproperty". These is just my personal thought and not necessary. Now you've given me the solution.
18.12.21 13:18, me@chenjt.com пише:
classmethod supersedes staticmethod. It was not clearly known when they were introduced, but now we see that there is very few use cases for staticmethod which cannot be replaced by classmethod (actually only one specific case). If it would be known in advance staticmethod would be not added. So you can use a combination of @classmethod and @property. class Data: @classmethod @property def imagesTotal(cls): return 10 There are some issues with help() and unittest.mock. They may not work as you expected.
19.12.21 19:41, Ethan Furman пише:
Setting a Python function as a class attribute without making it a method. def func(*args, **kwargs): ... class A: f = staticmethod(func) a = A() a.f(1) # calls func(1), not func(a, 1) It is used in tests if there are C and Python implementations. staticmethod(func) could be replaced with lambda self, /, *args, **kwargs: func(*args, **kwargs) or property(lambda self: func) in these cases.
Totally agree with this. I think both of points should be clarified in the documentation: https://docs.python.org/3/library/functions.html#staticmethod Namely that: * Nearly all uses of static methods should instead be class methods, and * The main exception is setting an ordinary function as a class attribute without making it a method. Best, Neil On Sunday, December 19, 2021 at 3:07:38 PM UTC-5 Serhiy Storchaka wrote:
On Sun, Dec 19, 2021 at 5:41 AM Serhiy Storchaka <storchaka@gmail.com> wrote: So you can use a combination of @classmethod and @property.
And this would be more useful anyway: if you want a class property, it may well need access to other class attributes— and now you have that access: -CHB
-- Christopher Barker, PhD (Chris) Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython
participants (9)
-
Chen Jintao
-
Chris Angelico
-
Christopher Barker
-
Danilo J. S. Bellini
-
Ethan Furman
-
Joao S. O. Bueno
-
me@chenjt.com
-
Neil Girdhar
-
Serhiy Storchaka