Wilgens Metelus
Wilgens Metelus

Reputation: 25

Private attributes and setting limits

so for my code, the code should print out two statements, calculating the vectors individually and writing both down. Using my code as an example, the program should print out

Vector: x=4, y=4
Vector: x=3, y=7 

However, I am having trouble with creating the class using private attributes, and making a limit of x must be greater than 3 and y cannot be greater than seven. Is the double underscore correct in making it private?

class Vector:
    def __init__(self):
        self.__x = 4
        self.__y =4


v1=Vector(4,4)
print(v1)
v2=Vector(v1.get_x()/2,v1.get_y()*2)
print(v2)

Upvotes: 1

Views: 172

Answers (3)

Josh Karpel
Josh Karpel

Reputation: 2145

The idiomatic way to do this in Python is something like this:

class Vector:
    def __init__(self, x, y):
        self._x = x
        self._y = y

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        if value < 3:
            raise ValueError('x must be greater than 3')

        self._x = value

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, value):
        if value > 7:
            raise ValueError('y must be less than 7')

        self._y = value

    def __repr__(self):
        return f'Vector(x = {self.x}, y = {self.y})'

v1 = Vector(4, 4)
print(v1)
v2 = Vector(v1.x / 2, v1.y * 2)
print(v2)

Notes on your original code:

  • A single underscore is the typical mark for a "private" variable. Python does not truly have private variables, so this is purely a convention. Anyone who reads the source code will know that they can access the underlying value of x like v1._x. Double-underscores does have a meaning, but it's for a different purpose. See https://docs.python.org/3/tutorial/classes.html#private-variables for more details.
  • It is not idiomatic to write get_foo methods. Instead, you should use the @property decorator (see https://docs.python.org/3/library/functions.html?highlight=property#property). @property lets you customize "attribute access".
  • You need to pass some inputs into your __init__.
  • You print(v1), but since you didn't define __str__ or __repr__, this would just print something like <__main__.Vector object at 0x0000019CA15D36A0>, which isn't very useful.

Upvotes: 2

yaho cho
yaho cho

Reputation: 1779

You need to make get and set method in Vector class.

class Vector:
    def __init__(self, x, y):
        self.__set_x(x)
        self.__set_y(y)

    def __str__ (self):
        return 'vector : '+str(self.__x)+' '+str(self.__y)

    def __set_x(self, x):
        if x < 3: x = 3
        self.__x = x

    def __set_y(self, y):
        if y >= 7: y = 7
        self.__y = y

    def get_x(self):
        return self.__x

    def get_y(self):
        return self.__y


v1=Vector(4,4)
print(v1)
v2=Vector(v1.get_x()/2,v1.get_y()*2)
print(v2)

I added some methods to complete implementation.

  1. __str__ returns string object to be displayed class as the string by print(v1) what you coded.
  2. get_x and get_y return private attribute value when you run v1.get_x() and v1.get_y().
  3. And, Finally, I made __set_x(x) and __set_y(y) as private to be initialized in constructor only.

Upvotes: 1

Deepstop
Deepstop

Reputation: 3807

Regarding the double-underscore. It seems that it works to make it private. I tried it as a test. Maybe it was an update in some newer version of Python than the one I originally studied.

class test_priv():
    def __init__(self, x, y):
        self.__x = x
        self.__y = y

    def showvars(self):
        print(self.__x, self.__y)

p = test_priv(1,2)

p.showvars()
print(p.__x)


$ python test.py
1 2
Traceback (most recent call last):
  File "acid.py", line 12, in <module>
    print(p.__x)
AttributeError: 'test_priv' object has no attribute '__x'

Upvotes: 0

Related Questions