Python strange attribute - python

Ive been taking online Python 3 course and there was an exercise.
You should write a class called Foo that has a property called x, which is set according to these rules:
The initial value of x is 0 when creating the Foo class.
When setting x with a number:
If the number is nonnegative, the two digits to the right of it are stored in x.
p=Foo()
print(p.x) -----> output:0
p.x=123
print(p.x) -----> output :23
I just wondering how is the x getting the assignment through the object.
>>> p=Foo()
>>> p.x = 1234
>>> p.x == 34
True
>>> type(p.x)
<class 'int'>

class Foo():
def __init__(self):
self.n=0
#property
def x(self):
return self.n
#x.setter
def x(self, num):
if num<100 and num>=0:
self.n=num
elif num>100 and num%100!=0 :
self.n=num%100
elif num<0:
self.n=-1
else:
self.n=0

Related

I'm still learning python so I'm still confused on what is going on when it prints "<__main__.Game object at 0x000001B55BE82B90>"

class Game:
def __init__(self, lives):
self.lives = lives
def push(self, num):
self.lives.append(num)
def pop(self):
self.lives.pop()
def peek(self):
print(self.lives)
I want to print lives and remove or add depending on the answer is correct by the user but it does print "<main.Game object at 0x000001B55BE82B90>"
lives =[0, 0, 0]
lives1 = Game(lives)
print(lives1)
a = 5
b = 5
c = a+b
print(a, "+" ,b, "= ")
ans = int(input("Please write the answer:"))
if (c == and):
lives1.push(0)
else:
lives1.pop()
print(lives1)
When you create a class, the default string generated when you print an instance of the class has the form <module.class object at address>:
>>> class Example:
... pass
...
>>> x = Example()
>>> print(x)
<__main__.Example object at 0x0000013D58E1FF10>
There are two methods you can define to make your own display of the class:
__repr__ defines a debug representation of the object.
__str__ defines a print representation of the object.
Example:
>>> class Example:
... def __init__(self, value):
... self.value = value
... def __repr__(self):
... return f'Example(value={self.value})'
... def __str__(self):
... return f'Value = {self.value}'
...
>>> x = Example(7)
>>> x # In the REPL, shows __repr__ string
Example(value=7)
>>> print(repr(x)) # repr() explicitly calls __repr__
Example(value=7)
>>> print(x) # print uses __str__ string
Value = 7
>>> print(str(x)) # str() explicitly calls __str__
Value = 7
When defining classes, consider at least defining __repr__ so it prints useful information about the class as recommended by the __repr__ documentation:
... If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment) [e.g. eval(repr(obj))] ...
This is typically used for debugging, so it is important that the representation is information-rich and unambiguous.
Define __str__ if you need a "pretty" print. If __str__ is not defined, str() uses __repr__.
>>> class Game:
... def __init__(self, lives):
... self.lives = lives
... def push(self, num):
... self.lives.append(num)
... def pop(self):
... self.lives.pop()
... def peek(self):
... print(self.lives)
... def __repr__(self):
... return f'Game(lives={self.lives})'
... def __str__(self):
... return f'Lives = {self.lives}'
...
>>> g = Game([1,2,3])
>>> g
Game(lives=[1, 2, 3])
>>> print(g)
Lives = [1, 2, 3]
Note the __repr__ string I used can be evaluated to produce a Game object with the same value as recommended:
>>> g2 = eval(repr(g))
>>> g2
Game(lives=[1, 2, 3])

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

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

Extending base classes in Python

I'm trying to extend some "base" classes in Python:
class xlist (list):
def len(self):
return len(self)
def add(self, *args):
self.extend(args)
return None
class xint (int):
def add(self, value):
self += value
return self
x = xlist([1,2,3])
print x.len() ## >>> 3 ok
print x ## >>> [1,2,3] ok
x.add (4, 5, 6)
print x ## >>> [1,2,3,4,5,6] ok
x = xint(10)
print x ## >>> 10 ok
x.add (2)
print x ## >>> 10 # Not ok (#1)
print type(x) ## >>> <class '__main__.xint'> ok
x += 5
print type(x) ## >>> <type 'int'> # Not ok (#2)
It works fine in the list case because the append method modifies the object "in place", without returning it. But in the int case, the add method doesn't modify the value of the external x variable. I suppose that's fine in the sense that self is a local variable in the add method of the class, but this is preventing me from modifying the initial value assigned to the instance of the class.
Is it possible to extend a class this way or should I define a class property with the base type and map all the needed methods to this property?
Your two xint examples don't work for two different reasons.
The first doesn't work because self += value is equivalent to self = self + value which just reassigns the local variable self to a different object (an integer) but doesn't change the original object. You can't really get this
>>> x = xint(10)
>>> x.add(2)
to work with a subclass of int since integers are immutable.
To get the second one to work you can define an __add__ method, like so:
class xint(int):
def __add__(self, value):
return xint(int.__add__(self, value))
>>> x = xint(10)
>>> type(x)
<class '__main__.xint'>
>>> x += 3
>>> x
13
>>> type(x)
<class '__main__.xint'>
int is a value type, so each time you do an assignment, (e.g. both instances of += above), it doesn't modify the object you have on the heap, but replaces the reference with one of the result of the right hand side of the assignment (i.e. an int)
list isn't a value type, so it isn't bound by the same rules.
this page has more details on the differences: The Python Language Reference - 3. Data model
IMO, yes, you should define a new class that keeps an int as an instance variable
i expanded you xlist class just a bit, made it so you could find all index points of a number making it so you can extend with multiple lists at once making it initialize and making it so you can iterate through it
class xlist:
def __init__(self,alist):
if type(alist)==type(' '):
self.alist = [int(i) for i in alist.split(' ')]
else:
self.alist = alist
def __iter__(self):
i = 0
while i<len(self.alist):
yield self.alist[i]
i+=1
def len(self):
return len(self.alist)
def add(self, *args):
if type(args[0])==type([1]):
if len(args)>1:
tmp = []
[tmp.extend(i) for i in args]
args = tmp
else:args = args[0]
if type(args)==type(''):args = [int(i) for i in args.split(' ')]
(self.alist).extend(args)
return None
def index(self,val):
gen = (i for i,x in enumerate(self.alist) if x == val)
return list(gen)
Ints are immutable and you can't modify them in place, so you should go with option #2 (because option #1 is impossible without some trickery).
I wrote an example of a mutable integer class that implements some basic methods from the list of operator methods. It can print properly, add, subtract, multiply, divide, sort, and compare equality.
If you want it to do everything an int can you'll have to implement more methods.
class MutablePartialInt:
def __init__(self, value):
self.value = value
def _do_relational_method(self, other, method_to_run):
func = getattr(self.value, method_to_run)
if type(other) is MutablePartialInt:
return func(other.value)
else:
return func(other)
def __add__(self, other):
return self._do_relational_method(other, "__add__")
def __sub__(self, other):
return self._do_relational_method(other, "__sub__")
def __mul__(self, other):
return self._do_relational_method(other, "__mul__")
def __truediv__(self, other):
return self._do_relational_method(other, "__truediv__")
def __floordiv__(self, other):
return self._do_relational_method(other, "__floordiv__")
def __eq__(self, other):
return self._do_relational_method(other, "__eq__")
def __neq__(self, other):
return self._do_relational_method(other, "__neq__")
def __lt__(self, other):
return self._do_relational_method(other, "__lt__")
def __gt__(self, other):
return self._do_relational_method(other, "__gt__")
def __str__(self):
return str(self.value)
def __repr__(self):
return self.__str__()

Categories

Resources