How do change class attributes individually? - python

I read a bit about getters and setters, but haven't quite figured it out. One of my issues is the declaration in the init method: how can I change only one attribute if the method needs to arguments? Any other methods are of course welcome as well.
class States:
def __init__(self, f=0, n=0):
self.state = n
self.level_state = f
#property
def state(self, n):
return self._state
#state.setter
def state(self, n):
self._state = n
#property
def level_state(self, f):
return self._level_state
#level_state.setter
def state(self, f):
self._level_state = f
Example situation, changing the attributes individually:
Situation1:
States().state = 3
Situation2:
States().level_state = 2

The code doesn't work because you've named the underlying attributes the same as the corresponding properties.
You need to use the same attribute names as the property getters/setters are referring to:
class States:
def __init__(self, f=0, n=0):
self._state = n # <-- changed here
self._level_state = f # <-- changed here
#property
def state(self, n):
return self._state
#state.setter
def state(self, n):
self._state = n
#property
def level_state(self, f):
return self._level_state
#level_state.setter
def state(self, f):
self._level_state = f
But the simple solution for this case would be to not use properties at all:
class States:
def __init__(self, f=0, n=0):
self.state = n
self.level_state = f
# done

Related

Magical method __len__()

How to call the __len__() function using an object of the class ?
class foo(object):
def __init__(self,data)
self.data = data
def __len__(self):
return len(self.data)
x = foo([1,2,3,4])
The idea behind a magic method is to be able to call it as x.__len__() or len(x). They don't return the output until explicitly called or have or stored in class variables.
Method 1: Call function explicitly
You can simply call the function explicitly as -
class foo(object):
def __init__(self,data):
self.data = data
def __len__(self):
print('i am in a magic function')
return len(self.data)
x = foo([1,2,3,4])
len(x) #or x.__len__() which is equivalent
i am in a magic function
4
Method 2: Display during initialization
Or if you want to trigger it during initialization, just add it in the __init__(). Remember, init wouldn't return anything so you can push the output into stdio with a print.
class foo(object):
def __init__(self,data):
self.data = data
print(self.__len__())
def __len__(self):
print('i am in a magic function')
return len(self.data)
x = foo([1,2,3,4])
i am in a magic function
4
Method 3: Store and access as a class variable
If you want to save it, then you can define a self.length variable which can store it and can be retrieved by x.length
class foo(object):
def __init__(self,data):
self.data = data
self.length = self.__len__()
def __len__(self):
return len(self.data)
x = foo([1,2,3,4])
x.length
4
You can do it this way:
>>>x = foo([1,2,3,4])
>>>len(x)
4
It basically allows you to use len().
Imagine you have only:
class foo(object):
def __init__(self,data):
self.data = data
x = foo([1,2,3,4])
print(len(x))
Now, if you have:
class foo(object):
def __init__(self,data):
self.data = data
self.length = len(data)
x = foo([1,2,3,4])
print(len(x))
You still have the error:
(You can get the length with x.length though)
But if you add the magical method __len__():
class foo(object):
def __init__(self,data):
self.data = data
self.length = len(data)
def __len__(self):
return self.length
x = foo([1,2,3,4])
print(len(x))
You now use len() successfully.
Same way you call any other function. By its name.
print(x.__len__())
which will give 4 for your code
If we go with your class called foo() we can call the method __len__ like this.
a = foo([1,2,3,4])
b = a.__len__()
Or if you want to save the length within the class:
class foo(object):
def __init__(self,data)
self.data = data
self.len = None
def __len__(self):
self.len = len(self.data)
a = foo([1,2,3,4])
a.__len__()
print(a.len)

multiple functions in Python

We have some variable, or other instance: a='?'.
We have such input:
f = a(3112).bas(443).ssad(34)
When we type
print(f)
Output should be:
3112a-443bas-34ssad
I've tried some ways to solve this and have found information about chaining, but I still have the problem. I can't return class name to the brginning of the string.
This, what I have:
class A():
def __getattribute__(self, item):
print (str(item))
return super(A, self).__getattribute__(item)
def __init__(self, x):
self.x = x
print (str(x))
def b(self, item):
print (str(item))
return self
def c(self, item):
print (str(item))
return self
def d(self, item):
print (str(item))
return self
A(100).b(200).c(300).d(400)
My output:
100
b
200
c
300
d
400
But I couldn't concatenate it in one string.
Dynamic way
class A(object):
def __init__(self, integer):
self._strings = ['{}a'.format(integer)]
def __getattr__(self, attrname, *args):
def wrapper(*args, **kwargs):
self._strings.append('{}{}'.format(args[0], attrname))
return self
return wrapper
def __str__(self):
return '-'.join(self._strings)
print(A(100).bas(200).ssad(300))
Output
100a-200bas-300ssad
But also
print(A(100).egg(200).bacon(300).SPAM(1000))
Output
100a-200egg-300bacon-1000SPAM
Static way
class A(object):
def __init__(self, integer):
self._strings = ['{}a'.format(integer)]
def bas(self, integer):
self._strings.append('{}bas'.format(integer))
return self
def ssad(self, integer):
self._strings.append('{}ssad'.format(integer))
return self
def __str__(self):
return '-'.join(self._strings)
print(A(100).b(200).c(300))
Output
100a-200bas-300ssad
More about __str__
You can override the __str__ method to define your specific output:
class A():
def __init__(self, a, b="", c="", d=""):
self._a = a
self._b = b
self._c = c
self._d = d
def __str__(self):
return '{}a-{}b-{}c-{}d'.format( self.a, self.b, self.c, self.d )
def b(self, item):
self._b = item
return self
def c(self, item):
self._c = item
return self
def d(self, item):
self._d = item
return self
f = A(100).b(200).c(300).d(400)
print(f) # 100a-200b-300c-400d
Here I tried it in another way , ie, If you want to take the function name instead of manually giving it you can use inspect in python. Try this code :
import inspect
class A():
l = []
def __init__(self, x):
self.x = x
print (str(x))
self.l.append(str(x) + "a")
def b(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
def c(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
def d(self, item):
print (str(item))
self.l.append(str(item) + inspect.stack()[0][3])
return self
print("-".join(A(100).b(200).c(300).d(400).l))
The o/p is like :
'100a-200b-300c-400d'

Chaining instance methods in python

I would like create a class in python with method and sub-method.
Example what I want to do :
foo = Foo()
foo.playlist('my playlist').add('i_add_a_track_in_"my playlist".ogg')
foo.playlist('my playlist').delete('i_remove_this_track.ogg')
I have this code for now :
class Foo(object):
def playlist(self, name):
pass #my function...
def add(self, track):
pass #adding track
def delete(self, track):
pass #delete track
Please help me, I don't know how i can do it.
Thank you
IIUC, you want to chain method calls one after another? All you'd have to do is return self at the end of each function.
class Foo(object):
...
def playlist(self, name):
...
return self
... # and so on
MVCE:
In [229]: class Foo:
...: def __init__(self, data):
...: self.data = data
...:
...: def add(self, val):
...: self.data += val
...: return self
...:
...: def sub(self, val):
...: self.data -= val
...: return self
...:
In [231]: x = Foo(0)
In [232]: x = x.add(10).sub(5) # or just x.add(10).sub(5)
In [233]: x.data
Out[233]: 5
If I understand correctly, foo.playlist('someplaylist').do_something() should actually be a shortcut for
playlist = foo('someplaylist')
playlist.do_something()
where playlist is NOT a foo object (ie: foo.do_something() is not supposed to make any sense and should just raise an error) but an instance of a distinct class.
If that's indeed the case, you actually want two classes: Foo with method playlist(...) that returns a Playlist object, and Playlist with add() and delete() methods:
class Playlist(object):
def __init__(self, name):
self.name = name
def add(self, what):
print("adding {} to playlist {}".format(what, self.name))
def delete(self, what):
print("deleting {} from playlist {}".format(what, self.name))
class Foo(object):
def playlist(self, name):
return Playlist(name)

What is the "metaclass" way to do this?

I want to write a program that accepts as input a number p and produces as output a type-constructor for a number that obeys integer arithmetic modulo p.
So far I have
def IntegersModP(p):
N = type('IntegersMod%d' % p, (), {})
def __init__(self, x): self.val = x % p
def __add__(a, b): return N(a.val + b.val)
... (more functions) ...
attrs = {'__init__': __init__, '__add__': __add__, ... }
for name, f in attrs.items():
setattr(N, name, f)
return N
This works fine, but I'd like to know what the Pythonic way to do this is, which I understand would use metaclasses.
Like this:
def IntegerModP(p): # class factory function
class IntegerModP(object):
def __init__(self, x):
self.val = x % p
def __add__(a, b):
return IntegerModP(a.val + b.val)
def __str__(self):
return str(self.val)
def __repr__(self):
return '{}({})'.format(self.__class__.__name__, self.val)
IntegerModP.__name__ = 'IntegerMod%s' % p # rename created class
return IntegerModP
IntegerMod4 = IntegerModP(4)
i = IntegerMod4(3)
j = IntegerMod4(2)
print i + j # 1
print repr(i + j) # IntegerMod4(1)
Metaclasses are for when your class needs to behave differently from a normal class or when you want to alter the behavior of the class statement. Neither of those apply here, so there's really no need to use a metaclass. In fact, you could just have one ModularInteger class with instances that record their value and modulus, but assuming you don't want to do that, it's still easy to do this with an ordinary class statement:
def integers_mod_p(p):
class IntegerModP(object):
def __init__(self, n):
self.n = n % IntegerModP.p
def typecheck(self, other):
try:
if self.p != other.p:
raise TypeError
except AttributeError:
raise TypeError
def __add__(self, other):
self.typecheck(other)
return IntegerModP(self.n + other.n)
def __sub__(self, other):
...
IntegerModP.p = p
IntegerModP.__name__ = 'IntegerMod{}'.format(p)
return IntegerModP

Allowing User to Input Variables (Python)

I am working on a project using PuLP and I am trying to create a terminal prompt to allow users to input their data and then my Python program will change the input to code readable by PuLP. To do this I must allow users to input:
2*a + 3*b <= c
and my code will eval() this code as well as creating variables a, b and c such
a = LpVariable("a",None,None,LpContinuous)
b = LpVariable("b",None,None,LpContinuous)
c = LpVariable("c",None,None,LpContinuous)
any ideas? I've tried using exec() but it does not seem to like this much.
at the moment I'm getting the input via:
print "Please enter your constraints 1 at a time and enter '#' when done:"
control = True
while (control):
entry = raw_input('-->')
entryS = ""
entryS += entry
so the string 2*a+3*B <= c is stored as entryS
Using eval() might not be such a good idea, but if you insist (Python 3):
call = lambda f: lambda *args: f(*args)
flip = lambda f: lambda *args: f(*reversed(args))
class Expression:
def __repr__(self):
return '{}({})'.format(type(self).__name__, self)
class BinaryExpression(Expression):
def __init__(self, left, right):
self.left = promote(left)
self.right = promote(right)
def __str__(self):
return '({} {} {})'.format(self.op, self.left, self.right)
class Variable(Expression):
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
class Number(Expression):
def __init__(self, value):
self.value = int(value)
def __str__(self):
return str(self.value)
class Multiplication(BinaryExpression):
op = '*'
class Addition(BinaryExpression):
op = '+'
class Smaller(BinaryExpression):
op = '<'
class Greater(BinaryExpression):
op = '>'
class SmallerOrEqual(BinaryExpression):
op = '<='
class GreaterOrEqual(BinaryExpression):
op = '>='
Expression.__mul__ = call(Multiplication)
Expression.__rmul__ = flip(Multiplication)
Expression.__add__ = call(Addition)
Expression.__radd__ = flip(Addition)
Expression.__lt__ = call(Smaller)
Expression.__gt__ = call(Greater)
Expression.__le__ = call(SmallerOrEqual)
Expression.__ge__ = call(GreaterOrEqual)
def promote(item):
if isinstance(item, str):
return Variable(item)
elif isinstance(item, int):
return Number(item)
else:
return item
class LpVariable:
def __init__(self, name, x, y, z):
self.name = name
self.x = x
self.y = y
self.z = z
def __str__(self):
return 'LpVariable({}, {}, {}, {})'.format(
self.name,
self.x,
self.y,
self.z,
)
__repr__ = __str__
LpContinuous = 'LpContinuous'
class ExpressionVisitor:
def visit(self, node):
return getattr(self, 'visit_' + type(node).__name__)(node)
class LpTransformer(ExpressionVisitor):
def visit_Variable(self, node):
return LpVariable(node.name, None, None, LpContinuous)
def visit_Number(self, node):
return node.value
def visit_Multiplication(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_Addition(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_Smaller(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_Greater(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_SmallerOrEqual(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
def visit_GreaterOrEqual(self, node):
return [node.op, self.visit(node.left), self.visit(node.right)]
class Evaluator(ExpressionVisitor):
def __init__(self, **env):
self.env = env
def visit_Variable(self, node):
return self.env[node.name]
def visit_Number(self, node):
return node.value
def visit_Multiplication(self, node):
return self.visit(node.left) * self.visit(node.right)
def visit_Addition(self, node):
return self.visit(node.left) + self.visit(node.right)
def visit_Smaller(self, node):
return self.visit(node.left) < self.visit(node.right)
def visit_Greater(self, node):
return self.visit(node.left) > self.visit(node.right)
def visit_SmallerOrEqual(self, node):
return self.visit(node.left) <= self.visit(node.right)
def visit_GreaterOrEqual(self, node):
return self.visit(node.left) >= self.visit(node.right)
class Namespace(dict):
def __missing__(self, key):
value = self[key] = Variable(key)
return value
def main():
constraints = '2*a + 3*b <= c'
namespace = Namespace()
tree = eval(constraints, {}, namespace)
print('AST in prefix notation:', tree)
print()
print('Namespace:', namespace)
print()
print('LP-Transformed tree:')
import pprint
pprint.pprint(LpTransformer().visit(tree))
print()
print('Evaluated with a=3, b=5, c=10:')
pprint.pprint(Evaluator(a=3, b=5, c=10).visit(tree))
print()
print('Evaluated with a=3, b=5, c=100:')
pprint.pprint(Evaluator(a=3, b=5, c=100).visit(tree))
if __name__ == '__main__':
main()
Result:
AST in prefix notation: (<= (+ (* 2 a) (* 3 b)) c)
Namespace: {'a': Variable(a), 'c': Variable(c), 'b': Variable(b)}
LP-Transformed tree:
['<=',
['+',
['*', 2, LpVariable(a, None, None, LpContinuous)],
['*', 3, LpVariable(b, None, None, LpContinuous)]],
LpVariable(c, None, None, LpContinuous)]
Evaluated with a=3, b=5, c=10:
False
Evaluated with a=3, b=5, c=100:
True
The LpVariable class is obviously a mockup. Also, the LpTransformer class should produce something that's usable by pulp. Just change the visit_* methods accordingly.
Numbers are all ints, which you might not want. You should probably add floats and/or convert all numbers to decimal.Decimal.
Instead of using eval() I'd probably write a real parser, maybe with pyparsing, or, my favorite for stuff like that, Parcon.
Put
entryS = ""
before the while loop.

Categories