I am working on a graph library in Python and I am defining my vetex this way:
class Vertex:
def __init__(self,key,value):
self._key = key
self._value = value
#property
def key(self):
return self._key
#key.setter
def key(self,newKey):
self._key = newKey
#property
def value(self):
return self._value
#value.setter
def value(self,newValue):
self.value = newValue
def _testConsistency(self,other):
if type(self) != type(other):
raise Exception("Need two vertexes here!")
def __lt__(self,other):
_testConsistency(other)
if self.index <= other.index:
return True
return False
......
Do I really have to define __lt__,__eq__,__ne__....all by my self? It is so verbose. Is there simpler way I can get around this?
Cheers.
Please dont use __cmp__ since it will be away in python 3.
functools.total_ordering can help you out here. It's meant to be a class decorator. You define one of __lt__(), __le__(), __gt__(), or __ge__() AND __eq__ and it fills in the rest.
As a side note:
Instead of writing this
if self.index <= other.index:
return True
return False
write this:
return self.index <= other.index
It's cleaner that way. :-)
Using functools.total_ordering, you only need to define one of the equality operators and one of the ordering operators. In Python < 3.2, you're out of luck, something has to define these operators as individual methods. Though you may be able to save some code by writing a simpler version of total_ordering yourself, if you need it in several places.
Related
I'd like to compare two objects of the same type with the dunder method _eq_ for equality. Every object stores values for "word", "pronunciation", "weight", and "source" and equality is reached, when everything is the same.
My solution looks like the following and works but it feels clunky and I am sure that there is a better way.
def __eq__(self, other):
if self.check_other(other): # checks of both objects are snstances of LexicalEntity
return_bool = True
if self.word != other.get_word():
return_bool = False
if self.weight != other.get_weight():
return_bool = False
if self.source != other.get_source():
return_bool = False
if self.pron != other.get_pron():
return_bool = False
return return_bool
Thanks for your help.
For starters, dispense with getters and setters in Python. That will make your code much less clunky and more idiomatic, i.e., you don't need other.get_word(), you just need other.word, and remove your definition of get_word, it is useless. Python != Java.
So, then for something like this, a typical implementation would be:
def __eq__(self, other):
if isinstance(other, LexicalEntity):
these_values = self.word, self.weight, self.source, self.pron
other_values = other.word, other.weight, other.source, other.pron
return these_values == other_values
return NotImplemented # important, you don't want to return None
Alternatively, you might also just use one long boolean expression:
def __eq__(self, other):
if isinstance(other, LexicalEntity):
return (
self.word == other.word and self.weight == other.weight
and self.source == other.source and self.pron == other.pron
)
return NotImplemented
I think this maybe is little more readable:
def __eq__(self, other):
if self.check_other(other):
attrs = ["word", "weight", "source", "pron"]
return all([getattr(self, attr) == getattr(other, attr) for attr for attrs])
But I guess it's a preference if we want more readable or more smart solution
Getters and setters don't make much sense in Python, you should start using the #property annotation instead, if you do have important validations - if you're just doing this for data encapsulation, Python principles are much more loose in that aspect, so just ditch getters/setters.
As for asserting equality, if you want to avoid manually referring to each attribute, the below reflection is appliable to virtually any case:
def __eq__(self, other):
if isinstance(other, self.__class__):
attrs = [
a for a in dir(self) if not a.startswith('_') and not callable(getattr(self, a))
]
return all([getattr(self, attr) == getattr(other, attr) for attr in attrs])
return NotImplemented
As #juanpa.arrivillaga already mentioned, returning the NotImplemented (not the same as raising NotImplementedError, as noted in the comments below) is important because if other is from a different class this stops you from returning None in the equality check. A better explanation of why return NotImplemented is the fallback in these cases is found in this answer.
I'd like to modify a class method to do some things in addition to the original method call. I have a toy example posted below.
Example:
class str2(str):
def __init__(self, val):
self.val = val
def upper(self):
print('conveting to upper')
return self.upper()
x = str2('a')
print(x.upper())
This does what I should have expected and gives a maximum recursion depth error. Is it possible to modify the upper method so that it prints some text before calling the actual str.upper method, while ideally keeping the name the same?
I've been wondering if this is the situation to use a decorator, but I am not familiar enough with them to have a clear idea on how to do this.
The solution would be:
class str2(str):
def __init__(self, val):
self.val = val
def upper(self):
print('conveting to upper')
return str.upper(self.val)
x = str2('a')
print(x.upper())
My point to the your code:
in upper function you just print it then go to same function again and again
this makes it that it will keep printing
it raises an error at the end because python basically has enough of this
My point to my code:
use the method-descriptor (<method 'upper' of 'str' objects>) to use it so it doesn't confuse it with self
use that because it will still be calling the real str class (not the metaclass)
I am also blaming myself that why i didn't think of:
class str2(str):
def __init__(self, val):
self.val = val
def upper(self):
print('conveting to upper')
return self.val.upper()
x = str2('a')
print(x.upper())
In the method str2.upper you are calling str2.upper which in turn calls str2.upper which... You see where this is going.
What you probably intended to so was to call str.upper from str2.upper. This is done by using super. Calling super() returns an object which delegates method calls to the parent classes.
class str2(str):
def upper(self):
print('converting to upper')
return super().upper()
Research "Mapping" and "decorators" - I think there's an easier/more pythonic way to do what you're trying to do.
As #Schalton stated, there is a way to do it without having to inherit from str by using decorators. Consider this snippet:
def add_text(func):
def wrapper(*args, **kwargs):
print('converting to upper')
return func(*args)
return wrapper
class str2:
def __init__(self, val):
self.val = val
#add_text
def upper(self):
return self.val.upper()
instance = str2('a')
print(instance.upper())
The great advantage of this is that the wrapper is reusable, e.g. if you have another class that you want to modify with the exact same behavior, you can just add the #decorator and don't have to redo all the work. Also, removing the additional functionality gets also easier.
I have an int-derived class with overloaded comparison operator.
In the body of the overloaded methods I need to use the original operator.
The toy example:
>>> class Derived(int):
... def __eq__(self, other):
... return super(Derived, self).__eq__(other)
works fine with Python 3.3+, but fails with Python 2.7 with exception AttributeError: 'super' object has no attribute '__eq__'.
I can think about several walkarrounds, which I found not very clean:
return int(self) == other
requires creation of a new int object just to compare it, while
try:
return super(Derived, self).__eq__(other)
except AttributeError:
return super(Derived, self).__cmp__(other) == 0
splits the control flow based on the Python version, which I find terribly messy (so is inspecting the Python version explicitly).
How can I access the original integer comparison in an elegant way working with Python 2.7 and 3.3+?
Python 2 and 3 are significantly different from each other so I think you should bite the bullet and check versions. That is only to be expected if you're trying to write code that works on both (sooner or later in my experience you find something you have to patch). To avoid any performance impact you could do something like:
from six import PY2
class Derived(int):
if PY2:
def __eq__(self, other):
return super(Derived, self).__cmp__(other) == 0
else:
def __eq__(self, other):
return super(Derived, self).__eq__(other)
That's what I'd do. If I really wanted to subclass int...
If you really don't want to, perhaps you could try:
class Derived(int):
def __eq__(self, other):
return (self ^ other) == 0
Obviously if you care about performance you'll have to do some profiling with the rest of your code and find out if either of them is significantly worse...
Both versions implement an __xor__ method, you could try this:
class Derived(int):
def __eq__(self, other):
return not super(Derived, self).__xor__(other)
I believe that you should define the __eq__ in the int before defining the class. For example:
int = 5
def int.__eq__(self, other):
return self.real == other
IntDerived = Derived(int)
This should give the super class an __eq__ attribute.
EDITED
The main idea worked, but it has been brought to my attention that the code isn't working. So: improved code:
class Derived(int):
def __eq__(self, other):
return self.real == other
Int = 5
D = Derived(Int)
D.__eq__(4) #Output: False
D.__eq__(5) #Output: True
using hasattr avoids creating a new int object, catching an exception or explicitly checking for the Python version.
The below code works on both Python 2.7 and 3.3+:
class Derived(int):
def __eq__(self, other):
return super(Derived, self).__cmp__(other) == 0 if hasattr(Derived, "__cmp__") else super(Derived, self).__eq__(other)
Still somewhat perplexed by python and it's magic functional programming, so I tend to find myself writing code that is more towards the Java paradigm of programming as opposed to Idiomatic Python.
My question is somewhat related to: How do I make a custom class a collection in Python
The only difference is I have nested objects (using composition). The VirtualPage object is comprised of a list of PhysicalPage objects. I have a function which can take a list of PhyscialPage objects and coalesce all of the details into a single named tuple I call PageBoundary. Essentially it's a serialization function which can spit out a tuple comprised of an integer range which represents the physical page and the line number in the page. From this I can easily sort and order VirtualPages among one another (that's the idea at least):
PageBoundary = collections.namedtuple('PageBoundary', 'begin end')
I also have a function which can take a PageBoundary namedtuple and de-serialize or expand the tuple into a list of PhysicalPages. It's preferable that these two data storage classes not change as it will break any downstream code.
Here is a snippet of my custom python2.7 class. It is composed of lot things one is list which contains a the object PhysicalPage:
class VirtualPage(object):
def __init__(self, _physical_pages=list()):
self.physcial_pages = _physcial_pages
class PhysicalPage(object):
# class variables: number of digits each attribute gets
_PAGE_PAD, _LINE_PAD = 10, 12
def __init__(self, _page_num=-1):
self.page_num = _page_num
self.begin_line_num = -1
self.end_line_num = -1
def get_cannonical_begin(self):
return int(''.join([str(self.page_num).zfill(PhysicalPage._PAGE_PAD),
str(tmp_line_num).zfill(PhysicalPage._LINE_PAD) ]))
def get_cannonical_end(self):
pass # see get_cannonical_begin() implementation
def get_canonical_page_boundaries(self):
return PageBoundary(self.get_canonical_begin(), self.get_canonical_end())
I would like to leverage some templated collection (from the python collections module) to easily sort and compare as list or set of VirtualPage classes. Also would like some advice on the layout of my data storage classes: VirtualPage and PhysicalPage.
Given either a sequence of VirtualPages or as in the example below:
vp_1 = VirtualPage(list_of_physical_pages)
vp_1_copy = VirtualPage(list_of_physical_pages)
vp_2 = VirtualPage(list_of_other_physical_pages)
I want to easily answer questions like this:
>>> vp_2 in vp_1
False
>>> vp_2 < vp_1
True
>>> vp_1 == vp_1_copy
True
Right off the bat it seems obvious that the VirtualPage class needs to call get_cannonical_page_boundaries or even implement the function itself. At a minimum it should loop over it's PhysicalPage list to implement the required functions (lt() and eq()) so I can compare b/w VirtualPages.
1.) Currently I'm struggling with implementing some of the comparison functions. One big obstacle is how to compare a tuple? Do I create my own lt() function by creating a custom class which extends some type of collection:
import collections as col
import functools
#total_ordering
class AbstractVirtualPageContainer(col.MutableSet):
def __lt__(self, other):
'''What type would other be?
Make comparison by first normalizing to a comparable type: PageBoundary
'''
pass
2.) Should the comparison function implementation exist in the VirtualPage class instead?
I was leaning towards some type of Set data structure as the properties of the data I'm modeling has the concept of uniqueness: i.e. physical page values cannot overlap and to some extend act as a linked list. Also would setter or getter functions, implemented via # decorator functions be of any use here?
I think you want something like the code below. Not tested; certainly not tested for your application or with your data, YMMV, etc.
from collections import namedtuple
# PageBoundary is a subclass of named tuple with special relational
# operators. __le__ and __ge__ are left undefined because they don't
# make sense for this class.
class PageBoundary(namedtuple('PageBoundary', 'begin end')):
# to prevent making an instance dict (See namedtuple docs)
__slots__ = ()
def __lt__(self, other):
return self.end < other.begin
def __eq__(self, other):
# you can put in an assertion if you are concerned the
# method might be called with the wrong type object
assert isinstance(other, PageBoundary), "Wrong type for other"
return self.begin == other.begin and self.end == other.end
def __ne__(self, other):
return not self == other
def __gt__(self, other):
return other < self
class PhysicalPage(object):
# class variables: number of digits each attribute gets
_PAGE_PAD, _LINE_PAD = 10, 12
def __init__(self, page_num):
self.page_num = page_num
# single leading underscore is 'private' by convention
# not enforced by the language
self._begin = self.page_num * 10**PhysicalPage._LINE_PAD + tmp_line_num
#self._end = ...however you calculate this... ^ not defined yet
self.begin_line_num = -1
self.end_line_num = -1
# this serves the purpose of a `getter`, but looks just like
# a normal class member access. used like x = page.begin
#property
def begin(self):
return self._begin
#property
def end(self):
return self._end
def __lt__(self, other):
assert(isinstance(other, PhysicalPage))
return self._end < other._begin
def __eq__(self, other):
assert(isinstance(other, PhysicalPage))
return self._begin, self._end == other._begin, other._end
def __ne__(self, other):
return not self == other
def __gt__(self, other):
return other < self
class VirtualPage(object):
def __init__(self, physical_pages=None):
self.physcial_pages = sorted(physcial_pages) if physical_pages else []
def __lt__(self, other):
if self.physical_pages and other.physical_pages:
return self.physical_pages[-1].end < other.physical_pages[0].begin
else:
raise ValueError
def __eq__(self, other):
if self.physical_pages and other.physical_pages:
return self.physical_pages == other.physical_pages
else:
raise ValueError
def __gt__(self, other):
return other < self
And a few observations:
Although there is no such thing as "private" members in Python classes, it is a convention to begin a variable name with a single underscore, _, to indicate it is not part of the public interface of the class / module/ etc. So, naming method parameters of public methods with an '_', doesn't seem correct, e.g., def __init__(self, _page_num=-1).
Python generally doesn't use setters / getters; just use the attributes directly. If attribute values need to be calculated, or other some other processing is needed use the #property decorator (as shown for PhysicalPage.begin() above).
It's generally not a good idea to initialize a default function argument with a mutable object. def __init__(self, physical_pages=list()) does not initialize physical_pages with a new empty list each time; rather, it uses the same list every time. If the list is modified, at the next function call physical_pages will be initialized with the modified list. See VirtualPages initializer for an alternative.
Recently I've been trying to figure out a solution to the 'expression problem' of choosing between implementing my code in OOP or FP (functional programming). The example I used to illustrate my problem was a Vector2D class. I could make a class that contains all the necessary functions for a 2D vector (dot product, magnitude, etc.), or I could make a set of functions that take a 2-tuple representing a vector. Which option do I chose?
To cope with this problem, I thought it might be nice to make a decorator that takes a class's methods and turns them into global functions. This is how I did it:
import types
def function(method):
method._function = True
return method
def make_functions(cls):
for key in cls.__dict__:
method = getattr(cls, key)
if not isinstance(method, types.FunctionType):
continue
if hasattr(method, '_function') and method._function:
globals()[method.__name__] = method
return cls
#make_functions
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return 'Vector(%g, %g)' % (self.x, self.y)
def __iter__(self):
for component in self.x, self.y:
yield component
def __getitem__(self, key):
return (self.x, self.y)[key]
def __setitem__(self, key, val):
if key == 0:
self.x = val
elif key == 1:
self.y = val
else:
print('not cool man')
def __add__(self, other):
x = self[0] + other[0]
y = self[1] + other[1]
return self.__class__(x, y)
__radd__ = __add__
def __sub__(self, other):
x = self[0] - other[0]
y = self[1] - other[1]
return self.__class__(x, y)
def __rsub__(self, other):
x = other[0] - self[0]
y = other[1] - self[1]
return self.__class__(x, y)
def __mul__(self, other):
x = other * self[0]
y = other * self[1]
return self.__class__(x, y)
__rmul__ = __mul__
#function
def dot_product(self, other):
return self[0]*other[1] + self[1]*other[0]
Now, dot_product is not only a method of the Vector2D class, but it is also a global function that takes in two vectors (or vector-like objects). This satisfies both the functional and object-oriented approaches to implementing an object like this. The only problem I can foresee this approach making is that any class that can be represented as another object like a tuple or a list, must be defined to work in the same ways as the objects which act like it. This is not so bad for a Vector that can also be a tuple, since all we have to do is define the __getitem__ and __iter__ methods, however I can see this getting wildly out of control for classes that have multiple contrasting implementations
Is this a fair solution to the problem? Is it bad practice or technique? Should I solely provide one or the other?
Python has a #staticmethod decorator for using class methods without an instantiation of that class. Simply annotate a class method with the static method wrapper (note the method now does not take a self reference), and you can call it from the class itself.
In your case, for the dot product, simply do:
class Vector2D():
# Magic methods here...
#staticmethod
def dot_product(a, b):
return a[0]*b[1] + a[1]*b[0]
Then, simply call Vector2D.dot_product(my_vector1, my_vector2) to use the function from the Vector2D class itself.
Assigning class methods to global functions sounds like a very dangerous, buggy, complex, and verbose solution. I would avoid it at all costs.