New to python classes and objects - python

Hello Ive only been coding for about 3 weeks now and I stumbled across this code that doesn't do anything when I put it in.
class calculation(object):
def multiply(self, a=5, b=6):
self.a = a
self.b = b
I know its simple but I am still new to programming, if anybody could give a brief explanation to why this doesn't work I would really appreciate it. Thanks

It doesn't work because of an indentation error. Indentation is how Python knows that a def is a method on a class rather than a plain function at the top level, how it knows which lines are part of a loop and where the loop ends, etc. You have to get it right. But you've got this:
class calculation(object):
def multiply(self, a=5, b=6):
self.a = a
self.b = b
Because the def is dedented back to the same level as the class, there's nothing inside the class. That's not legal; every compound statement (a statement that ends with a :, like a class definition) has to be followed by something indented.
On top of that, the fact that multiply takes a self parameter means it's almost certainly intended to be a method of some class.
So, to fix it:
class calculation(object):
def multiply(self, a=5, b=6):
self.a = a
self.b = b
And now, it works. But it doesn't seem to do anything, does it?
Of course it's always possible that you didn't copy the whole thing. Or that wherever you copied it from, the code was buggy and missing a line. But let's assume this really is a useful function from someone's useful code (except for the indentation error).
First, all you're doing is defining a class. If never create an instance of that class, much less call any methods on it, the class doesn't do anything. But let's assume you knew that, and you know how to create an instance and call methods. It still doesn't seem to do anything.
Most likely (again, assuming this is what you're actually asking, and that you copied the code right, and…) what this is doing is storing the operands to use later.
A realistic example of why you'd want to do that would be in some kind of expression-tree library, that calls multiply whenever it parses a *, and gradually builds up complex expressions out of simple ones, maybe so you can compile the expression to C code or do algebraic transformations on it.
But that probably sounded like gobbledegook to you, so here's a simple but silly example:
class calculation(object):
def multiply(self, a=5, b=6):
self.a = a
self.b = b
table = []
for a in range(1, 5):
row = []
for b in range(1, 5):
col = calculation()
col.multiply(a, b)
row.append(col)
table.append(row)
print('Times table')
for row in table:
for col in row:
print('{} x {} = {}'.format(col.a, col.b, col.a * col.b))

Your problem is that the function inside the class is misindented. Try indenting that. Also, for your multiply function, you probably want to return the two values multiplied:
class calculation(object):
def multiply(self, a=5, b=6):
self.a = a
self.b = b
return self.a * self.b

Related

Pythonic way of class argument validation

I would like to get some tips on the Pythonic way to validate the arguments when creating an instance of a class. I have a hard time understanding the proper usage of the __new__ method and maybe this is one of its usages? Say for example that i have class Test that takes in two arguments a and b. If, for example, i want to ensure that both must be integers and that b must be greater than a, i could do as follows:
class Test:
def __init__(self, a, b):
if not (isinstance(a,int) and isinstance(b,int)):
raise Exception("bla bla error 1")
if not b > a:
raise Exception("bla bla error 2")
self.a = a
self.b = b
#.....
or, i could do as follows:
def validate_test_input(a,b):
if not (isinstance(a, int) and isinstance(b, int)):
raise Exception("bla bla error 1")
if not b > a:
raise Exception("bla bla error 2")
class Test:
def __init__(self, a, b):
validate_test_input(a,b)
self.a = a
self.b = b
#.....
What would you do? Is there any convention on data validation ? Should dunder new method be used here? If , so please show an example.
First snippet is almost perfectly fine. Unless this logic is reused in several places in your code base I would avoid the second snippet because it decouples the logic from the class.
I would just do some small semantic changes.
Raise proper exception types, ie TypeError and ValueError
Rephrase the conditions to be more readable (you may disagree as this is quite subjective)
Of course provide a useful text instead of "bla bla", but I trust you with that one ;)
class Test:
def __init__(self, a, b):
if not isinstance(a, int) or not isinstance(b, int):
raise TypeError("bla bla error 1")
if a <= b:
raise ValueError("bla bla error 2")
self.a = a
self.b = b
#.....
Some may find the original if not (isinstance(a, int) and isinstance(b, int)) to be more readable than what I suggested and I will not disagree. Same goes for if a <= b:. It depends if you prefer to stress the condition you want to be true or the condition you want to be false.
In this case, since we are raising an exception I prefer to stress the condition we want to be false.
If this code is at development, I would maybe do that, which is not very different from your code:
class Test:
def __init__(self, a, b):
assert isinstance(a,int) and isinstance(b,int), "bla bla error 1"
assert b > a, "bla bla error 2"
self.a = a
self.b = b
#.....
And if I need this control when I will release that code (for example, if it is a library) I would convert asserts to raise, then raise a TypeError and a ValueError:
class Test:
def __init__(self, a, b):
if not (isinstance(a,int) and isinstance(b,int)):
raise TypeError("bla bla error 1")
if not b > a:
raise ValueError("bla bla error 2")
self.a = a
self.b = b
#.....
So your code is the true way to go.
In the case of __new__ magic method, today I found a good example in builtin turtle library. In the definition of Vec2D class:
class Vec2D(tuple):
"""A 2 dimensional vector class, used as a helper class
for implementing turtle graphics.
May be useful for turtle graphics programs also.
Derived from tuple, so a vector is a tuple!
Provides (for a, b vectors, k number):
a+b vector addition
a-b vector subtraction
a*b inner product
k*a and a*k multiplication with scalar
|a| absolute value of a
a.rotate(angle) rotation
"""
def __new__(cls, x, y):
return tuple.__new__(cls, (x, y))
...
As you know, tuple takes an argument which is iterable. Developers of this module probably wanted to change it, so they defined __new__ as (cls, x, y), and then they called tuple.__new__ as (cls, (x, y)). The cls in here is the class which is instanced. For more information, look at here: Calling __new__ when making a subclass of tuple
The way you do it in the first code snippet is okay, but as python is quite versatile with what you can pass to a function or a class, there is much more to check if you go that way that mere argument types.
Duck typing makes checking argument types less reliable: a provided object could comply with what a function or a constructor need but not derive from some known class.
You could also want to check arguments names or such things.
The most common style is rather not testing inputs and consider the caller is safe (in internal code) and use some dedicated module like zope.interface for interactions with external world.
To make things lighter on a syntaxic POV interface checking is also typically done using decorators.
PS: the '__new__' method is about metaclass and used to solve issue related to objects allocation. Definitely unrelated to interface checks.

Python method/function chaining

In python, is it possible to chain together class methods and functions together? For example, if I want to instantiate a class object and call a method on it that affects an instance variable's state, could I do that? Here is an example:
class Test(object):
def __init__(self):
self.x = 'Hello'
#classmethod
def make_upper(y):
y.x = y.x.upper()
What I'm wanting to do is this:
h = Test().make_upper()
I want to instantiate a class object and affect the state of a variable in one line of code, but I would also like to be able to chain together multiple functions that can affect state or do something else on the object. Is this possible in python like it is in jQuery?
Yes, sure. Just return self from the instance methods you are interested in:
class Test(object):
def __init__(self):
self.x = 'Hello'
def make_upper(self):
self.x = self.x.upper()
return self
def make_lower(self):
self.x = self.x.lower()
return self
h = Test().make_upper()
print(h.x)
Output:
HELLO
Yes and no. The chaining certainly works, but h is the return value of make_upper(), not the object returned by Test(). You need to write this as two lines.
h = Test()
h.make_upper()
However, PEP-572 was recently accepted for inclusion in Python 3.8, which means someday you could write
(h := Test()).make_upper()
The return value of Test() is assigned to h in the current scope and used as the value of the := expression, which then invokes its make_upper method. I'm not sure I would recommend using := in this case, though; the currently required syntax is much more readable.

Using Python classes for encapsulation, not instantiation

I have run across a few examples of Python code that looks something like this:
class GiveNext :
list = ''
def __init__(self, list) :
GiveNext.list = list
def giveNext(self, i) :
retval = GiveNext.list[i]
return retval
class GiveABCs(GiveNext):
i = -1
def _init__(self, list) :
GiveNext.__init__(self, list)
def giveNext(self):
GiveABCs.i += 1
return GiveNext.giveNext(self, GiveABCs.i)
class Give123s(GiveNext):
i = -1
def _init__(self, list) :
GiveNext.__init__(self, list)
def giveNext(self):
Give123s.i += 1
return GiveNext.giveNext(self, Give123s.i)
for i in range(3):
print(GiveABCs('ABCDEFG').giveNext())
print(Give123s('12345').giveNext())
the output is: A 1 B 2 C 3
If I were more clever, I could figure out how to put the string literals inside the constructor...but that is not crucial right now.
My question is on the use of classes this way. Yes, an instance of the class gets created each time that that the call within the print() gets made. Yet the i's are 'permanent' in each class.
This strikes me as less of an object-oriented approach, and more of a way of using classes to accomplish encapsulation and/or a functional programming paradigm, since the instances are entirely transitory. In other words, an instance of the class is never instantiated for its own purposes; it is there only to allow access to the class-wide methods and variables within to do their thing, and then it is tossed away. In many cases, it seems like the class mechanism is used in a back-handed way, in order to leverage inheritance and name resolution/spacing: an instance of the class is never really required to be built or used, conceptually.
Is this standard Python form?
Bonus question: how would I put the string literals inside each class declaration? Right now, even if I change the _init__ for GiveABCs to
GiveNext.__init__(self, 'wxyz')
it completely ignores the 'wxyz' literal, and uses the 'ABCDEF' one - even though it is never mentioned...
Please don't learn Python with this code. As mentioned by others, this code goes against many Python principles.
One example: list is a Python builtin type. Don't overwrite it, especially not with a string instance!
The code also mixes class and instance variables and doesn't use super() in subclasses.
This code tries to simulate an iterator. So simply use an iterator:
give_abcs = iter('ABCDEFG')
give_123s = iter('12345')
for _ in range(3):
print(next(give_abcs))
print(next(give_123s))
# A
# 1
# B
# 2
# C
# 3
If you really want to fix the above code, you could use:
class GiveNext :
def __init__(self, iterable) :
self.i = - 1
self.iterable = iterable
def giveNext(self) :
self.i += 1
return self.iterable[self.i]
giveABCs = GiveNext('ABCDEFG')
give123s = GiveNext('12345')
for _ in range(3):
print(giveABCs.giveNext())
print(give123s.giveNext())
It outputs:
A
1
B
2
C
3
This code in the OP is an incredible amount of crap. Not only it is long, unreadable, misuses OO features, and does not use Python features at all (an iterator being a standard Python feature). Here is a suggestion for a more Pythonist approach:
giveABCs = iter('ABCDEFG')
give123s = iter('12345')
for i in range(3):
print(next(giveABCs))
print(next(give123s))
About your bonus question: I guess you are modifing the _init__() method of GiveABCs and Give123s. It is normal that whatever code you put in there has no effect, because the Python constructor is __init__() (with 2 leading underscores, not 1). So The constructor from GiveNext is not overloaded.

Self in python Class - I can do it with out it...? [duplicate]

This question already has answers here:
Why do you need explicitly have the "self" argument in a Python method? [duplicate]
(10 answers)
Closed 6 years ago.
Consider this code:
class example(object):
def __init__ (): # No self
test() # No self
def test(x,y): # No self
return x+y
def test1(x,y): # No self
return x-y
print(example.test(10,5))
print(example.test1(10,5))
15
5
This works as expected. I believe I can write a whole program not using self. What am I missing? What is this self; why is it needed in some practical way?
I have read a lot about it - (stack, Python documentation), but I just don't understand why it's needed, since I can obviously create a program without it.
You can perfectly create a program without it. But then you'd be missing one of the key features of classes. If you can do without self, I'd argue you can do without classes and just do something purely with functions :)
Classes allow you to create objects which have a PROPERTY associated to them, and self allows you to access those values. So say you have a square.
g code:
class Square(object):
def __init__ (self, length, height):
self.length = length # THIS square's length, not others
self.height = height # THIS square's height, not other
def print_length_and_height(self):
print(self.length, self.height) # THIS square's length and height
square1 = Square(2,2)
square2 = Square(4,4)
square1.print_length_and_height() # 2 2
square2.print_length_and_height() # 4 4
Now, this example is quite silly, of course, but i think it shows what SELF specifically is for: it refers to the particular instance of an object.
By all means, if you don't see the point to it, just do away with classes and just use functions, there nothing wrong with that.
You haven't utilised a class or object properly. Cutting out the garbage code, your program reduces to:
def test(x,y): #No class
return x+y
def test1(x,y): #No class
return x-y
print(example.test(10,5))
print(example.test1(10,5))
Output:
15
5
Your "class" is no more useful than if you wrapped your program in the nested structures:
if True:
for i in range(1):
...
A proper object will have attributes (data fields) and functions that operate on that data (see below). Your code has an empty object; hence, you have nothing on which to operate, no need for self, and no need for a class at all.
Rather, use a class when you need to encapsulate a data representation and associated operations. Below, I've reused some of your code to make example do some trivial complex number work. There are many extensions and improvements to make in this; I kept it relatively close to your original work.
class example(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
sign = ' + ' if self.b >= 0 else ' - '
return str(self.a) + sign + str(abs(self.b)) + 'i'
def add(self, x):
self.a += x.a
self.b += x.b
def sub(self, x):
self.a -= x.a
self.b -= x.b
complex1 = example(10, 5)
complex2 = example(-3, 2)
complex1.add(complex2)
print(complex1)
complex2.sub(complex1)
print(complex2)
Output:
7 + 7i
-10 - 5i
Are you familiar with Object-Oriented Paradigm?
If you don't you should check it. Python is a Object-Oriented Language and self lets you define your object properties.
An example:
You have a class named Vehicle. A vehicle could be a bike, a car, even a plane. So something you can include is a name and a type.
class Vehicle():
def init(self, name, type): # Constructor
self.name = name
self.type = type
def info(self):
print("I'm a ")
print(self.name)
That's all, now you have a vehicle with name and type. Every instance of Vehicle would have a name and a type different or not and every intance can access its own variables. I'm sorry I can't explain it better. Firstable you need to know Object-Oriented Paradigm knowledge. Please comment my answer if you have doubts & I'll answer you or give a link where it comes explained better.

Nested classes: Accessing the methods of the outer class from the inner one

Suppose you have two classes, A and B. Class B is defined inside the class A. I want to access the variables and methods of the outer class while inside the inner class. The code here is a toy example but has the essentials of what I want to demonstrate:
class A:
a = 'even'
b = 'odd'
class B:
def __init__(self, n):
if n%2 == 0: self.num = a
if n%2 == 1: self.num = b
self.description = A.desc()
def __getitem__(self, i):
return self.B(i)
def desc(self):
return a + '-' + b
>>> c = A()
>>> d = c[4]
>>> TypeError: unbound method desc() must be called with A instance as first argument (got nothing instead)
Here the method desc does some work on the variables of the class A and produces output. Class A is initialized correctly and you can access the variables a and b, even from the inner scope, given that you don't define the description variable. However, I cannot find a way to call the outer scope class methods desc. Is it possible to use the method desc in B without instantiating class A?
Explanation on why I use such a pattern:
Variables a and b in my program are rather big. I only need to initialize them once. In addition, I don't want these variables to float around in the program but to be only accessible to the inner class. Adding to all these is the fact that I can use the A.__getitem__ to extract 'slices' of the big data when needed. So the outer class provides me with hiding/encapsulation of the data, the indexing operator (through __getitem__) and all the routines required for extraction of slices of data (here the method desc. The inner class, B, provides the bundling of useful information from the big data for each index. This, most likely, is not the optimal design for achieving the described task. I am open and eager to hear your opinion regarding the alternative patterns.
I can't see any reason for you to be using classes here, let alone nested ones. In any case, there is almost never a reason to nest classes in Python, since inner classes don't get any special access to the outer class.
However if you want to allow anything to access a method without instantiating the object, you can make it a classmethod:
#classmethod
def desc(self):
return a + '-' + b
But I can't see why you would do any of this. Also, nothing here is a closure.

Categories

Resources