How to Make a Class Property

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 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.

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



Leave a reply



Submit