getting instance as argument python - python

I want to get class instance into function as argument, like code below. I know it doesn`t work.
class coordinate:
x = 1
y = 2
inst = coordinate()
def get_class(instance):
return instance.x + instance.y
get_class(inst)
Just getting instance`s inner variable is one of the solution, but the class that I want to use contains pretty diverse things. It makes code confusing
x = inst.x
y = inst.y
def get_class(x, y):
return x + y
get_class(x, y)
Is there any possible way?

First, let me point out that you probably want your x and y to be instance attributes and not class attributes.
Then if you want a function that takes a class instance as argument, what you want is probably an instance method.
class Coordinates:
def __init__(self, x, y):
self.x = x
self.y = y
def sum_coordinates(self):
return self.x + self.y
Coordinates(1, 2).sum_coordinates() # 3

Related

pass arguments inside splitted methods

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

Is this a correct universal __repr__ definition?

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.

TypeError: unbound method mult() must be called with calculadora instance as first argument (got int instance instead)

I get a
TypeError: unbound method mult() must be called with calculadora instance as first argument (got int instance instead)
when running my python file :
from __future__ import print_function
class calculadora:
def suma(x,y):
added = x + y
print(added)
def resta(x,y):
sub = x - y
print(sub)
def mult(x,y):
multi = x * y
print(multi)
calculadora.mult(3,5)
If you want to access methods as static methods(accesing methods without the clas instance), you need to decorate them with #staticmethod:
class calculadora:
#staticmethod
def suma(x, y):
added = x + y
print(added)
#staticmethod
def resta(x, y):
sub = x - y
print(sub)
#staticmethod
def mult(x, y):
multi = x * y
print(multi)
If you meant instance methods, you need to create instance first. and need to modify methods' signatures to include self as the first parameter:
class calculadora:
def suma(self, x, y): # not `self`, refering class instance
added = x + y
print(added)
def resta(self, x, y):
sub = x - y
print(sub)
def mult(self, x, y):
multi = x * y
print(multi)
c = calculadora() # Create instance
c.mult(3,5) # Access the method through instance, (not class)

How to assign class method to class attribute? [duplicate]

This question already has answers here:
Calling a function of a module by using its name (a string)
(18 answers)
Closed 7 years ago.
I'm trying to assign class methods to class attribute, so I can call the methods from string. When using the class I want to call it from string like:
A.MAP['add'](x, y)
A.MAP['subtract'](x, y)
This is my current code:
class A:
MAP = {
'add' : A.add(x, y),
'subtract' : A.subtract(x, y),
}
#classmethod
def add(cls, x, y)
return x + y
#classmethod
def subtract(cls, x, y)
return x - y
However the result shown error that A is not defined at the line of assigning A.add to MAP['add']. For short functions I can use lambda. However, in case of a longer function, how can I achieve this design?
Note that when you try:
class A:
MAP = {
'add' : A.add(x, y),
'subtract' : A.subtract(x, y),
}
you are trying to access e.g. A.add before the name A exists (the class isn't bound to the name until definition completes) and before the name add exists (you haven't defined that method yet). Everything at the top level of the class definition is done in order.
You need to put the class methods into the dictionary after the class has been defined (they don't become callable until definition is complete):
class A:
MAP = {}
#classmethod
def add(cls, x, y): # note colon
return x + y
#classmethod
def subtract(cls, x, y): # also here
return x - y
A.MAP['add'] = A.add
A.MAP['subtract'] = A.subtract
Note that, as neither class method uses cls, you could make them #staticmethods instead. Or just use functions - Python isn't Java, you don't need to put everything into a class.
Alternatively, you can use getattr to access attributes (including class methods) by name:
>>> class A:
#classmethod
def add(cls, x, y):
return x + y
#classmethod
def subtract(cls, x, y):
return x - y
>>> getattr(A, 'add')(1, 2)
3
Please do not program in python like that, instead use a more standard oop approach like this:
#!/usr/bin/env python
class A:
def __init__(self):
pass
#classmethod
def add(self, x, y):
return x + y
#classmethod
def subtract(self, x, y):
return x - y
if __name__ == "__main__":
a = A()
print a.add(1,2) # ans: 3
print a.subtract(2,1) # ans: 1

How to make a list object? instance has no attribute '__getitem__'

I am new in Python and in OOP in general. I have an error "...instance has no attribute '__getitem__'", and I understand that the object I have created is not a list. How can I make to be a list object. Here is the class file:
#!/usr/bin/python -tt
import math, sys, matrix, os
class Point:
'Class for points'
pointCount = 0
def __init__(self, x, y, z):
'initialise the Point from three coordinates'
self.x = x
self.y = y
self.z = z
Point.pointCount += 1
def __str__(self):
'print the Point'
return 'Point (%f, %f, %f)' %(self.x, self.y, self.z)
def copyPoint(self, distance):
'create another Point at distance from the self Point'
return Point(self.x + distance[0], self.y + distance[1], self.z + distance[2])
def __del__(self):
'delete the Point'
Point.pointCount -= 1
#print Point.pointCount
return '%s deleted' %self
I need to have it as a point with three coordinates inside (x, y, z), and those coordinates must be "callable" like in a list instance with [].
I have read similar topics but did not understand much. Please describe it in simple words and with examples.
Write a __getitem__ method:
def __getitem__(self, item):
return (self.x, self.y, self.z)[item]
This constructs a tuple of x, y, and z, and uses Python's own indexing facilities to access it.
Alternatively you could switch your own internal storage to be a tuple, and create properties for x, y and z:
def __init__(self, x, y, z):
self.coords = (x, y, z)
#property
def x(self): # sim. for y, z
return self.coords[0]
def __getitem__(self, item):
return self.coords[item]
I suggest you consider making your Point class using the collections.namedtuple factory function which will make it a subclass of the the built-in tuple class. This will save you some boiler-plate work. namedtuple class have attributes that can be accessed both by name, such as p.x and indexed, like p[0].
They are also very memory efficient like tuples, which may be important if you're going to have a lot of class instances.
You can further specialize what is returned by subclassing it, or use the verbose option to capture the source code and modify that as necessary.
There's an example in the documentation linked to above showing it being used to create a 2D Point class, which seems like it could be very helpful in your specific use-case.
Here's an example showing how one could define a custom 3D Point class via subclassing:
from collections import namedtuple
class Point(namedtuple('Point', 'x y z')):
__slots__ = () # prevent creation of instance dictionaries to save memory
point_count = 0 # instance counter
def __init__(self, *args):
super(Point, self).__init__(*args)
Point.point_count += 1
def distance(self, other):
return sum((self[i]-other[i])**2 for i in xrange(len(self))) ** 0.5
def copy_point(self, distance):
'create another Point at distance from the self Point'
return Point(*[dimension+distance for dimension in self])
p1 = Point(0, 0, 0)
print 'p1:', p1
p2 = p1.copy_point(20)
print 'p2: Point(%s)' % ', '.join(str(p2[i]) for i in xrange(len(p2)))
print 'distance p1 <-> p2: %.3f' % p1.distance(p2)
Output:
p1: Point(x=1, y=2, z=3)
p2: Point(21, 22, 23)
distance p1 <-> p2: 34.641
Note that by using namedtuple you don't have to implement a __getitem__() yourself, nor write a __str__() method. The only reason an __init__() was needed was because of the need to increment the class instance counter which was added -- something that namedtuples don't have or do by default.
Yes, you need to define __getitem__, but I would probably design the class as follows, which allows attribute and index access to the co-ordinates.
from collections import namedtuple
class Point(object):
def __init__(self, x, y, z):
self._coords = namedtuple('Coords', 'x y z')._make( (x, y, z) )
#property
def coords(self):
return self._coords
def __getitem__(self, item):
return self.coords[item]
def copy_point(self, distance):
return Point(*(el + distance for el in self.coords))
def __repr__(self):
return 'Point: {}'.format(self.coords)
p = Point(1, 2, 3)
p.copy_point(20), p.coords[0], p.coords.x
# (Point: Coords(x=21, y=22, z=23), 1, 1)

Categories

Resources