I have a python class with "emulated" static properties via a metaclass:
class MyMeta(type):
#property
def x(self): return 'abc'
#property
def y(self): return 'xyz'
class My: __metaclass__ = MyMeta
Now some of my functions receives the property name as a string, which should be retrieved from My.
def property_value(name):
return My.???how to call property specified in name???
The point here is that I don't want an instance of My to be created.
Many thanks,
Ovanes
You could use
getattr(My,name)
I was looking at this recently. I wanted to be able to write Test.Fu where Fu is a computed property.
The following works using a descriptor object:
class DeclareStaticProperty(object):
def __init__(self, method):
self.method = method
def __get__(self, instance, owner):
return self.method(owner())
class Test(object):
def GetFu(self):
return 42
Fu = DeclareStaticProperty(GetFu)
print Test.Fu # outputs 42
Note that there is an instance of Test allocated behind the scenes.
Related
How to return a list from the class level using properties? When call instance a class it's all ok, but when it calls the attribute class, it gets the property object
below sample code:
class zoo:
__count_animals=0
__listAnimals=[]
def __init__(self,typee,name,age):
self.typee=typee
self.name=name
self.age=age
self.__listAnimals.append(self)
zoo.__count_animals+=1
#property
def count_animals(self):
return self.__count_animals
#count_animals.setter
def count_animals(self,newvalue):
newvalue=zoo.__ilosc_zwierzat
self.__count_animals=newvalue
#property
def listAnimals(self):
return self.__listAnimals
#listAnimals.setter
def listAnimals(self,newobj):
newobj=zoo.__listAnimals
self.__listAnimals=newobj
zw1=zoo("Tiger","NoName",23)
print(zw1.listAnimals) # result it's ok ->[<__main__.zoo object at 0x006A23D0>, <__main__.zoo object at 0x006A2410>]
but
print(zoo.listAnimals) # result <property object at 0x002A1DB0>
This works as expected. Because you are calling the property object on class instead on instance. Class does not hold the same data as class instances.
The way you expect it to happen is that __count_animals and __listAnimals are class properties instead of instance properties.
So I slightly modified your code to work with classproperties instead of instance properties.
Above I define classproperty decorator:
class classproperty(object):
def __init__(self, f):
self.f = f
def __get__(self, obj, owner):
return self.f(owner)
Then your class zoo
class zoo:
__count_animals=0
__listAnimals=[]
def __init__(self,typee,name,age):
self.typee=typee
self.name=name
self.age=age
zoo.__listAnimals.append(self)
zoo.__count_animals+=1
#classproperty
def count_animals(self):
return self.__count_animals
#classproperty
def listAnimals(cls):
return cls.__listAnimals
zw1=zoo("Tiger","NoName",23)
print(zoo.listAnimals) # result [<__main__.zoo object at 0x10699c410>]
Works like a charm!
You are calling the class property, you need first to instance that class in to an object and then get the property of the object.
I'm trying to add extra decorator for magic method (__get__) in descriptor class.
I'm able to do it when I use #property but not when I use descriptor class.
I check range because my object set registers on the bus and some registers can take only specific range of values:
import functools
def check_range(min, max):
def decorator(f):
#functools.wraps(f)
def wrap(self, value):
if value not in range(min, max+1):
return
return f(self, value)
return wrap
return decorator
This works:
class Foo:
def __init__(self):
self.device.init_smth('my_object')
#property
def my_object(self):
return self.device.get_value('my_object')
#my_object.setter
#check_range(0,1)
def my_object(self, value):
self.device.set_value('my_object', value)
a = Foo()
print(a.my_object)
a.my_object = 1
print(a.my_object)
a.myobject = -1
And in this example everything works the same but check_range is not invoked:
class Register:
def __init__(self, name, device):
self.name = name
device.init_smth(name)
def __get__(self, instance, owner):
return instance.device.get_value(self.name)
#check_range(0,1)
def __set__(self, instance, value):
instance.device.set_value(self.name, value)
class Foo:
def __init__(self):
self.my_object = Register('my_object', self.device)
a = Foo()
print(a.my_object)
a.my_object = 1
print(a.my_object)
a.myobject = -1
I may be wrong, but most probably your descriptor not invoked at all, decorator is not the problem. Descriptors meant to be used like
class Foo2:
my_object = Register('my_object', 'init_value')
— you're defining it like class attribute. And python will execute all machinery with __get__/__set__/__del__ if your class attribute supports it (i.e. it is descriptor).
This is why there is an "instance" argument in descriptor methods — you're defining descriptor as class variable, but i.e. __set__ method will receive actual instance of your class, so you can manage per-instance data, like your device
Lets say I have this class:
class Test(object):
def __init__(self, a):
self.a = a
def test(self, b):
if isinstance(self, Test):
return self.a + b
else:
return self + b
This would ideally in my world do this:
>>> Test.test(1,2)
3
>>> Test(1).test(2)
3
Now this doesn't work because you get this error:
TypeError: unbound method test() must be called with Test instance as first argument (got int instance instead)
In python3 this works fine, and I have the sneaking suspicion this is possible with a decorator in python2 but my python foo isn't strong enough to get that to work.
Plot Twist: So what happens when I need something on self when it's not called statically.
If you want something that will actually receive self if called on an instance, but can also be called on the class, writing your own descriptor type may be advisable:
import types
class ClassOrInstanceMethod(object):
def __init__(self, wrapped):
self.wrapped = wrapped
def __get__(self, instance, owner):
if instance is None:
instance = owner
return self.wrapped.__get__(instance, owner)
class demo(object):
#ClassOrInstanceMethod
def foo(self):
# self will be the class if this is called on the class
print(self)
Demo.
For the original version of your question, you could just write it like any other static method, with #staticmethod. Calling a static method on an instance works the same as calling it on the class:
class Test(object):
#staticmethod
def test(a, b):
return a + b
Demo.
I want to create property method dynamically.
It means, for example, i want first class A to be equivalent with second one.
Is there any way?
class A(object):
def __init__(self):
self._a = 10
self.createPropertyMethod(a, self._a, getFunc, setFunc, delFunc)
def createPropertyMethod(self, name, value, getFunc, setFunc, delFunc)
#TODO
.
class A(object):
def __init__(self):
self._a = 10
#property
def a(self):
return getFunc(self._a)
#a.setter
def a(self, value):
setFunc(self._a, value)
#a.deleter
def a(self):
delFunc(self._a)
You can't, not on instances. The property object needs to be part of the class for the descriptor protocol on which it relies to work.
You can use the __getattr__, __setattr__ and __delattr__ hooks instead to proxy attribute access dynamically.
How to save code duplication in the following scenario ?
say Aand B are two classes having a common function(say) name
class A(object):
name = 'foo'
#property
def name(self): # the common function
return self.name
similarly B
class B(object):
name = 'bar'
#property
def name(self):
return self.name
One way would be to make a class from which both of them inherit from, and define name there.
Any good alternatives ?
If you're really determined to avoid inheritance, just define a function outside of either class:
def get_name(object):
return object.name
class A(object):
name = 'foo'
def get_name(self): # the common function
return self.name
class B(A):
pass
In this case B would inherit from A
Is there a reason you can't have B inherit from A?
class B(A):
name = 'bar'
Since you are decorating name with #property, I am assuming you want this to be an instance variable. If you want this to return a more private variable, let's call it _name, you have to do:
class A(object):
def __init__(self):
self._name = 'foo'
#property
def name(self):
return self._name
You can't have both a variable and a function have the same name, since the latter will simply override the former. If you want a base class that takes care of this, it would look like this:
class HasName(object):
def __init__(self, name):
self._name = name
#property
def name(self):
return self._name
class A(HasName):
def __init__(self):
self._name = 'foo'
class B(HasName):
def __init__(self):
self._name = 'bar'
You can also call the constructor in HasName.
Assuming self.name stands in for a more complex method, the easiest way to cut down on duplicated code is to move the function out to the module and have it take an arbitrary object as a parameter. Then, if you still want to tie the method directly to the class, you can add a short method that dispatches to the module function.
def _name(obj):
return obj.name
class A(object):
# ...
#property
def name(self):
return _name(self)
class B(object):
# ...
#property
def name(self):
return _name(self)
Note that this will not work well if A.name and B.name have completely different behaviors. If the _name function starts checking the type of the object given, reconsider whether you really want to abstract that functionality in the first place.