Python abstractclass Inheritance - python

I have two class structured as below
from abc import ABCMeta, abstractmethod
class C(metaclass=ABCMeta):
""""""
def __init__(self, x, y):
self._x = x
self._y = y
#property
#abstractmethod
def x(self):
"""Get the _x"""
#x.setter
#abstractmethod
def x(self, value):
"""Set the x"""
#property
def y(self):
"""Get the _y"""
#y.setter
def y(self, value):
"""Set the _y"""
class D(C):
""""""
def __init__(self, x, y):
self._x = x
self._y = y
#property
def x(self):
return self._x
#C.x.setter
def x(self, value):
self._x = value
#property
def y(self):
return self._y
#C.y.setter
def y(self, value):
self._y = value
When I initialize an instance of D. It throws a error:
TypeError: Can't instantiate abstract class D with abstract methods x
When I rewrite setters decorator in D as
#x.setter
def x(self, value):
self._x = value
it works. But in python abc document https://docs.python.org/3/library/abc.html it states:
in disappreciated #abc.abstractproperty
If only some components are abstract, only those components need to be updated to create a concrete property in a subclass:
class D(C):
#C.x.setter
def x(self, val):
...
I don't know why write in this way will lead to error. Please help me understand the logic here. Thank you.

When you write #C.x.setter above your setter, you're setting x to a version of C.x with the setter replaced with your new setter function. Only the setter - the getter you wrote earlier is discarded. You're still using C.x's abstract getter.
The example in the docs uses #C.x.setter because they want the behavior it provides. In the doc example, C.x has a concrete getter, and they just want to replace the setter. That's not the case in your code.

Related

A simple class of Python can kill Spyder4.1.4 (Python3.8)

On the way learning Python, I have read some class examples and tried to practice. But how can this piece of code can kill Spyder4.1.4 (Python3.8) by just running?
p=Point(101,202,0)
Kernel died, restarting...
class Point():
id=0
def __init__(self, x, y, z:float=0):
self._x = x; self._y = y; self._z = z; self.id+=1
#property
def x(self):
return self._x
#x.setter# to define a "non-public member"
def x(self, value):
self._x=value
#property
def y(self):
return self._y
#y.setter
def y(self, value):
self._y=value
#property
def xy(self):
return [self._x,self._y]
#xy.setter
def xy(self,xval,yval):
self._x=xval;self._y=yval
#property
def z(self):
return self._z
#z.setter
def z(self, value):
self._z=value
#property
def id(self):
return self.id
I have tried Jupyter notebook or https://ideone.com/hjUDTU. But none is working. I am really lost...

call a setter from __init__ in Python

How can I call a Python (v2.7) setter property from inside __init__? I written the following class but I dont know how to change it to make it work. I get an AttributeError: 'test' object has no attribute '_x' exception. There are a few similar questions around here but couldnt find an answer so far. The idea is when the initialiser is called to do some processing/slicing and assign the result to an attribute
class test(object):
def __init__(self, a,b):
self._x = self.x(a,b)
#property
def x(self):
return self._x
#x.setter
def x(self, a, b):
self._x = "Get this from {} and make a dataframe like {}".format(a,b)
self.x is a property, so you'd just assign directly to it like you would with a regular attribute:
def __init__(self, a, b):
self.x = (a, b)
However, the setter is given one object, always; in the above case, it is passed a tuple; you could unpack it:
#x.setter
def x(self, value):
a, b = value
self._x = "Get this from {} and make a dataframe like {}".format(a,b)
Note the value argument; that's the result of the assignment being passed to the setter.
Demo:
>>> class test(object):
... def __init__(self, a, b):
... self.x = (a, b)
... #property
... def x(self):
... return self._x
... #x.setter
... def x(self, value):
... a, b = value
... self._x = "Get this from {} and make a dataframe like {}".format(a,b)
...
>>> t = test(42, 'foo')
>>> t.x
'Get this from 42 and make a dataframe like foo'

Setting Values Of Inherited Properties

I want to be able to create a concrete instance of a class that inherits from another concrete class, which in turn inherits from an abstract class.
The basic pattern is:
from abc import ABCMeta, abstractproperty
class Foo(object):
__metaclass__ = ABCMeta
#abstractproperty
def x(self):
pass
#abstractproperty
def y(self):
pass
class Bar(Foo):
x = None
y = None
def __init__(self, x, y):
self.x = x
self.y = y
#property
def x(self):
return self.x
#x.setter
def x(self, value):
self.x = value
#property
def y(self):
return self.y
#y.setter
def y(self, value):
self.y = value
class Baz(Bar):
def __init__(self):
super().__init__(x=2, y=6)
a = Baz()
When I try to create the instance of Baz I get a RecursionError: maximum recursion depth exceeded error. (As well as a pylint warning telling me that the signatures of the setter methods don't match the signatures of the base class)
However, if I remove the setters, I get an error self.x = x AttributeError: can't set attribute
What's the correct pattern to do this?
You need to change names for your x() / y() methods or for your x / y properties, for example rename
class Bar(Foo):
x = None
y = None
To:
class Bar(Foo):
x_val = None
y_val = None
And rename the references to x / y as well.
What you did is basically:
def x():
return x()
It happened because your def x overridden the x = None, so x is a function(property) that is calling itself. Avoid this by using another attribute(named differently) for storing the actual value of x.
Example from python docs (https://docs.python.org/3.5/library/functions.html#property):
class C:
def __init__(self):
self._x = None
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
Note: attribute names starting with underscore should be considered "private" and should not be directly accessed outside of the class. But it's only a convention for programmers, technically they are just normal attributes and you can do whatever you want, but it's nice to follow some convention, isn't it?

python abstract property setter with concrete getter

is it possible to use abc.abstractproperty to create a concrete getter but make the setter abstract so its different for each of the inheriting classes. I handle the setting of val different for each subclass.
eg.
#abstractproperty
def val(self):
return self._val
#val.setter
def val(self, x):
pass
You'll need a little bit of indirection. Define the setter as you normally would, but have it call an abstract method that does the actual work. Then each child class will need to provide a definition of that method. For example,
class Base(object):
__metaclass__ = abc.ABCMeta
def __init__(self):
self._val = 3
#property
def val(self):
return self._val
#val.setter
def val(self, x):
self._val_setter(x)
#abc.abstractmethod
def _val_setter(self, x):
pass
class Child(Base):
def _val_setter(self, x):
self._val = 2*x
Then
>>> c = Child()
>>> print c.val
3
>>> c.val = 9
>>> print c.val
18
How I ended up doing it.
class C(metaclass=ABCMeta):
#property
def x(self):
...
#x.setter
#abstractmethod
def x(self, val):
...
class D(C):
#C.x.setter
def x(self, val):
...

why my code run wrong ,it is about '#property'

I used python 2.5, I want to know how can change the next code when the Platform is python2.5 or python2.6
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
a=C()
print a.x#error
thanks
thanks ,alex,i think property must be 3 arguments in your example
but ,i have seen a code which with 'property' only use 1 argumennt ,why,can it work
class SortingMiddleware(object):
def process_request(self, request):
request.__class__.field = property(get_field)
request.__class__.direction = property(get_direction)
Python 2.5 does not support the .setter and .deleter sub-decorators of property; they were introduced in Python 2.6.
To work on both releases, you can, instead, code something like:
class C(object):
def __init__(self):
self._x = None
def _get_x(self):
"""I'm the 'x' property."""
return self._x
def _set_x(self, value):
self._x = value
def _del_x(self):
del self._x
x = property(_get_x, _set_x, _del_x)

Categories

Resources