When designing classes, I found it awkward to place default argument values in the __init__ method, as in:
class Class1(object):
def __init__(self, y=2, z=3):
self.y = self.manip_y(y)
self.z = self.manip_z(z)
def manip_y(self, y):
return y * 10
def manip_z(self, z):
return z - 30
Is it considered better practice to add **kwargs to function signatures to place default values in the function signatures as well?:
class Class2(object):
def __init__(self, **kwargs):
self.y = self.manip_y(**kwargs)
self.z = self.manip_z(**kwargs)
def manip_y(self, y=2, **kwargs):
return y * 10
def manip_z(self, z=3, **kwargs):
return z - 30
It's better to add default values in the __init__ signature -- that way someone only needs to look at the signature to figure out the options. And, in example 2, the default values are now hidden in other functions. Additionally, your documentation will be simpler.
do not do this. why? because it forces you to read not only the __init__ code to understand how to create the object but also all of the functions called therein.
Related
I need to split class methods in several files. Functionality need to by that I can pass inside method all variables defined in self and receive new self variables defined inside the method.
My attempt:
Below code works, but I don't know if this is the best/proper solution.
Base:
from calculate_function import function
class Data():
def __init__(self):
self.y = -2
self.x = 1
self.z, self.result = function(self)
calculate_function.py:
def function(self):
z = 2
result = z + self.x
return z, result
For above I pass self inside new function for collect all init variables, then define new self variable/results.
There will by much more functions inside different files that will done some calculations and create new variables for instance of class.
Question
What I need is to pass each created self variable to each function.
For above code the solution is proper defined or there is better option to this?
If you want to externalize some part of your class code to external functions, it's better to write those as pure functions and keep the attribute access (and even more attributes updates) within the class code itself - this makes the code much easier to test, read and maintain. In you case this would looks like:
from calculate_function import function
class Data():
def __init__(self):
self.y = -2
self.x = 1
self.z, self.result = function(self.x)
calculate_function.py:
def function(x):
z = 2
result = z + x
return z, result
The points here are that 1/ you can immediatly spot the creation of attributes z and result and 2/ you can test function() without a Data instance.
I need to split class methods in several files.
This often means your class has too many responsabilities. Some parts of it can be delegated to pure functions like shown above. Some other parts, that need access to a common subset of your class attributes, can be delegated to other, smaller, specialized classes - but preferably using composition / delegation instead of inheritance (depending on concrete use cases of course).
You dont need pass self inside the function
Why not do it like this:
class Data():
def __init__(self):
self.y = -2
self.x = 1
self.function()
def function(self):
self.z = 2
self.result = self.z + self.x
Do wish to use another Class function or just a stand alone function?
Here is solution, using class inheritance:
-- function1.py --
class FunctionClass1():
def function1(self):
self.result = self.x + self.y
-- function2.py --
class FunctionClass2():
def function2(self):
self.result = self.result + self.z
-- data.py --
from function1 import FunctionClass1
from function2 import FunctionClass2
class Data(FunctionClass1, FunctionClass2):
def __init__(self):
self.x = 1
self.y = 2
self.z = 3
self.function1()
self.function2()
For a long time I have been puzzled by Alex Martelli's remark about:
(...) the fuzzy unattainable goal of making repr's returned value
acceptable as input to eval!
So I gave it a try and came up with this:
class Sic():
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
self.method_var = lambda x, y, z : x + y + z
def __repr__(self):
def right_quotes(value):
return repr(value).translate(str.maketrans('\'\"', '\"\''))
from inspect import signature
class_sig = signature(self.__class__)
fields = tuple('{}={}'.format(k,right_quotes(v)) for k,v in self.__dict__.items() if k in class_sig.parameters)
return self.__class__.__name__ + str(tuple(sorted(fields))).replace("\'","")
Is this a correct general implementation of __repr__? If not could you give an example where it fails?
(I have improved the original version with the suggestion of Barmar, and responding to the objection of Kuco 23. I am looking here to a most general solution, even if it involves using introspection.)
What the quote means is that, when a string returned from the __repr__ method is ran on a python interpreter, it should evaluate to the object at its initialization stage.
The code you provided has a couple of faults.
Any object encoded in the __repr__ return string, should also be represented with their __repr__ method.
And also the self.__dict__.items() will return (name, value) pair for every attribute name set to the object self. The problem here is that some of those object were not used for the self's initialization. For example if your code was modified as
class Sic():
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
self.method_var = someFunction(x, y, z)
def __repr__(self):
fields = tuple("{}={}".format(k, v) for k, v in self.__dict__.items())
return self.__class__.__name__ + str(tuple(sorted(fields))).replace("\'","")
the repr method would return Sic(x=x0, y=y0, z=z0, method_var=mv0), even though that string's evaluation would be invalid, as the __init__ method only takes 3 arguments.
The safest option would be to implement the __repr__ method for any class you implement separately, as in
class Sic():
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __repr__(self):
args = map(repr, (self.x, self.y, self.z))
return f"Sic({', '.join(args)})"
If you insist on defining a __repr__ method for a custom class, you would have to know for each object, which arguments the __init__ method takes in, which would probably require some additional modifications to every class and make the code more complex.
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).
I'm new to Python and am only now starting to see the uses of self and would like to know if I am using it correctly. I have some sample code below and was wondering if someone could just skim through and see if it's the correct usage. I'm not sure if it's correct because I seem to be needing to use self a lot but perhaps that is just the style of the language. Thank You
Code
from tkinter import Canvas
class BouncyBall:
def __init__(self):
self.x = 0
self.y = 0
self.d = 15
self.color = 'blue'
self.speed = 2
self.move_left = False
self.move_right = False
def __init__(self, x, y, d, color):
self.x = x
self.y = y
self.d = d
self.color = color
self.speed = 2
self.move_left = False
self.move_right = False
#Accessor Methods
def get_x(self):
return self.x
def get_y(self):
return self.y
def get_diameter(self):
return self.d
def get_color(self):
return self.color
def get_speed(self):
return self.speed
def moving_right(self):
return self.move_right
def moving_left(self):
return self.move_left
#Mutator Methods
def set_x(self, x):
self.x = x
def set_y(self, y):
self.y = y
def set_diameter(self, d):
self.d = d
def set_color(self, color):
self.color = color
def set_speed(self, speed):
self.speed = speed
def set_move_right(self, move_right):
self.move_right = move_right
def set_move_left(self, move_left):
self.move_left = move_left
def draw_ball(self, canvas):
if isinstance(canvas, Canvas):
canvas.create_oval(self.x, self.y, self.x + self.d, self.y + self.d, fill=self.color)
else:
print("Improper Parameter Sent In")
You are using self correctly. It does tend to appear a lot in Python compared with other languages like C++ where the this parameter is implicit.
However, in Python it is not conventional to write get() and set() methods for everything, as you have done. You can reduce your code quite a bit by removing those--and remove a lot of selfs in the process.
Well, first off your __init__ is wrong. Python doesn't allow two definitions of a function/method with the same name in the same namespace, whether or not the prototype differs. I'd suggest dropping your first definition, and changing the def line of the second to:
def __init__(self, x=0, y=0, d=15, color='blue'):
which will do what you wanted (allow you to initialize without arguments by using default values).
You also probably want to drop all your set_ and get_ methods. If the attributes are read/write, just access them normally without getters and setters. If at some later point you need to make them read-only, or compute them, you can rename the attribute to have a leading underscore (e.g. _x) and use #property decorators to continue providing attribute-like access (with or without writability). That would instantly remove the vast majority of (unnecessary) accessor and mutator methods that make you reference self so often. For example, if x should be read-only, you'd set self._x = x in your __init__, then define a property:
#property
def x(self):
return self._x
and users would continue to read it as if it were a simple attribute, they just couldn't write it by accident (they could directly write _x, but that's their problem; Python's philosophy is that we're all adults, and if you ignore the convention that underscore prefixes are internal implementation details, the consequences are on your head).
Otherwise, yes, you'll be referencing self a lot. Python prefers explicit namespacing to implicit, so you use self to differentiate between instance access and scoped variable access. If you are going to be using a given variable a lot (and it won't change during the course of a method), you can cache it to a local name and use the local name unqualified, e.g.:
def some_method(self):
# We use x a lot and never change it, so cache up front:
x = self.x
# Can read cached x over and over without qualification for rest of method
EDIT2: Thank you all for your help!
EDIT: on adding #staticmethod, it works. However I am still wondering why i am getting a type error here.
I have just started OOPS and am completely new to it. I have a very basic question regarding the different ways I can call a function from a class.
I have a testClass.py file with the code:
class MathsOperations:
def __init__ (self, x, y):
self.a = x
self.b = y
def testAddition (self):
return (self.a + self.b)
def testMultiplication (self):
return (self.a * self.b)
I am calling this class from another file called main.py with the following code:
from testClass import MathsOperations
xyz = MathsOperations(2, 3)
print xyz.testAddition()
This works without any issues. However, I wanted to use the class in a much simpler way.
I have now put the following code in the testClass.py file. I have dropped the init function this time.
class MathsOperations:
def testAddition (x, y):
return x + y
def testMultiplication (a, b):
return a * b
calling this using;
from testClass import MathsOperations
xyz = MathsOperations()
print xyz.testAddition(2, 3)
this doesn't works. Can someone explain what is happening wrongly in case 2? How do I use this class?
The error i get is "TypeError: testAddition() takes exactly 2 arguments (3 given)"
you have to use self as the first parameters of a method
in the second case you should use
class MathOperations:
def testAddition (self,x, y):
return x + y
def testMultiplication (self,a, b):
return a * b
and in your code you could do the following
tmp = MathOperations()
print tmp.testAddition(2,3)
if you use the class without instantiating a variable first
print MathOperation.testAddtion(2,3)
it gives you an error "TypeError: unbound method"
if you want to do that you will need the #staticmethod decorator
For example:
class MathsOperations:
#staticmethod
def testAddition (x, y):
return x + y
#staticmethod
def testMultiplication (a, b):
return a * b
then in your code you could use
print MathsOperations.testAddition(2,3)
disclaimer: this is not a just to the point answer, it's more like a piece of advice, even if the answer can be found on the references
IMHO: object oriented programming in Python sucks quite a lot.
The method dispatching is not very straightforward, you need to know about bound/unbound instance/class (and static!) methods; you can have multiple inheritance and need to deal with legacy and new style classes (yours was old style) and know how the MRO works, properties...
In brief: too complex, with lots of things happening under the hood. Let me even say, it is unpythonic, as there are many different ways to achieve the same things.
My advice: use OOP only when it's really useful. Usually this means writing classes that implement well known protocols and integrate seamlessly with the rest of the system. Do not create lots of classes just for the sake of writing object oriented code.
Take a good read to this pages:
http://docs.python.org/reference/datamodel.html
http://docs.python.org/tutorial/classes.html
you'll find them quite useful.
If you really want to learn OOP, I'd suggest starting with a more conventional language, like Java. It's not half as fun as Python, but it's more predictable.
class MathsOperations:
def __init__ (self, x, y):
self.a = x
self.b = y
def testAddition (self):
return (self.a + self.b)
def testMultiplication (self):
return (self.a * self.b)
then
temp = MathsOperations()
print(temp.testAddition())
Your methods don't refer to an object (that is, self), so you should
use the #staticmethod decorator:
class MathsOperations:
#staticmethod
def testAddition (x, y):
return x + y
#staticmethod
def testMultiplication (a, b):
return a * b
You need to have an instance of a class to use its methods. Or if you don't need to access any of classes' variables (not static parameters) then you can define the method as static and it can be used even if the class isn't instantiated. Just add #staticmethod decorator to your methods.
class MathsOperations:
#staticmethod
def testAddition (x, y):
return x + y
#staticmethod
def testMultiplication (a, b):
return a * b
docs: http://docs.python.org/library/functions.html#staticmethod