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

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.)

Related

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).

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)
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'

Python - How to edit a class object value automatically?

How can I change a class object with some rules when it assigned?
for example:
class Foo:
x=0
if x < 0:
x = -1
else:
x = 1
p = Foo()
p.x = 1234
print(p.X)
So when I print p.x I expect 1 to be printed. but 1234 is printed. What should I do?
The first x = 0 you declare is a class attribute. It is the same for all objects of the class.
When you write p.x, you create an instance attribute, a value of x that belongs to that specific object. That hides the Foo.x in that particular object (that's how the python attribute lookup works).
However, that value remains the default for other objects of the class, eg, if you create a new object
foo2 = Foo()
print(f2.x) # prints 1
You have to make x a property, with a setter function:
class Foo:
def __init__(self):
self.x = 1
#property
def x(self):
return self._x
#x.setter
def x(self, value):
if value < 0:
value = -1
else:
value = 1
self._x = value
This makes it so the function decorated with #x.setter is executed whenever an assignment to the x attribute is performed:
>>> foo = Foo()
>>> foo.x = 1234
>>> foo.x
1

Python class attribute validation on __init__

I'm trying to validate one attribute of my class using setter in the code below. The attribute I want to validate is called '__x' and is set to parameter passed on 'init' method. When I change 'self__x' to 'self.x', it's working as I expect. What I want to is how it's working with 'self.x', while I don't return 'x' attribute anywhere in getter and setter methods and why it's not working with 'self.__x'?
class P:
def __init__(self, x):
self.__x = x # not working
# self.x = x # working
#property
def x(self):
return self.__x
#x.setter
def x(self, x):
if x < 0:
self.__x = 0
else:
self.__x = x
p = P(-5)
print(p.x) # prints -5
It's like this. Imagine there's a school bully, let's call him Dan, who targets you. There's also Beth, who you like very much. Normally, you want to avoid Dan and meet Beth, but Dan doesn't care and will bop you on the head if he sees you.
Now you also make friends with Joe. He's a gentle giant. Very nice guy. He says to come to his place and he'll make sure he doesn't let Dan in. It all works great: when Dan comes to Joe's door, he's turned away; when Beth comes, Joe lets her in.
The key point is this: it only works as long as Dan is opening the door. If you hear the doorbell and you go out yourself, it doesn't work any more.
So here, if you do self.x = -5, Joe checks the number, sees it's Dan, and sends him packing with a zero. But if you do self.__x = -5, Joe never sees Dan. You get a bop on the head.
self.__x is just a variable, it can't do any checking on its own. self.x is a function though (two of them really, one for reading and one for writing), and it can do whatever it wants - set self.__x or refuse to.
Let's begin with the "#decorator" syntax. It's actually only syntactic sugar, so
#decorate
def myfunc():
pass
is just a shorthand for
def myfunc():
pass
myfunc = decorate(myfunc)
Note that python functions are objects too (as well as classes and modules FWIW) so you can pass functions as arguments to other functions, return functions from functions, store functions as variables or attributes etc.
Now with the property class (yes, it's a class): it's only a generic implementation of the descriptor protocol, which is the python mechanism to support computed attributes.
A naive python implementation of property would mostly look something like (I ignore the fdel and __del__ parts):
class propertytype(type):
# this is what will allow you
# to use `property` as decorator,
# it will return a new `property` instance
# with `func` as setter
def __call__(cls, func):
return cls(func)
class property(metaclass=propertytype):
def __init__(self, fget, fset=None):
self.fget = fget
self.fset = fset
# this is the getter
def __get__(self, instance, cls=None):
if instance is None:
return self
return self.fget(instance)
# this is the setter (if there's one)
def __set__(self, instance, value):
if not self.fset:
raise AttributeError("Attribute is read-only")
self.fset(instance, value)
# and this allows you to use`#myprop.setter`
# in your class definition
def setter(self, func):
self.fset = func
return self
And finally: while it's good practice to create all instance attributes of an object in the initializer (the __init__ method), you can actually set existing or new attributes just wherever and whenever you want. Except for a few types that (mainly for implementation reasons) use a totally different way to store attributes (you can look for slots if you want to learn more about this), ordinary Python objects are, mainly, dicts in disguise, so myobj.foo = 'bar' will usually just store 'bar' in self.__dict__['foo']. Well, if you don't use computed attributes, of course ;)
Ok, now we have the building blocks, let analyze what's going on with your class:
class P:
# let's ignore the initializer for now
#property
def x(self):
return self.__x
#x.setter
def x(self, x):
if x < 0:
self.__x = 0
else:
self.__x = x
This could be rewritten as
class P:
# let's ignore the initializer for now
def _getx(self):
return self.__x
def _setx(self):
if x < 0:
self.__x = 0
else:
self.__x = x
x = property(_getx, setx)
So now with
p = P()
when we do:
p.x = 5
the attribute resolution rules (implemented in object.__setattr__(self, name, value)) will actually lookup "x" on "P", find our "x" property, and since it's a binding descriptor (it has a __set__ method), call x.__set__(p, 5), which in turn will call self.fset(p, 5) (cf property.__set__() definition), which will call p._setx(5).
And if we had back the initializer:
class P:
def __init__(self, x):
self.x = x
# getter / setter / property definition here
then the very exact thing happens (except the P instance is named self instead of p ) - it actually ends up calling P._setx(self, x).
The only difference with your original implementation is that using the property has a decorator, the getter and setter functions do not become methods of the class, they only live as the fget and fset attributes of the x property object.

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