How to make a class property?
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 callingTypeOfBar.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.
Is there any way to create a class property in Python?
If you want the descriptor property
to trigger when you get an attribute from object X, then you must put the descriptor in type(X)
. So if X is a class, the descriptor must go in the class's type, also known as the class's metaclass -- no "trickery" involved, it's just a matter of completely general rules.
Alternatively, you might write your own special-purpose descriptor. See here for an excellent "how-to" treaty on descriptors. Edit for example:
class classprop(object):
def __init__(self, f):
self.f = classmethod(f)
def __get__(self, *a):
return self.f.__get__(*a)()
class buh(object):
@classprop
def bah(cls): return 23
print buh.bah
emits 23
, as desired.
How to create a read-only class property in Python?
The property
descriptor always returns itself when accessed from a class (ie. when instance
is None
in its __get__
method).
If that's not what you want, you can write a new descriptor that always uses the class object (owner
) instead of the instance:
>>> class classproperty(object):
... def __init__(self, getter):
... self.getter= getter
... def __get__(self, instance, owner):
... return self.getter(owner)
...
>>> class Foo(object):
... x= 4
... @classproperty
... def number(cls):
... return cls.x
...
>>> Foo().number
4
>>> Foo.number
4
How to setup a class property in objective C?
Since Xcode 8 you can define a class property in the header file of YourClass, using the "class" identifier like:
@interface YourClass : NSObject
@property (class, strong, nonatomic) NSTimer *timer;
@end
To use the class property in class methods in your implementation you need to asign a static instance variable to your class property. This allows you to use this instance variable in class methods (class methods start with "+").
@implementation YourClass
static NSTimer *_timer;
You have to create getter and setter methods for the class property, as these will not be synthesized automatic.
+ (void)setTimer:(NSTimer*)newTimer{
if (_timer == nil)
_timer = newTimer;
}
+ (NSTimer*)timer{
return _timer;
}
// your other code here ...
@end
Now you can access the class property from all over the app and other methods with the following syntax - here are some examples:
NSTimeInterval seconds = YourClass.timer.fireDate.timeIntervalSinceNow;
[[YourClass timer] invalidate];
You will always send messages to the same object, no problems with multiple instances!
Please find an Xcode 11 sample project here: GitHub sample code
Creation and persistence of a class property in Python
Every time you access sig.t
, the t
function you decorated with @property
is (re)run, and the result is used as the value of sig.t
. That means the array is created on demand and never stored on the t
object.
You seem to want this, but I'd be wary about it. Property accesses are generally expected to be cheap, and this property isn't. Consider making an ordinary method instead.
Is it possible to create a class property that is a combination of other properties?
Update your class like so:
public class Person
{
public string Last { get; set; }
public string First { get; set; }
public string FullName
{
get
{
return string.Format("{0}, {1}", First, Last);
}
}
}
Additional to your question, I would also recommend implementing an override of the ToString()
method (your question mentions making display easier) as most UI technologies will use this as a default way of displaying an object.
public override string ToString()
{
return FullName;
}
Python 3.4 - How to create a template property for many classes
If your object will never have more than one of the templated properties, then you can write a simple function that builds an appropriate property object and returns it:
def PositiveValuedProperty():
def getter(obj):
return obj.__value
def setter(obj, new_value):
if new_value < 1:
new_value = 1
obj.__value = new_value
return property(getter, setter)
Then your classes would be:
class Robot:
Price = PositiveValuedProperty()
class Box:
Weight = PositiveValuedProperty()
This wont work however if any class uses multiples of these properties, since they're all writing to the same attribute name. If you want to allow more than one to be in a class, you'll probably want to specify an attribute name to the factory function:
def PositiveValuedProperty(name):
name = "_" + name
def getter(obj):
return getattr(obj, name)
def setter(obj, new_value):
if new_value < 1:
new_value = 1
setattr(obj, name, new_value)
return property(getter, setter)
Now you could set up a RobotBox
with both a Price
and a Weight
:
def RobotBox():
Price = PositiveValuedProperty("Price")
Weight = PositiveValuedProperty("Weight")
The actual values will be stored in attributes _Price
and _Weight
if you want internal code to access them without going through the property
's checks.
Note that if your logic is much more complicate than the above, you might be better served building your own descriptor type, rather than creating closures and passing them to the property
constructor as I've done above. A descriptor is simply a class with some of the __get__
, __set__
and/or __delete__
methods defined according to the descriptor protocol. Here's how you could implement the last version of PositiveValuedProperty
as a descriptor class rather than a factory function:
class PositiveValuedProperty():
def __init__(self, name):
self.name = "_" + name
def __get__(self, obj, cls=None):
return getattr(obj, self.name)
def __set__(self, obj, new_value):
if new_value < 1:
new_value = 1
setattr(obj, self.name, new_value)
As you can see, it's almost identical to the property
code, since property
is a descriptor that uses the functions you pass it to implement its __get__
and __set__
methods. You can however write more complicated descriptors. For instance, you could have your descriptor deduce its own name, if you wanted it to, by inspecting the attributes of type(obj)
(or the cls
parameter to __get__
) and looking for one that is equal to self
. That's a bit fragile though, since the descriptor could actually have multiple names (e.g. class Foo: x=MyDescritptor(); y=x
) and and searching through the class's variables is probably slow.
Related Topics
Pandas Groupby.Apply Method Duplicates First Group
Generating Permutations with Repetitions
Is It a Good Practice to Use Try-Except-Else in Python
How to Upgrade All Python Packages with Pip
Quoting Backslashes in Python String Literals
How to Calculate the Date Six Months from the Current Date Using the Datetime Python Module
"Fire and Forget" Python Async/Await
Why Is There No Tuple Comprehension in Python
How to Use Python to Login to a Webpage and Retrieve Cookies for Later Usage
Multiprocessing.Pool: When to Use Apply, Apply_Async or Map
How to Compare Version Numbers in Python
Python 3 Importerror: No Module Named 'Configparser'
Rotate Axis Text in Python Matplotlib
Directory-Tree Listing in Python
Python Pandas - Find Difference Between Two Data Frames
How to Get a String After a Specific Substring
How to Use a Python Script in the Command Line Without Cd-Ing to Its Directory? Is It the Pythonpath