Is it possible to override a property in a base class by a regular attribute in a derived class, something like this:
class A(object):
#property
def x(self):
return self._x
#x.setter
def x(self, y):
self._x = y
class B(A):
def __init__(self, y):
self.x = y #the descriptor methods are not called and
#"x" is a regular attribute in the object dict.
The reason I am asking is because I have a complex base class in which one of the descriptor attributes typically performs a complicated calculation. However, in one of the derived classes, the returned value is trivial and it seems like a waste to have to override with another descriptor and not just a regular storage attribute.
You can simply redeclare x in B:
class A(object):
#property
def x(self):
print("calculating x...")
return self._x
#x.setter
def x(self, y):
print('setting x...')
self._x = 10*y
class B(A):
x = None
def __init__(self, y):
self.x = y #the descriptor methods are not called and
#"x" is a regular attribute in the object dict.
b = B(3)
print(b.x)
# 3
Related
Was wondering if there was a way to set a class attribute to a specific instance from within the class definition. For example,
class Value:
def __init__(self, x):
self.x = x
# Something like
# half = Value(0.5)
>>> Value.half.x
0.5
>>> Value.half.half.x
0.5
I'm also aware I can easily set it outside the class that seems a bit more bulky and error prone, like this
class Value:
def __init__(self, x):
self.x = x
Value.half = Value(0.5)
>>> Value.half.x
0.5
>>> Value.half.half.x
0.5
No. At the time the body of the class is being evaluated, the class doesn't yet exist. A class statement is a declarative syntax for calling a metaclass:
class Value:
def __init__(self, x):
self.x = x
is roughly equivalent to
def init(self, x):
self.x = x
Value = type('Value', (object,), {'__init__': init})
Your class attribute would have to be a member of the dict passed as the third argument, which has to be fully defined before type is called.
not quite, but you can make a class method that return a new instance of your class in whatever way you want with the classmethod decorator
>>> class Value:
def __init__(self, x):
self.x=x
def __repr__(self):
return f"{type(self).__name__}({self.x})"
#classmethod
def half(cls):
return cls(0.5)
>>> Value(10)
Value(10)
>>> Value.half()
Value(0.5)
>>>
look like in py3.9 you can combine it with the property decorator to accomplish just that, see linked documentation above (but I don't have it at the moment)
Simply, you can't because the class hasn't yet existed. But you can use either metaclass or class decorator to achieve the same goal as the following shows:
#Metaclass
class Meta(type):
def __init__(cls, clsname, clsbases, clsdict):
cls.half = cls(0.5)
class Value(metaclass=Meta):
def __init__(self, x):
self.x = x
#Decorator
def decorator(cls):
cls.half = cls(0.5)
return cls
#decorator
class Value2:
def __init__(self, x):
self.x = x
print(Value.half.half.x)
print(Value.half.x)
print(Value2.half.half.x)
print(Value2.half.x)
Here is the format of my code:
class A(object):
def __init__(self, x, other):
self.other = other
self.x = x
class B(A):
def __init__(self):
# place code here
def something_else(self):
return self.x["foo"]
x is an object which I would like to call, with a subscript later on (in something_else.
I would like only x to be inherited from the parent class.
It is important that other is not inherited, so super().__init__ is not suitable.
I have attempted a workaround by creating a function within class A:
def x(self):
return self.x
so I could call super().x() in class B, but this doesn't work either.
I have attempted calling directly super.x["foo"], and this doesn't work.
How can I achieve what I want in my case?
Thanks!
Variables don't always have to be registered in the __init__ function, if you want x from class A, have a method in A:
def set_x(self, x):
self.x = x
# other stuff
you'll still be able to call set_x from class B as all functions are inherited, from there you can instantiate property x without calling __init__ from A.
This question already has answers here:
Python class #property: use setter but evade getter?
(4 answers)
Closed 4 years ago.
class My_Class:
def __init__(self):
self._x = 0
#property
def x(self):
return self._x
#x.setter
def x(self, x):
self._x = x
If I delete the following getter from the code above:
#property
def x(self):
return self._x
The code stops working. How can I create a setter without a getter?
The property function does not have to be used as a decorator:decorator can be used as a function:
class My_Class:
def _set_x(self, value):
self._x = value
x = property(fset=_set_x) # now value has only a setter
del _set_x # optional: delete the unneeded setter function
instance = My_Class()
instance.x= 8 # the setter works
print(instance._x) # the "private" value
print(instance.x) # raises: AttributeError: unreadable attribute
class My_Class:
def __init__(self):
self._x = 0
#property
def x(self):
raise RuntimeError('This property has no getter!')
#x.setter
def x(self, x):
self._x = x
Here's an alternative answer to what I already offered: make your own write-only descriptor.
class WriteOnly:
def __init__(self, private_name):
self.private_name = private_name
def __set__(self, obj, value):
obj.__dict__[self.private_name] = value
def __get__(self, obj, type=None):
raise AttributeError('unreadable attribute')
class My_Class:
x = WriteOnly('_x')
instance = My_Class()
instance.x = 8 # the setter works
print(instance._x) # the "private" value
print(instance.x) # raises: AttributeError: unreadable attribute
This question already has answers here:
Understanding __get__ and __set__ and Python descriptors
(8 answers)
Closed 8 years ago.
Is there a function such that i can write but as a function?
class foo:
def __init__(self,x):
self.x = x;
asd = foo(2);
asd.x = 5;
print(asd.x);
But like:
class foo:
def __init__(self,x):
self.x = x;
def someFunction(self,string,value):
if(string == 'x'):
self.x = value;
print("worked");
asd = foo(2);
asd.x = 3; #and "worked" will be printed?
I tried __ set __ and __ setattr __ but i had no luck ;\
Is there a way to call a function when setting a class variable?
asd.x = 3; calls a function?
Use a property. The method decorated by #property will be used whenever you try to access the attribute x; the method subsequently decorated by #x.setter will be called whenever you try to set the value of x. The underlying "private" attribute _x is used to store the value for x used by both the getter and setter.
class foo:
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
print("worked")
def __init__(self, x):
self._x = x
The decorator syntax can be skipped if you want more explicit names for the getter and setter methods:
class foo(object):
def __init__(self, x):
self._x = x
def _get_x(self):
return self._x
def _set_x(self, value):
self._x = value
print("worked")
x = property(_get_x, _set_x)
For an object to handle setting of attributes on itself, use the __setattr__ method. It's rather tricky to debug, so don't do this unless you know what you're doing. Good explanation
source
class Beer(object):
def __init__(self, adj):
self.adj = adj
def __setattr__(self, key, value):
print '\tSET',key,value
object.__setattr__(self, key, value) # new style (don't use __dict__)
b = Beer('tasty')
print 'BEFORE',b.adj
b.adj = 'warm'
print 'AFTER',b.adj
print b.__dict__
output
SET adj tasty
BEFORE tasty
SET adj warm
AFTER warm
{'adj': 'warm'}
In C-ish languages, I'd mask data storage details with getter/setter methods/functions like:
int getFoo();
void setFoo(int value);
I have some Python that does:
class MyClass:
def Foo(self):
...magic to access foo...
return value
What's the right way to write/name a setter for Foo? I'm sure it's more idiom than language feature but I'm not sure what's common. Maybe I need to rename Foo() to getFoo() and match it with setFoo(). I guess that's OK if that's what is usually done.
You can use a property. This is pulled directly from the docs:
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
"""I'm the 'x' property."""
return self._x
#x.setter
def x(self, value):
self._x = value
#x.deleter
def x(self):
del self._x
Now you can do...
c = C()
c.x = "a"
print c.x
>>> "a"
del c.x
Keep in mind that in Python versions prior to Python 3 (e.g., Python 2.7) you need to make sure that your object is a new-style class (it must derive from object) for it to support properties like this. Granted, you probably should be using new-style classes for all your classes anyway...
Use the builtin property function:
class MyClass:
def __init__(self):
self._value = 'Initialize self._value with some value or None'
def get_foo(self):
...magic to access foo...
return self._value
def set_foo(self, value):
... magic processing for value ...
self._value = value
foo = property(get_foo, set_foo)
Now you can use access it like this:
inst = MyClass()
inst.foo = 'Some value'
print inst.foo
It will print:
'Some value'
Generally you don't need to use getters and setters in Python.
If however, you want to expose the result of a procedure as a property, you can use the #property decorator:
class MyClass:
#property
def foo(self):
# operation
return value
#foo.setter
def foo(self, value):
# operation storing value
It is more common to just store the value of foo in an attribute. This can be calculated in the __init__ instance initializer:
class MyClass:
def __init__(self):
self.foo = someCalculationDeterminingFoo()