How to define attribution of attribution in python - python

I am trying to make an attribution of an attribution in python.
Is there a way to do so:
class Foo():
def __init__(self, x, y):
self.x = x
self.x.y = y
I have no idea how to do it, I checked for some examples. But I have not found any example similar.

Not exactly clear what you need you can do something like this (for example):
class Bar(object):
def __init__(self, y=None):
self.y = y
class Foo(object):
def __init__(self, x, y):
self.x = x
self.x.y = y
if __name__ == '__main__':
x = Bar()
y = 1
foo = Foo(x,y)

Related

Pytest fails with AttributeError: 'str' object has no attribute 'x'

I am having trouble getting a test to pass. When I run the code it seems to work find, but in pytest it fails:
desk.py
class Dimension:
x = 0
y = 0
z = 0
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
class Desk:
def __init__(self, dimension):
self.dimension = dimension
#property
def dimension(self):
return self.__dimension
#dimension.setter
def dimension(self, d):
s = d.split(".")
self.__dimension = Dimension(int(s[0]), int(s[1]), int(s[2]))
#property
def is_large(self):
if self.dimension.x > 100:
return True
return False
test_desk.py
...
def test_is_large():
desk = Desk("5.5.5")
assert desk.is_large == False
...
I get AttributeError: 'str' object has no attribute 'x'
If I change to getter and setter methods it works find, but I would like to use decorators.
UPDATE:
I used python3 -m pytest to run pytest using python3 and it works fine
It's the double underscore of self.__dimension. Read this: What is the difference in python attributes with underscore in front and back
And this: How to access "__" (double underscore) variables in methods added to a class
Change self.__dimension to self._dimension and it will make.
EDIT: Not the underscore. Your code works perfectly in Python3. In Python2 I made it work this way:
class Dimension:
x = 0
y = 0
z = 0
def __init__(self, x, y, z):
self.x = 0
self.y = 0
self.z = 0
class Desk:
def __init__(self, dimension):
s = dimension.split(".")
self.__dimension = Dimension(int(s[0]), int(s[1]), int(s[2]))
#property
def dimension(self):
return self.__dimension
#dimension.setter
def dimension(self, d):
s = d.split(".")
self.__dimension = Dimension(int(s[0]), int(s[1]), int(s[2]))
#property
def is_large(self):
if self.dimension.x > 100:
return True
return False

Access the private attributes in a inherited class in python

I have a class a defined like this:
class a:
def __init__(self, w, x, y, z):
self.w = w
self.x = x
self.y = y
self.__z = z
I also have another class b which inherits a defined like this:
class b(a):
def __init__(self, w, x, y, z, t):
super().__init__(w, x, y, z)
self.__t = t
Now if I had access w, x, y from within b, I could simply do:
self.w
self.x
self.y
But I can't do self.z or self.__z to access z. So my question is how can you access dunder values such as z from within class b
(I know python doesn't really have private variables and I could do self._a__z from within class b to access z but I'm looking for methods which would allow me to just do something like self.z to access z from inside b)
There are a variety of ways you could solve the problem by changing the API of class a to expose it's __z attribute in some more inheritance-friendly way. For instance, you could make the actual mangled attribute name an implementation detail and have the public API be a property:
class a:
def __init__(self, w, x, y, z):
self.w = w
self.x = x
self.y = y
self.__z = z
#property
def z(self):
return self.__z
#z.setter
def z(self, value):
self.__z = value
But unless you're doing some validation or modification of the value somewhere in the property's code, you probably should just do away with the double-underscores and let the child class access self.z like it can w, x and y. The simplest solution is to replace self.__z = z with self.z = z. You can always change it later to use a property if you find you do need validation or something.
If you just want to hint that z is not part of the wider public API, but only for subclasses and other code that knows about the intimate details of a's design, consider using a single underscore: self._z = z. This has no special effects in the interpreter, but the single-underscore serves as a sort of documentation that _z is an internal attribute and you should only mess with it if you know what you're doing.
You could do something like this if you want to keep your code clean:
class a:
def __init__(self, w, x, y, z):
self.w = w
self.x = x
self.y = y
self.__z = z
def get_field(self):
return self.__z
class b(a):
def __init__(self, w, x, y, z, t):
super().__init__(w, x, y, z)
self.__t = t
def ChildMethodWhichUsingParentField(self):
return self.get_field()
c = b(1,2,3,4,5)
print(c.ChildMethodWhichUsingParentField())
Output
4
Similarly, you can use a setter to change its value:
class a:
def __init__(self, w, x, y, z):
self.w = w
self.x = x
self.y = y
self.__z = z
def get_field(self):
return self.__z
def set_field(self,z):
self.__z = z
class b(a):
def __init__(self, w, x, y, z, t):
super().__init__(w, x, y, z)
self.__t = t
def ChildMethodWhichUsingParentField(self):
return self.get_field()
def ChildMethodWhichSettingParentField(self,z):
self.set_field(z)
c = b(1,2,3,4,5)
print(c.ChildMethodWhichUsingParentField())
c.ChildMethodWhichSettingParentField(10)
print(c.ChildMethodWhichUsingParentField())
Output
4
10

Pass arbitrary number of variables through multiple functions/classes/methods

I have a class with methods that looks something like this
class A(object):
def __init__(self, strat):
self.strat_cls = strat
self._genInstances()
def _genInstances(self):
self.strat = self.strat_cls(self.x, self.y)
and the strat_cls:
class strat1(Strat):
def __init__(self, x=4):
self.x = x
def calculate_something(self, event):
if x > 2:
print("hello")
I initialize everything by:
example = A(strat1)
When initializing I need to be able to pass an arbitrary number of arguments to the calculate_something method in the strat1 class like this:
example = A(strat1, x=3)
or
example = A(strat1, x=3, y=5)
where y will then be used further down in the calculate_something method.
How do I do that? I need to be able to pass both "new variables" and overriding the x variable. I've tried several times using *args and **kwargs, but I end up with errors.
Here is your code with comments. The main point is you have to save the arguments in A and pass them to strat when you're initializing it.
class A(object):
def __init__(self, strat, **strat_kwargs):
self.strat_cls = strat
# save kwargs to pass to strat
self.strat_kwargs = strat_kwargs
self._genInstances()
def _genInstances(self):
# init strat with kwargs
self.strat = self.strat_cls(**self.strat_kwargs)
class strat1(Strat):
def __init__(self, x=4, y=None):
# save x and y
self.x = x
self.y = y
def calculate_something(self, event):
# use self.x here
if self.x > 2:
print("hello")

In the main function, how to print the value (x,y) from the def __str__?

for example
def __str__ (self):
return (x,y)
def main():
how do u print the value of x and y from the def str(self): function
Would really appreciate it thanks!!!
That code doesn't make sense, so I'm extrapolating.
I'm assuming you have some class like so:
class Foobar(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return str((x,y))
def main():
foobar = Foobar(1,2)
main()
In this case, you COULD use string manipulation to handle it.
x_value, y_value = map(str.strip("()"), str(foobar).split(','))
But that's uglier than sin. Why not just reference the values directly?
x_value, y_value = foobar.x, foobar.y
Using the example in Adam's answer:
class Foobar(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return '({foo.x}, {foo.y})'.format(foo=self)
Would result in:
foo = Foobar(2, 3)
print(foo)
'(2, 3)'

Is it possible to instantiate an object of one class in two different ways?

Here is an example which creates a point as p=Point(x, y). Assume that I have some array ppp=(x, y) where x and y are numbers and I want to make it of class Point but in the way: p=Point(ppp). I can do either one or another way but not both simultaneously. Is it possible to have both ways?
There are two different ways to acquire the result, the first is to analyse arguments that you pass to __init__ and in dependence of their quantity and type - choose a decision what are you using to instantiate class.
class Point(object):
x = 0
y = 0
def __init__(self, x, y=None):
if y is None:
self.x, self.y = x, x
else:
self.x, self.y = x, y
The other decision is to use classmethods as instantiators:
class Point(object):
x = 0
y = 0
#classmethod
def from_coords(cls, x, y):
inst = cls()
inst.x = x
inst.y = y
return inst
#classmethod
def from_string(cls, x):
inst = cls()
inst.x, inst.y = x, x
return inst
p1 = Point.from_string('1.2 4.6')
p2 = Point.from_coords(1.2, 4.6)
If you know that you have a tuple/list while creating the instance, you can do: p = Point(*ppp), where ppp is the tuple.
class Point:
def __init__(self, x, y=None):
if isinstance(x, tuple):
self.x, self.y = x
else:
self.x = x
self.y = y
Yes:
class Point(object):
def __init__(self, x, y=None):
if y is not None:
self.x, self.y = x, y
else:
self.x, self.y = x
def __str__(self):
return "{}, {}".format(self.x, self.y)
print Point(1,2)
# 1, 2
print Point((1,2))
# 1, 2
I would guess that your looking for a way to overload your constructor, as is common in statically typed languages such as C++ and Java.
This is not possible in Python. What you can do is provide different keyword argument combinations, something like:
class Point(object):
def __init__(self, x=None, y=None, r=None, t=None):
if x is not None and y is not None:
self.x = x
self.y = y
elif r is not None and t is not None:
# set cartesian coordinates from polar ones
Which you would then use as:
p1 = Point(x=1, y=2)
p2 = Point(r=1, t=3.14)

Categories