Beginner questions regarding Python classes - python

I am new to Python so please don't flame me if I ask something too noobish :)
1.
Consider I have a class:
class Test:
def __init__(self, x, y):
self.x = x
self.y = y
def wow():
print 5 * 5
Now I try to create an object of the class:
x = Test(3, 4)
This works as expected. However, when I try to call the method wow(), it returns an error, which is fixed by changing wow() to:
def wow(self)
Why do I need to include self and if I don't, what does the method mean?2. In the definition of __init__:
def __init__(self, x, y):
self.x = x
self.y = y
Why do I need to declare x and y, when I can do this:
def __init__(self):
self.x = x
self.y = y
I hope I am being clear...
Thanks for your time.

If you do that :
def __init__(self):
self.x = x
self.y = y
you assign the gobal vars x and y (it they exists ) to your instance
with :
def __init__(self, x, y):
self.x = x
self.y = y
you assign what you give as parameter to the constructor
and that is a lot more flexible :-)

The instance reference in Python is explicit. That way it can be manipulated by e.g. decorators before finally being passed to the method.
We need to declare x and y as arguments to the function so that we can use their names within the function, bound to the arguments passed in the corresponding function call.

Just to be clear
Why do I need to declare x and y, when
I can do this:
def __init__(self):
self.x = x
self.y = y
This ^ will only work if x and y can be found at runtime - if they haven't been passed in then they must have been set elsewhere (globally) or it will generate an error.
>>> class c:
def __init__(self):
self.x = x
>>> x = 1
>>> q = c()
>>> q.x
1
>>> del x
>>> q.x
1
>>> w = c()
Traceback (most recent call last):
File "<pyshell#24>", line 1, in <module>
w = c()
File "<pyshell#14>", line 3, in __init__
self.x = x
NameError: global name 'x' is not defined
>>>
>>> w = c(2)
Traceback (most recent call last):
File "<pyshell#19>", line 1, in <module>
w = c(2)
TypeError: __init__() takes exactly 1 argument (2 given)
This is why you want / need to specify them as parameters - it might work with the global lookup but it would probably violate the "principle of least astonishment"

self is a "magic" name - it can really be anything, but self is used for consistency and clarity. To answer your question, each class method/function requires an explicit reference to the class as the first parameter. Using Ipython:
In [66]: class Test:
....: def __init__(self):
....: pass
....: def wow(self):
....: print self
....:
....:
In [67]: x = Test()
In [68]: x.wow()
<__main__.Test instance at 0x0159FDF0>
Your second example won't actually work unless you already have an x and y in your namespace.
For instance, if you defined your class:
class Test:
def __init__(self):
self.x = x
self.y = y
and tried
x = Test()
it will throw a NameError.
However if you write:
x = 3
y = 4
test = Test()
then it will work. However, it's not a good idea to do such a thing. For the reason why read line 2:
In [72]: import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

In Python, methods should always take "one extra" argument, which is the reference to the instance the method is being called on. This is automatic in other languages such as Java, C#, etc. but Python is verbose about it.
That doesn't make sense. Where are x and y in that example? If you want the constructor to take two arguments which populate the object, define it as such. Otherwise, you're doing something else.

Python is different from languages like C++ and Java in that the object instance reference is passed explicitly.
That is, if you have an object which is an instance of the class and you want to invoke a method that operates on that instance (e.g., reads its fields), you use the self references as the object.
In c++ and Java, you have an implicit "this" reference that is present in the compiled version of your program but not in the source code. You use the static keyword to make it into a class method that does not have a "this".

Related

Python method calls in constructor and variable naming conventions inside a class

I try to process some data in Python and I defined a class for a sub-type of data. You can find a very simplified version of the class definition below.
class MyDataClass(object):
def __init__(self, input1, input2, input3):
"""
input1 and input2 are a 1D-array
input3 is a 2D-array
"""
self._x_value = None # int
self._y_value = None # int
self.data_array_1 = None # 2D array
self.data_array_2 = None # 1D array
self.set_data(input1, input2, input3)
def set_data(self, input1, input2, input3):
self._x_value, self._y_value = self.get_x_and_y_value(input1, input2)
self.data_array_1 = self.get_data_array_1(input1)
self.data_array_2 = self.get_data_array_2(input3)
#staticmethod
def get_x_and_y_value(input1, input2):
# do some stuff
return x_value, y_value
def get_data_array_1(self, input1):
# do some stuff
return input1[self._x_value:self._y_value + 1]
def get_data_array_2(self, input3):
q = self.data_array_1 - input3[self._x_value:self._y_value + 1, :]
return np.linalg.norm(q, axis=1)
I'm trying to follow the 'Zen of Python' and thereby to write beautiful code. I'm quite sceptic, whether the class definition above is a good pratice or not. While I was thinking about alternatives I came up with the following questions, to which I would like to kindly get your opinions and suggestions.
Does it make sense to define ''get'' and ''set'' methods?
IMHO, as the resulting data will be used several times (in several plots and computation routines), it is more convenient to create and store them once. Hence, I calculate the data arrays once in the constructor.
I do not deal with huge amount of data and therefore processing takes not more than a second, however I cannot estimate its potential implications on RAM if someone would use the same procedure for huge data.
Should I put the function get_x_and_y_value() out of the class scope and convert static method to a function?
As the method is only called inside the class definition, it is better to use it as a static method. If I should define it as a function, should I put all the lines relevant to this class inside a script and create a module of it?
The argument naming of the function get_x_and_y_value() are the same as __init__ method. Should I change it?
It would ease refactoring but could confuse others who read it.
In Python, you do not need getter and setter functions. Use properties instead. This is why you can access attributes directly in Python, unlike other languages like Java where you absolutely need to use getters and setters and to protect your attributes.
Consider the following example of a Circle class. Because we can use the #property decorator, we don't need getter and setter functions like other languages do. This is the Pythonic answer.
This should address all of your questions.
class Circle(object):
def __init__(self, radius):
self.radius = radius
self.x = 0
self.y = 0
#property
def diameter(self):
return self.radius * 2
#diameter.setter
def diameter(self, value):
self.radius = value / 2
#property
def xy(self):
return (self.x, self.y)
#xy.setter
def xy(self, xy_pair):
self.x, self.y = xy_pair
>>> c = Circle(radius=10)
>>> c.radius
10
>>> c.diameter
20
>>> c.diameter = 10
>>> c.radius
5.0
>>> c.xy
(0, 0)
>>> c.xy = (10, 20)
>>> c.x
10
>>> c.y
20

rename class variables in python without the self

Not sure how to quite phrase it, but here's the deal. I have a script where every variable is defined globally, but later I want to convert the script into a class for better encapsulation.
However, all the variables I used in the script needs to be converted into object variables. I would have changed something like
x = 5
into
self.x = 5
And after doing that all the functions in the script needs to be turned into methods of the class, however, most of the methods are mathematical formulas, and refactoring something as clean as
z = x ** y + x
into
z = self.x ** self.y + self.x
really hurts readability.
So as a solution to this I've been typing these really awkward re-naming at the beginning of the methods:
def method(self, ...):
x = self.x
y = self.y
...
It makes the formulas readable but typing all that re-naming is really painful, is there a more elegant way of doing this?
self is only a suggested name. I would encourage you to use it, but in some cases it is better to shorten it.
class A:
x = None
y = None
def calculate_z(s):
return s.x ** s.y + s.x
foo = A()
foo.x = 4
foo.y = 2
foo.calculate_z() # 20
Fun fact: you could even use unicode characters, like ® (in Python 3, that is).
def calculate_z(®):
return ®.x ** ®.y + ®.x
Well, there could be some other solutions, but they're all ugly hacks at most.
You can make the code possibly less awkward by using multiple assignment though:
x, y = self.x, self.y
In addition x and y are faster to use in CPython than self.x and self.y, because the latter ones would need a costly attribute lookup for every use.

Argument passing by reference to a class in python (á la C++), to modify it with the class methods

In this case, I want that the program print "X = changed"
class Clase:
def __init__(self,variable):
self.var = variable
def set_var(self):
self.var = 'changed'
X = 'unchanged'
V = Clase(X)
V.set_var()
print "X = ",X
All values are objects and are passed by reference in Python, and assignment changes the reference.
def myfunc(y):
y = 13
x = 42 # x now points at the integer object, 42
myfunc(y) # inside myfunc, y initially points to 42,
# but myfunc changes its y to point to a
# different object, 13
print(x) # prints 42, since changing y inside myfunc
# does not change any other variable
It's important to note here that there are no "simple types" as there are in other languages. In Python, integers are objects. Floats are objects. Bools are objects. And assignment is always changing a pointer to refer to a different object, whatever the type of that object.
Thus, it's not possible to "assign through" a reference and change someone else's variable. You can, however, simulate this by passing a mutable container (e.g. a list or a dictionary) and changing the contents of the container, as others have shown.
This kind of mutation of arguments through pointers is common in C/C++ and is generally used to work around the fact that a function can only have a single return value. Python will happily create tuples for you in the return statement and unpack them to multiple variables on the other side, making it easy to return multiple values, so this isn't an issue. Just return all the values you want to return. Here is a trivial example:
def myfunc(x, y, z):
return x * 2, y + 5, z - 3
On the other side:
a, b, c = myFunc(4, 5, 6)
In practice, then, there is rarely any reason to need to do what you're trying to do in Python.
In python list and dict types are global and are passed around by reference. So if you change the type of your variable X to one of those you will get the desired results.
[EDIT: Added use case that op needed]
class Clase:
def __init__(self,variable):
self.var = variable
def set_var(self):
self.var.test = 'changed'
class ComplicatedClass():
def __init__(self, test):
self.test = test
X = ComplicatedClass('unchanged')
print('Before:', X.test)
V = Clase(X)
V.set_var()
print("After:",X.test)
>>> Before: unchanged
>>> After: changed
strings are immutable so you could not change X in this way
... an alternative might be reassigning X in the global space... this obviously will fail in many many senarios (ie it is not a global)
class Clase:
def __init__(self,variable):
self.var = variable
def set_var(self):
globals()[self.var] = 'changed'
X = 'unchanged'
V = Clase('X')
V.set_var()
print "X = ",X
the other alternative is to use a mutable data type as suggested by Ashwin
or the best option is that this is probably not a good idea and you should likely not do it...

When to store things as part of an instance vs returning them?

I was just wondering when to store things as part of a class instance versus when to use a method to return things. For example, which of the following would be better:
class MClass():
def __init__(self):
self.x = self.get_x()
self.get_y()
self.z = None
self.get_z()
def get_x(self):
return 2
def get_y(self):
self.y = 5 * self.x
def get_z(self):
return self.get_x() * self.x
What are the conventions regarding this sort of thing and when should I assign things to self and when should I return values? Is this essentially a public/private sort of distinction?
You shouldn't return anything from __init__.
Python is not Java. You don't need to include get for everything.
If x is always 2 and y is always 10 and z is always 12, that is a lot of code.
Making some assumptions, I would write that class:
class MClass(object):
def __init__(self, x):
self.x = x
def y(self):
return self.x * 5
def z(self):
return self.x + self.y()
>>> c = MClass(2)
>>> c.x
2
>>> c.y() # note parentheses
10
>>> c.z()
12
This allows x to change later (e.g. c.x = 4) and still give the correct values for y and z.
You can use the #property decorator:
class MClass():
def __init__(self):
self.x = 2
#property
def y(self):
return 5 * self.x
#here a plus method for the setter
#y.setter
def y(self,value):
self.x = y/5
#property
def z(self):
return self.x * self.x
It's a good way of organizing yours acessors
There's no "conventions" regarding this, AFAIK, although there're common practices, different from one language to the next.
In python, the general belief is that "everything is public", and there's no reason at all to have a getter method just to return the value of a instance variable. You may, however, need such a method if you need to perform operations on the instance when such variable is accessed.
Your get_y method, for example, only makes sense if you need to recalculate the expression (5 * self.x) every time you access the value. Otherwise, you should simply define the y variable in the instance in __init__ - it's faster (because you don't recalculate the value every time) and it makes your intentions clear (because anyone looking at your code will immediately know that the value does not change)
Finally, some people prefer using properties instead of writing bare get/set methods. There's more info in this question
I read your question as a general Object Oriented development question, rather than a python specific one. As such, the general rule of member data would be to save the data as a member of the class only if it's relevant as part of a particular instance.
As an example, if you have a Screen object which has two dimensions, height and width. Those two should be stored as members. The area associated with a particular instance would return the value associated with a particular instance's height and width.
If there are certain things that seem like they should be calculated on the fly, but might be called over and over again, you can cache them as members as well, but that's really something you should do after you determine that it is a valid trade off (extra member in exchange for faster run time).
get should always do what it says. get_y() and get_z() don't do that.
Better do:
class MClass(object):
def __init__(self):
self.x = 2
#property
def y(self):
return 5 * self.x
#property
def z(self):
return self.x * self.x
This makes y and z always depend on the value of x.
You can do
c = MClass()
print c.y, c.z # 10, 4
c.x = 20
print c.y, c.z # 100, 400

Is it possible to change an instance's method implementation without changing all other instances of the same class? [duplicate]

This question already has answers here:
Override a method at instance level
(11 answers)
Closed 3 years ago.
I do not know python very much (never used it before :D), but I can't seem to find anything online. Maybe I just didn't google the right question, but here I go:
I want to change an instance's implementation of a specific method. When I googled for it, I found you could do it, but it changes the implementation for all other instances of the same class, for example:
def showyImp(self):
print self.y
class Foo:
def __init__(self):
self.x = "x = 25"
self.y = "y = 4"
def showx(self):
print self.x
def showy(self):
print "y = woohoo"
class Bar:
def __init__(self):
Foo.showy = showyImp
self.foo = Foo()
def show(self):
self.foo.showx()
self.foo.showy()
if __name__ == '__main__':
b = Bar()
b.show()
f = Foo()
f.showx()
f.showy()
This does not work as expected, because the output is the following:
x = 25
y = 4
x = 25
y = 4
And I want it to be:
x = 25
y = 4
x = 25
y = woohoo
I tried to change Bar's init method with this:
def __init__(self):
self.foo = Foo()
self.foo.showy = showyImp
But I get the following error message:
showyImp() takes exactly 1 argument (0 given)
So yeah... I tried using setattr(), but seems like it's the same as self.foo.showy = showyImp.
Any clue? :)
Since Python 2.6, you should use the types module's MethodType class:
from types import MethodType
class A(object):
def m(self):
print 'aaa'
a = A()
def new_m(self):
print 'bbb'
a.m = MethodType(new_m, a)
As another answer pointed out, however, this will not work for 'magic' methods of new-style classes, such as __str__().
This answer is outdated; the answer below works with modern Python
Everything you wanted to know about Python Attributes and Methods.
Yes, this is an indirect answer, but it demonstrates a number of techniques and explains some of the more intricate details and "magic".
For a "more direct" answer, consider python's new module. In particular, look at the instancemethod function which allows "binding" a method to an instance -- in this case, that would allow you to use "self" in the method.
import new
class Z(object):
pass
z = Z()
def method(self):
return self
z.q = new.instancemethod(method, z, None)
z is z.q() # true
If you ever need to do it for a special method (which, for a new-style class -- which is what you should always be using and the only kind in Python 3 -- is looked up on the class, not the instance), you can just make a per-instance class, e.g....:
self.foo = Foo()
meths = {'__str__': lambda self: 'peekaboo!'}
self.foo.__class__ = type('yFoo', (Foo,), meths)
Edit: I've been asked to clarify the advantages of this approach wrt new.instancemethod...:
>>> class X(object):
... def __str__(self): return 'baah'
...
>>> x=X()
>>> y=X()
>>> print x, y
baah baah
>>> x.__str__ = new.instancemethod(lambda self: 'boo!', x)
>>> print x, y
baah baah
As you can see, the new.instancemethod is totally useless in this case. OTOH...:
>>> x.__class__=type('X',(X,),{'__str__':lambda self:'boo!'})
>>> print x, y
boo! baah
...assigning a new class works great for this case and every other. BTW, as I hope is clear, once you've done this to a given instance you can then later add more method and other class attributes to its x.__class__ and intrinsically affect only that one instance!
If you're binding to the instance, you shouldn't include the self argument:
>>> class Foo(object):
... pass
...
>>> def donothing():
... pass
...
>>> f = Foo()
>>> f.x = donothing
>>> f.x()
>>>
You do need the self argument if you're binding to a class though:
>>> def class_donothing(self):
... pass
...
>>> foo.y = class_donothing
>>> f.y()
>>>
Your example is kind of twisted and complex, and I don't quite see what it has to do with your question. Feel free to clarify if you like.
However, it's pretty easy to do what you're looking to do, assuming I'm reading your question right.
class Foo(object):
def bar(self):
print('bar')
def baz():
print('baz')
In an interpreter ...
>>> f = Foo()
>>> f.bar()
bar
>>> f.bar = baz
>>> f.bar()
baz
>>> g = Foo()
>>> g.bar()
bar
>>> f.bar()
baz
Do Not Do This.
Changing one instance's methods is just wrong.
Here are the rules of OO Design.
Avoid Magic.
If you can't use inheritance, use delegation.
That means that every time you think you need something magic, you should have been writing a "wrapper" or Facade around the object to add the features you want.
Just write a wrapper.

Categories