I am confused as to when the __index__ method of a class is called. I had assumed the method would be called when ever the object was used in an indexing operation. I am not seeing __index__ called when the object is a subclass of int.
In [1]: class foo(int):
...: def __new__(cls, value):
...: return int.__new__(cls, value)
...: def __index__(self):
...: return int(self)+1
In [2]: i=foo(0)
In [3]: i
Out[3]: 0
In [4]: i.__index__()
Out[4]: 1
In [5]: [0,1,2][:i.__index__()]
Out[5]: [0]
In [6]: [0,1,2][:i]
Out[6]: []
it appears that int(i) is being used as the index not i.__index__(). What have I misunderstood?
Edited to simplify and correct the example.
__index__ implements lossless conversion to int. Python only calls __index__ if it actually needs such a conversion. In your case, it doesn't need a conversion, because your i is already an int. Python just uses the int value directly.
If you want to see the code that handles this, it's under PyNumber_Index.
Related
I am trying to implement slice functionality for a class I am making that creates a vector representation.
I have this code so far, which I believe will properly implement the slice but whenever I do something like v[4] where v is a vector, python raises an error about not having enough arguments. So I am trying to figure out how to define the __getitem__ special method in my class to handle both plain indexes and slicing.
def __getitem__(self, start, stop, step):
index = start
if stop == None:
end = start + 1
else:
end = stop
if step == None:
stride = 1
else:
stride = step
return self.__data[index:end:stride]
The __getitem__() method will receive a slice object when the object is sliced. Simply look at the start, stop, and step members of the slice object in order to get the components for the slice.
>>> class C(object):
... def __getitem__(self, val):
... print val
...
>>> c = C()
>>> c[3]
3
>>> c[3:4]
slice(3, 4, None)
>>> c[3:4:-2]
slice(3, 4, -2)
>>> c[():1j:'a']
slice((), 1j, 'a')
I have a "synthetic" list (one where the data is larger than you would want to create in memory) and my __getitem__ looks like this:
def __getitem__(self, key):
if isinstance(key, slice):
# Get the start, stop, and step from the slice
return [self[ii] for ii in xrange(*key.indices(len(self)))]
elif isinstance(key, int):
if key < 0: # Handle negative indices
key += len(self)
if key < 0 or key >= len(self):
raise IndexError, "The index (%d) is out of range." % key
return self.getData(key) # Get the data from elsewhere
else:
raise TypeError, "Invalid argument type."
The slice doesn't return the same type, which is a no-no, but it works for me.
How to define the getitem class to handle both plain indexes and slicing?
Slice objects gets automatically created when you use a colon in the subscript notation - and that is what is passed to __getitem__. Use isinstance to check if you have a slice object:
from __future__ import print_function
class Sliceable(object):
def __getitem__(self, subscript):
if isinstance(subscript, slice):
# do your handling for a slice object:
print(subscript.start, subscript.stop, subscript.step)
else:
# Do your handling for a plain index
print(subscript)
Say we were using a range object, but we want slices to return lists instead of new range objects (as it does):
>>> range(1,100, 4)[::-1]
range(97, -3, -4)
We can't subclass range because of internal limitations, but we can delegate to it:
class Range:
"""like builtin range, but when sliced gives a list"""
__slots__ = "_range"
def __init__(self, *args):
self._range = range(*args) # takes no keyword arguments.
def __getattr__(self, name):
return getattr(self._range, name)
def __getitem__(self, subscript):
result = self._range.__getitem__(subscript)
if isinstance(subscript, slice):
return list(result)
else:
return result
r = Range(100)
We don't have a perfectly replaceable Range object, but it's fairly close:
>>> r[1:3]
[1, 2]
>>> r[1]
1
>>> 2 in r
True
>>> r.count(3)
1
To better understand the slice notation, here's example usage of Sliceable:
>>> sliceme = Sliceable()
>>> sliceme[1]
1
>>> sliceme[2]
2
>>> sliceme[:]
None None None
>>> sliceme[1:]
1 None None
>>> sliceme[1:2]
1 2 None
>>> sliceme[1:2:3]
1 2 3
>>> sliceme[:2:3]
None 2 3
>>> sliceme[::3]
None None 3
>>> sliceme[::]
None None None
>>> sliceme[:]
None None None
Python 2, be aware:
In Python 2, there's a deprecated method that you may need to override when subclassing some builtin types.
From the datamodel documentation:
object.__getslice__(self, i, j)
Deprecated since version 2.0: Support slice objects as parameters to the __getitem__() method. (However, built-in types in CPython currently still implement __getslice__(). Therefore, you have to override it in derived classes when implementing slicing.)
This is gone in Python 3.
To extend Aaron's answer, for things like numpy, you can do multi-dimensional slicing by checking to see if given is a tuple:
class Sliceable(object):
def __getitem__(self, given):
if isinstance(given, slice):
# do your handling for a slice object:
print("slice", given.start, given.stop, given.step)
elif isinstance(given, tuple):
print("multidim", given)
else:
# Do your handling for a plain index
print("plain", given)
sliceme = Sliceable()
sliceme[1]
sliceme[::]
sliceme[1:, ::2]
```
Output:
('plain', 1)
('slice', None, None, None)
('multidim', (slice(1, None, None), slice(None, None, 2)))
The correct way to do this is to have __getitem__ take one parameter, which can either be a number or a slice object.
So take the complex built-in type as an example. I am making my own version of Complex for educational purposes, however as of now, they aren't behaving the same way.
When I run
>>> a = (2+3j)
>>> a
(2+3j)
>>> from complex import Complex # My version of the type
>>> b = Complex(2, 3)
>>> b
<complex.Complex object at 0x10caeb0f0>
I want my class to output the same thing. I always thought that this was the purpose of the str magic method, but that only gets invoked when something is trying to convert the instance to string, which isn't happening in the example above. How to do this?
Use __repr__:
class Complex:
def __init__(self, i, j):
self.i = i
self.j = j
def __repr__(self):
return f'({self.i}, {self.j}j)'
b = Complex(2, 3)
print(b)
Output:
(2, 3j)
I'm trying to use PyContracts within a web application, so I have lots of custom-defined classes being passed around that I simply want to type check alongside other more traditional argument types. I'd like to use contractual programming (PyContracts) to accomplish this, for the sake of cleanliness and forced documentation.
When I reference a locally visible class by name, PyContracts doesn't seem to be aware of the type. For example:
from contracts import contract
class SomeClass:
pass
#contract
def f(a):
"""
:param a: Just a parameter
:type a: SomeClass
"""
print(a)
my_a = SomeClass()
f(my_a)
Raises the following error:
ContractSyntaxError: Unknown identifier 'SomeClass'. Did you mean 'np_complex64'? (at char 0), (line:1, col:1)
I know I can use new_contract to custom-define names and bind them to classes, but that's a lot of hassle to do for every type. I want to use the docstring syntax for PyContracts if at all possible, and I definitely need to use the string-defined contract format since I'm using boolean type logic ("None|str|SomeClass"). How do I accomplish this with local types and minimal intrusion into the rest of my codebase?
I hacked together a magic decorator that adds types before creating the contract. For anyone that's interested, it seems to work, but it's probably pretty slow if you define a large number of functions:
def magic_contract(*args, **kwargs):
# Check if we got called without arguments, just the function
func = None
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
func = args[0]
args = tuple()
def inner_decorator(f):
for name, val in f.__globals__.items():
if isinstance(val, type):
new_contract(name, val)
return contract(*args, **kwargs)(f)
if func:
return inner_decorator(func)
return inner_decorator
And some test runs:
In [3]: class SomeClass:
...: pass
...:
In [4]: #magic_contract
...: def f(a):
...: """
...:
...: :param a: Some parameter
...: :type a: None|SomeClass
...: """
...: print(a)
...:
In [5]: f(None)
None
In [6]: f(SomeClass())
<__main__.SomeClass object at 0x7f1fa17c8b70>
In [7]: f(2)
...
ContractNotRespected: Breach for argument 'a' to f().
...
In [8]: #magic_contract(b='int|SomeClass')
...: def g(b):
...: print(type(b))
...:
In [9]: g(2)
<class 'int'>
In [10]: g(SomeClass())
<class '__main__.SomeClass'>
In [11]: g(None)
...
ContractNotRespected: Breach for argument 'b' to g().
...
I think the concept is called overloading.
Right now I'm writing a class that will provide getter and setter methods, and am stuck on a design issue.
Both methods are one-liners that simply set a value, or return a value.
def set_number(self, num):
self.count = num
def get_number(self):
return self.count
Would it be better to save space and make the class "look" smaller by doing something that will basically combine the two methods into one and then just decide which line should be executed depending on whether the num argument is provided?
Or should I just stick to clarity and keep them separated? Some people feel that it's a "waste of space" to keep all these one-liners on their own, while others disagree and prefer splitting them up.
Any reasons why I would choose one or the other?
In Python, you should prefer not to use getters and setters at all. Instead simply reference the count attribute directly, e.g. print instance.count or instance.count = 5
The point of getters and setters in other languages is for encapsulation and for future-proofing in case you need to add logic to the getters or setters. In Python you can accomplish this by later using property, which will not break your existing API.
#property
def number(self):
# do extra logic if necessary
return self.count
Properties can also have setters - see: http://docs.python.org/library/functions.html#property
Python is not Java. =)
Extra bonus reading material:
http://tomayko.com/writings/getters-setters-fuxors
http://eli.thegreenplace.net/2009/02/06/getters-and-setters-in-python/
Generally in python it's very bad style to use explicit getter/setter methods. Just do something like this:
In [1]: class Foo(object):
...: def __init__(self):
...: self.num = 1
...:
...:
In [2]: f = Foo()
In [3]: f.num
Out[3]: 1
In [4]: f.num = 2
In [5]: f.num
Out[5]: 2
If you really need logic, you can preserve this same API at a later date by using properties. Notice how the same interface is preserved below while still adding functionality.
In [8]: class Foo(object):
...: def __init__(self):
...: self._num = 1
...: #property
...: def num(self):
...: return self._num
...: #num.setter
...: def num(self, num):
...: if num < 0:
...: raise ValueError("Your Foo would be too small!")
...: self._num = num
...:
...:
In [10]: f = Foo()
In [11]: f.num
Out[11]: 1
In [12]: f.num = 2
In [13]: f.num
Out[13]: 2
In [14]: f.num = -1
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
/home/Daenyth/<ipython console> in <module>()
/home/Daenyth/<ipython console> in num(self, num)
ValueError: Your Foo would be too small!
Regarding "overloading" -- That term does not apply here. That is the term for changing the behavior of operators like +, ==, and so on, by changing the definition for those methods on your object. You can do some overloading in python via __cmp__, __add__, and so on.
I would leave it as two separate methods for the sake of code readabilty and maintainabilty.
I don't think so, but I thought I'd ask just in case. For example, for use in a class that encapsulates an int:
i = IntContainer(3)
i + 5
And I'm not just interested in this int example, I was looking for something clean and general, not overriding every int and string method.
Thanks, sunqiang. That's just what I wanted. I didn't realize you could subclass these immutable types (coming from C++).
class IntContainer(int):
def __init__(self,i):
#do stuff here
self.f = 4
def MultiplyBy4(self):
#some member function
self *= self.f
return self
print 3+IntContainer(3).MultiplyBy4()
This should do what you need:
class IntContainer(object):
def __init__(self, x):
self.x = x
def __add__(self, other):
# do some type checking on other
return self.x + other
def __radd__(self, other):
# do some type checking on other
return self.x + other
Output:
In [6]: IntContainer(3) + 6
Out[6]: 9
In [7]: 6 + IntContainer(3)
Out[7]: 9
For more information search for "radd" in the following docs:
http://docs.python.org/reference/datamodel.html#special-method-names
You'll find other such methods for "right addition", "right subtraction", etc.
Here's another link covering the same operators:
http://www.siafoo.net/article/57#reversed-binary-operations
By the way, Python does have casting operators:
http://www.siafoo.net/article/57#casts
But, they won't accomplish what you need in your example (basically because methods don't have any type annotation for parameters, so there's no good way to cast implicitly). So you can do this:
class IntContainer2(object):
def __init__(self, x):
self.x = x
def __int__(self):
return self.x
ic = IntContainer2(3)
print int(ic) + 6
print 6 + int(ic)
But this will fail:
print ic + 6 # error: no implicit coercion
You won't get conversion operators like in C++ because Python does not have this kind of strong static type system. The only automatic conversion operators are those which handle default numeric values (int/float); they are predefined in the language and cannot be changed.
Type "conversion" is usually done by constructors/factories. You can then overload standard methods like __add__ to make it work more like other classes.
sometimes maybe just subclass from int directly is enough. then __add__ and __radd__ need not costuming.
class IntContainer(int):
pass
i = IntContainer(3)
print i + 5 # 8
print 4 + i # 7
class StrContainer(str):
pass
s = StrContainer(3)
print s + '5' # 35
print '4' + s # 43
Is this what you need?
In [1]: class IntContainer(object):
...: def __init__(self, val):
...: self.val = val
...: def __add__(self, val):
...: return self.val + val
...: def __radd__(self, val):
...: return self.val + val
...:
...:
In [2]: i = IntContainer(3)
In [3]: i + 5
Out[3]: 8
In [4]:
Sorry for coming to the party 8.5 years late.
You can derive from an immutable (ie. int). You cannot define __init__ because the immutable is already created and can't be modified (by definition). This is where __new__ comes in handy.
class IntContainer(int):
def __new__ (cls, val):
ival = int.__new__(cls, val)
ival._rval = 'IntContainer(%d)' % ival
return ival
def __repr__ (self):
return self._rval
In [1]: i = IntContainer(3)
In [2]: i
Out[2]: IntContainer(3)
In [3]: repr(i)
Out[3]: 'IntContainer(3)'
In [4]: str(i)
Out[4]: '3'
In [5]: i + 5
Out[5]: 8
In [6]: 4 + i
Out[6]: 7
In [7]: int(i)
Out[7]: 3
In [8]: float(i)
Out[8]: 3.0
Now, to answer your question about conversion operators. You can also define __int__, __long__, __float__, and obviously, __str__. To convert or cast to an arbitrary object, you will most likely need to modify the other object to get what you want. You can use the __new__ method of that other object. Or if the other object is already created, try using __call__.