Python static setters and getters?
Question:
I have put a Jira client for my django application together and now need to make it static but I can’t figure how to convert @property
and @?.setter
into static fields:
Say I have a class:
class nothing(object):
auth_token = None
counter = 0
@property
def a(self):
self.log('getter')
if not self.auth_token:
self.auth_token = 'default'
return self.auth_token
@a.setter
def a(self, value):
self.log('setter')
self.auth_token = value
def log(self, value):
self.counter+=1
print '{0} called / counter: {1}'.format(value, self.counter)
and I want its methods to be static:
class nothing:
auth_token = None
counter = 0
@staticmethod
def get_a():
nothing.log('getter')
if not nothing.auth_token:
nothing.log('auth_token value is None, setting')
nothing.auth_token = 'default'
return nothing.auth_token
@staticmethod
def set_a(value):
nothing.log('setter')
nothing.auth_token = value
@staticmethod
def log(value):
nothing.counter+=1
print '{0} called / counter: {1}'.format(value, nothing.counter)
can’t mark get_a
as @property
now as calling it will return an object and not actually call get_a
. Methods are something I can live with but is there a way to have getters/setters instead?
Answers:
The easiest way is to make this class singleton. Instead of making methods static, override class with its instance:
nothing = nothing()
You can also use metaclasses if you want to have more than one instance.
You need a class property in python?
here is a solution for the getter. For the setter an other metaclass than type is required.
>>> class CP(object):
def __init__(self, getter, setter = None):
self._getter = getter
self._setter = setter
def setter(self, setter):
self._setter = setter
def __get__(self, obj, cls = None):
print '__get__', obj, cls
return self._getter(cls) # for static remove cls from the call
def __set__(self, *args):
print args
>>> class X(object):
@CP
def g(cls):
print 'g', cls
return 1
>>> X.g # getting returns value of g
__get__ None <class '__main__.X'>
g <class '__main__.X'>
1
>>> X().g
__get__ <__main__.X object at 0x02ACEC50> <class '__main__.X'>
g <class '__main__.X'>
1
>>> X.g = 3 # setting does not work
>>> X.g
3
But when I have a look at:
>>> X().g = 3
(<__main__.X object at 0x02ACEE50>, 3)
It seems not intended for properties to __set__
on class side. This is wise because: how else would you even be able to overwrite for example a property
on class side if __set__
was called?
The following is an example of using metaclasses. This example implements a naming convention where class ISomeClass
is what we have dubbed an ‘abstract interface’, and class Igloo
and class Panda
are not:
class MyObjectsInterfaceNamingMetaclass(type):
@property
def isAbstract(cls):
'''requires class name >1 chars'''
return cls.__name__.startswith('I') and cls.__name__[1].isupper()
in use:
class IBlueprinted(metaclass=MyObjectsInterfaceNamingMetaclass):
pass
class FabricBlueprint(IBlueprinted):
pass
class IToyBlueprint(IBlueprinted):
pass
class RedToyBlueprint(IToyBlueprint):
pass
demo:
print(IBlueprinted.isAbstract) #True
print(FabricBlueprint.isAbstract) #False
print(IToyBlueprint.isAbstract) #True
print(RedToyBlueprint.isAbstract) #False
I have put a Jira client for my django application together and now need to make it static but I can’t figure how to convert @property
and @?.setter
into static fields:
Say I have a class:
class nothing(object):
auth_token = None
counter = 0
@property
def a(self):
self.log('getter')
if not self.auth_token:
self.auth_token = 'default'
return self.auth_token
@a.setter
def a(self, value):
self.log('setter')
self.auth_token = value
def log(self, value):
self.counter+=1
print '{0} called / counter: {1}'.format(value, self.counter)
and I want its methods to be static:
class nothing:
auth_token = None
counter = 0
@staticmethod
def get_a():
nothing.log('getter')
if not nothing.auth_token:
nothing.log('auth_token value is None, setting')
nothing.auth_token = 'default'
return nothing.auth_token
@staticmethod
def set_a(value):
nothing.log('setter')
nothing.auth_token = value
@staticmethod
def log(value):
nothing.counter+=1
print '{0} called / counter: {1}'.format(value, nothing.counter)
can’t mark get_a
as @property
now as calling it will return an object and not actually call get_a
. Methods are something I can live with but is there a way to have getters/setters instead?
The easiest way is to make this class singleton. Instead of making methods static, override class with its instance:
nothing = nothing()
You can also use metaclasses if you want to have more than one instance.
You need a class property in python?
here is a solution for the getter. For the setter an other metaclass than type is required.
>>> class CP(object):
def __init__(self, getter, setter = None):
self._getter = getter
self._setter = setter
def setter(self, setter):
self._setter = setter
def __get__(self, obj, cls = None):
print '__get__', obj, cls
return self._getter(cls) # for static remove cls from the call
def __set__(self, *args):
print args
>>> class X(object):
@CP
def g(cls):
print 'g', cls
return 1
>>> X.g # getting returns value of g
__get__ None <class '__main__.X'>
g <class '__main__.X'>
1
>>> X().g
__get__ <__main__.X object at 0x02ACEC50> <class '__main__.X'>
g <class '__main__.X'>
1
>>> X.g = 3 # setting does not work
>>> X.g
3
But when I have a look at:
>>> X().g = 3
(<__main__.X object at 0x02ACEE50>, 3)
It seems not intended for properties to __set__
on class side. This is wise because: how else would you even be able to overwrite for example a property
on class side if __set__
was called?
The following is an example of using metaclasses. This example implements a naming convention where class ISomeClass
is what we have dubbed an ‘abstract interface’, and class Igloo
and class Panda
are not:
class MyObjectsInterfaceNamingMetaclass(type):
@property
def isAbstract(cls):
'''requires class name >1 chars'''
return cls.__name__.startswith('I') and cls.__name__[1].isupper()
in use:
class IBlueprinted(metaclass=MyObjectsInterfaceNamingMetaclass):
pass
class FabricBlueprint(IBlueprinted):
pass
class IToyBlueprint(IBlueprinted):
pass
class RedToyBlueprint(IToyBlueprint):
pass
demo:
print(IBlueprinted.isAbstract) #True
print(FabricBlueprint.isAbstract) #False
print(IToyBlueprint.isAbstract) #True
print(RedToyBlueprint.isAbstract) #False