Private attributes and setting limits - python

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)

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.

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.
__str__ returns string object to be displayed class as the
string by print(v1) what you coded.
get_x and get_y return private attribute value when you run
v1.get_x() and v1.get_y().
And, Finally, I made __set_x(x) and __set_y(y) as private to
be initialized in constructor only.

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'

Related

class Foo(), get remainder, after division input by 100

what's best way to make the class Foo():
>>> p=Foo()
>>> print (p.x) => p.x = 0
>>> p.x = 125
>>> print (p.x) => p.x = 25 (tens of 125)
You can use getters and setters. Depending on whether you want to store the remainder or the unmodified value in the instance, place the logic to calculate the remainder in either the setter or getter, respectively.
class Foo:
def __init__(self):
self._x = 0
#property
def x(self):
return self._x
#x.setter
def x(self, x):
self._x = x % 100
(As a side note, defaulting to using getters and setters (as is common in some other languages) is considered unpythonic. Here they (or some variation of it) are needed to alter the value set or retrieved according to your rule/requirement.)

The pythonic way to construct a multimethod setter

We can use a #property to construct a getter and setter. This is a short example how we can do this:
class A:
def __init__(self,x):
self.x = x
#property
def x(self):
return self.__x
#x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 100:
self.__x = 100
else:
self.__x = x
My case seems to be more complicated.
class A:
def __init__(self, x):
self.__x = x
self.x1()
self.x2()
self.x3()
def x1(self):
self.__x1 = self.__x + 1
return self.__x1
def x2(self):
self.__x2 = self.__x1 + 2
return self.__x2
def x3(self):
self.__x3 = self.__x2 + 3
return self.__x3
if __name__ == "__main__":
a = A(3)
print(a.x3)
Methods x1, x2 and x3 are oversimplified. The self.__x3 variable is set only once, when the __init__ method is called. Now, I need a getter method to get self.__x3 by calling a.x3. How to achieve that in the pythonic way?
Attempting an answer based on the assumption that you want the __x# variables modified only during __init__, and never again, but also want the accessors to follow the same code path (possibly because the read is also programmatically complex):
In this case, you can have the implementing function take an additional, defaulted argument. When accessed in attribute form, it will receive the defaulted argument, but if the fget member of the property is explicitly accessed, it can be called with the non-default argument. A simple example addressing x1 only:
class A:
def __init__(self, x):
self.__x = x
# Access the property itself off the class, bypassing execution,
# then call it directly with the non-default argument
type(self).x1.fget(self, True)
#property
def x1(self, doset=False):
if doset:
self.__x1 = self.__x + 1
return self.__x1
Alternatively, to simplify the usage in __init__, you can use a separate name for the underlying function vs. the property to achieve the same effect:
class A:
def __init__(self, x):
self.__x = x
# Call the implementing function directly with the non-default argument
self._x1(True)
# Implementing function named with single underscore prefix to indicate it's
# for internal/protected use only
def _x1(self, doset=False):
if doset:
self.__x1 = self.__x + 1
return self.__x1
# Define property x1 based on x1 for outside use
x1 = property(_x1)
Of course, if you don't have a complicated getter path, then the real solution is to separate _x1 from x1 completely, where _x1 is pure setter helper function for __init__, and x1 is pure getter:
class A:
def __init__(self, x):
self.__x = x
# Call the init helper
self._init_x1()
# Implementing function named with single underscore prefix to indicate it's
# for internal/protected use only
def _init_x1(self):
self.__x1 = self.__x + 1
#property:
def x1(self):
return self.__x1
To be clear, only the last of these is "Pythonic" in any meaningful sense. The second option has some limited use cases (where you have a function that demands existence, and is highly configurable, but has a reasonable set of defaults that a property could use), but in that case, it's usually a function that has public utility just like the property. Option #1 is the least Pythonic, as it's inconvenient to use (needing to elevate to the class type, extract the fget member, and explicitly pass self), and makes it quite clear that there is no expected use case outside of __init__ (because it's such a pain to use that no one would bother).

How to assign class method to class attribute? [duplicate]

This question already has answers here:
Calling a function of a module by using its name (a string)
(18 answers)
Closed 7 years ago.
I'm trying to assign class methods to class attribute, so I can call the methods from string. When using the class I want to call it from string like:
A.MAP['add'](x, y)
A.MAP['subtract'](x, y)
This is my current code:
class A:
MAP = {
'add' : A.add(x, y),
'subtract' : A.subtract(x, y),
}
#classmethod
def add(cls, x, y)
return x + y
#classmethod
def subtract(cls, x, y)
return x - y
However the result shown error that A is not defined at the line of assigning A.add to MAP['add']. For short functions I can use lambda. However, in case of a longer function, how can I achieve this design?
Note that when you try:
class A:
MAP = {
'add' : A.add(x, y),
'subtract' : A.subtract(x, y),
}
you are trying to access e.g. A.add before the name A exists (the class isn't bound to the name until definition completes) and before the name add exists (you haven't defined that method yet). Everything at the top level of the class definition is done in order.
You need to put the class methods into the dictionary after the class has been defined (they don't become callable until definition is complete):
class A:
MAP = {}
#classmethod
def add(cls, x, y): # note colon
return x + y
#classmethod
def subtract(cls, x, y): # also here
return x - y
A.MAP['add'] = A.add
A.MAP['subtract'] = A.subtract
Note that, as neither class method uses cls, you could make them #staticmethods instead. Or just use functions - Python isn't Java, you don't need to put everything into a class.
Alternatively, you can use getattr to access attributes (including class methods) by name:
>>> class A:
#classmethod
def add(cls, x, y):
return x + y
#classmethod
def subtract(cls, x, y):
return x - y
>>> getattr(A, 'add')(1, 2)
3
Please do not program in python like that, instead use a more standard oop approach like this:
#!/usr/bin/env python
class A:
def __init__(self):
pass
#classmethod
def add(self, x, y):
return x + y
#classmethod
def subtract(self, x, y):
return x - y
if __name__ == "__main__":
a = A()
print a.add(1,2) # ans: 3
print a.subtract(2,1) # ans: 1

Python decorator that makes OOP code FP; good or bad idea?

Recently I've been trying to figure out a solution to the 'expression problem' of choosing between implementing my code in OOP or FP (functional programming). The example I used to illustrate my problem was a Vector2D class. I could make a class that contains all the necessary functions for a 2D vector (dot product, magnitude, etc.), or I could make a set of functions that take a 2-tuple representing a vector. Which option do I chose?
To cope with this problem, I thought it might be nice to make a decorator that takes a class's methods and turns them into global functions. This is how I did it:
import types
def function(method):
method._function = True
return method
def make_functions(cls):
for key in cls.__dict__:
method = getattr(cls, key)
if not isinstance(method, types.FunctionType):
continue
if hasattr(method, '_function') and method._function:
globals()[method.__name__] = method
return cls
#make_functions
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return 'Vector(%g, %g)' % (self.x, self.y)
def __iter__(self):
for component in self.x, self.y:
yield component
def __getitem__(self, key):
return (self.x, self.y)[key]
def __setitem__(self, key, val):
if key == 0:
self.x = val
elif key == 1:
self.y = val
else:
print('not cool man')
def __add__(self, other):
x = self[0] + other[0]
y = self[1] + other[1]
return self.__class__(x, y)
__radd__ = __add__
def __sub__(self, other):
x = self[0] - other[0]
y = self[1] - other[1]
return self.__class__(x, y)
def __rsub__(self, other):
x = other[0] - self[0]
y = other[1] - self[1]
return self.__class__(x, y)
def __mul__(self, other):
x = other * self[0]
y = other * self[1]
return self.__class__(x, y)
__rmul__ = __mul__
#function
def dot_product(self, other):
return self[0]*other[1] + self[1]*other[0]
Now, dot_product is not only a method of the Vector2D class, but it is also a global function that takes in two vectors (or vector-like objects). This satisfies both the functional and object-oriented approaches to implementing an object like this. The only problem I can foresee this approach making is that any class that can be represented as another object like a tuple or a list, must be defined to work in the same ways as the objects which act like it. This is not so bad for a Vector that can also be a tuple, since all we have to do is define the __getitem__ and __iter__ methods, however I can see this getting wildly out of control for classes that have multiple contrasting implementations
Is this a fair solution to the problem? Is it bad practice or technique? Should I solely provide one or the other?
Python has a #staticmethod decorator for using class methods without an instantiation of that class. Simply annotate a class method with the static method wrapper (note the method now does not take a self reference), and you can call it from the class itself.
In your case, for the dot product, simply do:
class Vector2D():
# Magic methods here...
#staticmethod
def dot_product(a, b):
return a[0]*b[1] + a[1]*b[0]
Then, simply call Vector2D.dot_product(my_vector1, my_vector2) to use the function from the Vector2D class itself.
Assigning class methods to global functions sounds like a very dangerous, buggy, complex, and verbose solution. I would avoid it at all costs.

Using python property and still able to set the values explicitliy

Im trying to understand how the #property decorator works.
Here I have used method y as a property for field x,
After the attribute-self.x has a property, does it mean that we can't set the value explicitly..
I thought the last statement--> c.x = 2 will not work once you have the property method set on a variable?
class C(object):
def __init__(self):
self.x = 0
self.list = [1,2,3,4,10]
#property
def y(self):
print 'getting'
self.x = sum(self.list)
return self.x
#y.setter
def y(self, value):
print 'setting'
self.x = value
if __name__ == '__main__':
c = C()
print 'Value of c.y=',c.y
print '-'*80
c.y = 50
print '-'*80
print c.y
print '-'*80
if c.y >5:
print 'Hi'
You can always set x explicitly.
class Foo(object):
def __init__(self):
self.x = 1
self.lst = [1,2,3]
#property
def y(self):
self.x = sum(self.lst)
return self.x
#y.setter
def y(self,value):
self.x = value
f = Foo()
print f.y #6
print f.x #6
f.x = 3
print f.x #3
print f.y #6
print f.x #6
The problem is that in this example, calling the getter (y) also sets the value of the x attribute, so you'll never see the change of x if you're doing all of the changing via y because the act of looking at y changes the value of x.
One way that you might try to get around that limitation is:
class Foo(object):
def __init__(self):
self.x = None
self.lst = [1,2,3]
#property
def y(self):
return sum(self.lst) if self.x is None else self.x
#y.setter
def y(self,value):
self.x = value
Now if you explicitly set a value for x (or y), that value will stick until you set it back to None which you could even do in another function decorated with #y.deleter if you really wanted.
There is limited support for private instance variables in Python via name-mangling
to avoid exposing x, you need two leading underscores, i.e. __x
You cant prohibit to change attribute directly using property decorator but You can do such a trick I think
class A(object):
def __init__(self):
self.x = 0
#property
def x(self):
return self.__dict__['x']
#x.setter
def x(self, value):
self.__dict__['x']=value
this will allow You to implement behavior like You have described
Python does not provide any capability for preventing callers from accessing variables. In other words, there is no "private" in Python. By convention, a variable or method prefixed with an underscore is not intended for external use. E.g.,
class C(object):
def __init__(self):
self._x = 0
self.list = [1,2,3,4,10]
.
.
.
I can still access _x if I really want to, and nothing prevents me from setting it.
>>> c = C()
>>> c._x
10
>>> c._x = 20
>>> c._x
20
However, by convention, the underscore tells me I'm doing something dangerous and ill advised. It's up to me, the programmer, to determine if I broke anything by doing it.
This is a conscious design decision made when creating Python. The idea is that whoever uses your class is responsible for what they do with it; if they misuse it and it breaks, that's their fault. You warned them with the underscore. I think the notion that a clever programmer can get around your attempts to lock them out anyway may have played a role in the decision (such as reflection libraries or interacting with the compiled bytecode directly), but don't hold me to that.
On a mildly related note, the underscore does actually do something if the variable (including other imported modules, functions, etc.) is a member of a module. Members beginning with an underscore are not imported by import *. E.g.,
a.py
_a = 10
b = 50
Command prompt:
>>> from a import *
>>> b
50
>>> _a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_a' is not defined
In your particular example, x and its setter are relatively useless since you're overriding its value any time the getter is called.
class Foo(object):
def init(self):
self.x = None
self.lst = [1,2,3]
#property
def y(self):
return sum(self.lst) if self.x is None else self.x
#y.setter
def y(self,value):
self.x = value

Categories

Resources