I'm trying to create a class that returns a value, not self.
I will show you an example comparing with a list:
>>> l = list()
>>> print(l)
[]
>>> class MyClass:
>>> pass
>>> mc = MyClass()
>>> print mc
<__main__.MyClass instance at 0x02892508>
I need that MyClass returns a list, like list() does, not the instance info. I know that I can make a subclass of list. But is there a way to do it without subclassing?
I want to imitate a list (or other objects):
>>> l1 = list()
>>> l2 = list()
>>> l1
[]
>>> l2
[]
>>> l1 == l2
True
>>> class MyClass():
def __repr__(self):
return '[]'
>>> m1 = MyClass()
>>> m2 = MyClass()
>>> m1
[]
>>> m2
[]
>>> m1 == m2
False
Why is m1 == m2 False? This is the question.
I'm sorry if I don't respond to all of you. I'm trying all the solutions you give me. I cant use def, because I need to use functions like setitem, getitem, etc.
I think you are very confused about what is occurring.
In Python, everything is an object:
[] (a list) is an object
'abcde' (a string) is an object
1 (an integer) is an object
MyClass() (an instance) is an object
MyClass (a class) is also an object
list (a type--much like a class) is also an object
They are all "values" in the sense that they are a thing and not a name which refers to a thing. (Variables are names which refer to values.) A value is not something different from an object in Python.
When you call a class object (like MyClass() or list()), it returns an instance of that class. (list is really a type and not a class, but I am simplifying a bit here.)
When you print an object (i.e. get a string representation of an object), that object's __str__ or __repr__ magic method is called and the returned value printed.
For example:
>>> class MyClass(object):
... def __str__(self):
... return "MyClass([])"
... def __repr__(self):
... return "I am an instance of MyClass at address "+hex(id(self))
...
>>> m = MyClass()
>>> print m
MyClass([])
>>> m
I am an instance of MyClass at address 0x108ed5a10
>>>
So what you are asking for, "I need that MyClass return a list, like list(), not the instance info," does not make any sense. list() returns a list instance. MyClass() returns a MyClass instance. If you want a list instance, just get a list instance. If the issue instead is what do these objects look like when you print them or look at them in the console, then create a __str__ and __repr__ method which represents them as you want them to be represented.
Update for new question about equality
Once again, __str__ and __repr__ are only for printing, and do not affect the object in any other way. Just because two objects have the same __repr__ value does not mean they are equal!
MyClass() != MyClass() because your class does not define how these would be equal, so it falls back to the default behavior (of the object type), which is that objects are only equal to themselves:
>>> m = MyClass()
>>> m1 = m
>>> m2 = m
>>> m1 == m2
True
>>> m3 = MyClass()
>>> m1 == m3
False
If you want to change this, use one of the comparison magic methods
For example, you can have an object that is equal to everything:
>>> class MyClass(object):
... def __eq__(self, other):
... return True
...
>>> m1 = MyClass()
>>> m2 = MyClass()
>>> m1 == m2
True
>>> m1 == m1
True
>>> m1 == 1
True
>>> m1 == None
True
>>> m1 == []
True
I think you should do two things:
Take a look at this guide to magic method use in Python.
Justify why you are not subclassing list if what you want is very list-like. If subclassing is not appropriate, you can delegate to a wrapped list instance instead:
class MyClass(object):
def __init__(self):
self._list = []
def __getattr__(self, name):
return getattr(self._list, name)
# __repr__ and __str__ methods are automatically created
# for every class, so if we want to delegate these we must
# do so explicitly
def __repr__(self):
return "MyClass(%s)" % repr(self._list)
def __str__(self):
return "MyClass(%s)" % str(self._list)
This will now act like a list without being a list (i.e., without subclassing list).
>>> c = MyClass()
>>> c.append(1)
>>> c
MyClass([1])
If what you want is a way to turn your class into kind of a list without subclassing list, then just make a method that returns a list:
def MyClass():
def __init__(self):
self.value1 = 1
self.value2 = 2
def get_list(self):
return [self.value1, self.value2...]
>>>print MyClass().get_list()
[1, 2...]
If you meant that print MyClass() will print a list, just override __repr__:
class MyClass():
def __init__(self):
self.value1 = 1
self.value2 = 2
def __repr__(self):
return repr([self.value1, self.value2])
EDIT:
I see you meant how to make objects compare. For that, you override the __cmp__ method.
class MyClass():
def __cmp__(self, other):
return cmp(self.get_list(), other.get_list())
Use __new__ to return value from a class.
As others suggest __repr__,__str__ or even __init__ (somehow) CAN give you what you want, But __new__ will be a semantically better solution for your purpose since you want the actual object to be returned and not just the string representation of it.
Read this answer for more insights into __str__ and __repr__
https://stackoverflow.com/a/19331543/4985585
class MyClass():
def __new__(cls):
return list() #or anything you want
>>> MyClass()
[] #Returns a true list not a repr or string
class MyClass():
def __init__(self, a, b):
self.value1 = a
self.value2 = b
def __call__(self):
return [self.value1, self.value2]
Testing:
>>> x = MyClass('foo','bar')
>>> x()
['foo', 'bar']
You are describing a function, not a class.
def Myclass():
return []
the worked proposition for me is __call__ on class who create list of little numbers:
import itertools
class SmallNumbers:
def __init__(self, how_much):
self.how_much = int(how_much)
self.work_list = ['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉']
self.generated_list = ['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉']
start = 10
end = 100
for cmb in range(2, len(str(self.how_much)) + 1):
self.ListOfCombinations(is_upper_then=start, is_under_then=end, combinations=cmb)
start *= 10
end *= 10
def __call__(self, number, *args, **kwargs):
return self.generated_list[number]
def ListOfCombinations(self, is_upper_then, is_under_then, combinations):
multi_work_list = eval(str('self.work_list,') * combinations)
nbr = 0
for subset in itertools.product(*multi_work_list):
if is_upper_then <= nbr < is_under_then:
self.generated_list.append(''.join(subset))
if self.how_much == nbr:
break
nbr += 1
and to run it:
if __name__ == '__main__':
sm = SmallNumbers(56)
print(sm.generated_list)
print(sm.generated_list[34], sm.generated_list[27], sm.generated_list[10])
print('The Best', sm(15), sm(55), sm(49), sm(0))
result
['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉', '₁₀', '₁₁', '₁₂', '₁₃', '₁₄', '₁₅', '₁₆', '₁₇', '₁₈', '₁₉', '₂₀', '₂₁', '₂₂', '₂₃', '₂₄', '₂₅', '₂₆', '₂₇', '₂₈', '₂₉', '₃₀', '₃₁', '₃₂', '₃₃', '₃₄', '₃₅', '₃₆', '₃₇', '₃₈', '₃₉', '₄₀', '₄₁', '₄₂', '₄₃', '₄₄', '₄₅', '₄₆', '₄₇', '₄₈', '₄₉', '₅₀', '₅₁', '₅₂', '₅₃', '₅₄', '₅₅', '₅₆']
₃₄ ₂₇ ₁₀
The Best ₁₅ ₅₅ ₄₉ ₀
Related
I have inherited a project with many large classes constituent of nothing but class objects (integers, strings, etc). I'd like to be able to check if an attribute is present without needed to define a list of attributes manually.
Is it possible to make a python class iterable itself using the standard syntax? That is, I'd like to be able to iterate over all of a class's attributes using for attr in Foo: (or even if attr in Foo) without needing to create an instance of the class first. I think I can do this by defining __iter__, but so far I haven't quite managed what I'm looking for.
I've achieved some of what I want by adding an __iter__ method like so:
class Foo:
bar = "bar"
baz = 1
#staticmethod
def __iter__():
return iter([attr for attr in dir(Foo) if attr[:2] != "__"])
However, this does not quite accomplish what I'm looking for:
>>> for x in Foo:
... print(x)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'classobj' object is not iterable
Even so, this works:
>>> for x in Foo.__iter__():
... print(x)
bar
baz
Add the __iter__ to the metaclass instead of the class itself (assuming Python 2.x):
class Foo(object):
bar = "bar"
baz = 1
class __metaclass__(type):
def __iter__(self):
for attr in dir(self):
if not attr.startswith("__"):
yield attr
For Python 3.x, use
class MetaFoo(type):
def __iter__(self):
for attr in dir(self):
if not attr.startswith("__"):
yield attr
class Foo(metaclass=MetaFoo):
bar = "bar"
baz = 1
this is how we make a class object iterable. provide the class with a iter and a next() method, then you can iterate over class attributes or their values.you can leave the next() method if you want to, or you can define next() and raise StopIteration on some condition.
e.g:
class Book(object):
def __init__(self,title,author):
self.title = title
self.author = author
def __iter__(self):
for each in self.__dict__.values():
yield each
>>> book = Book('The Mill on the Floss','George Eliot')
>>> for each in book: each
...
'George Eliot'
'The Mill on the Floss'
this class iterates over attribute value of class Book.
A class object can be made iterable by providing it with a getitem method too.
e.g:
class BenTen(object):
def __init__(self, bentenlist):
self.bentenlist = bentenlist
def __getitem__(self,index):
if index <5:
return self.bentenlist[index]
else:
raise IndexError('this is high enough')
>>> bt_obj = BenTen([x for x in range(15)])
>>>for each in bt_obj:each
...
0
1
2
3
4
now when the object of BenTen class is used in a for-in loop, getitem is called with succesively higher index value, till it raises IndexError.
You can iterate over the class's unhidden attributes with for attr in (elem for elem in dir(Foo) if elem[:2] != '__').
A less horrible way to spell that is:
def class_iter(Class):
return (elem for elem in dir(Class) if elem[:2] != '__')
then
for attr in class_iter(Foo):
pass
class MetaItetaror(type):
def __iter__(cls):
return iter(
filter(
lambda k: not k[0].startswith('__'),
cls.__dict__.iteritems()
)
)
class Klass:
__metaclass__ = MetaItetaror
iterable_attr_names = {'x', 'y', 'z'}
x = 5
y = 6
z = 7
for v in Klass:
print v
An instance of enum.Enum happens to be iterable, and while it is not a general solution, it is a reasonable option for some use cases:
from enum import Enum
class Foo(Enum):
bar = "qux"
baz = 123
>>> print(*Foo)
Foo.bar Foo.baz
names = [m.name for m in Foo]
>>> print(*names)
bar baz
values = [m.value for m in Foo]
print(*values)
>>> qux 123
As with .__dict__, the order of iteration using this Enum based approach is the same as the order of definition.
You can make class members iterable within just a single line.
Despite the easy and compact code there are two mayor features included, additionally:
Type checking allows using additional class members not to be iterated.
The technique is also working if (public) class methods are defined. The proposals above using the "__" string checking filtering method propably fail in such cases.
# How to make class members iterable in a single line within Python (O. Simon, 14.4.2022)
# Includes type checking to allow additional class members not to be iterated
class SampleVector():
def __init__(self, x, y, name):
self.x = x
self.y = y
self.name = name
def __iter__(self):
return [value for value in self.__dict__.values() if isinstance(value, int) or isinstance(value, float)].__iter__()
if __name__ == '__main__':
v = SampleVector(4, 5, "myVector")
print (f"The content of sample vector '{v.name}' is:\n")
for m in v:
print(m)
This solution is fairly close and inspired by answer 12 from Hans Ginzel and Vijay Shanker.
Suppose I have the following:
class A:
def __init__( self, Att):
"""here Att is a string input"""
self.Att = Att
def __repr__( self ):
s = "My attribute is " + self.Att
return s
class B:
def __init__( self, Btt):
"""here Btt is a string input"""
self.Btt = Btt
def __repr__( self ):
s = "My other attribute is " + self.Btt
return s
def SetEqual(self):
Att = self.Btt
I realize the SetEqual method above will not work. But how might I go about creating a method in class B that will access class A and change the value of self.Att to be equal to self.Btt?
The following method from B takes a A object and changes its value:
def setEqual(self, a):
a.Att = self.Btt
Two remarks here.
First, Python does not know about encapsulation, so this is absolutely legal (and Pythonic) to write a.Att from the outside of the A class.
Second, be careful with the assignment, because it only links the two variables. As a tangible consequence, once you wrote a = b, a and b share the same id.
This is not a problem when manipulating immutable objects like integers, because if the two variables refer to the same id but one is modified, Python will change its id:
>>> a = 1
>>> b = a
>>> id(a) == id(b)
True
>>> b = 2
>>> id(a) == id(b)
False
However, when you manipulate collections, the behaviour is different:
>>> l1 = []
>>> l2 = l1
>>> id(l1) == id(l2)
True
>>> l1.append(12)
>>> id(l1) == id(l2)
True
Which means that when you manipulate mutable objects, changing its value somewhere will make it change everywhere else too.
You might want to take a look at the copy module for shallows and deep copies.
Consider the following code:
>>> class A(object):
... def __init__(self, a):
... self.a = a
... def __eq__(self, other):
... return self.a==other.a
...
>>> a=A(1)
>>> b=A(1)
>>> c=A(2)
>>> a==b
True # because __eq__ says so
>>> a==c
False # because __eq__ says so
>>> a is b
False # because they're different objects
>>> l = [b,c]
>>> a in l
True # seems to use __eq__ under the hood
So, in seems to use __eq__ to determine whether or not something is in a container.
Where can one find documentation on this behavior?
Is it possible to make in use object identity, a.k.a. a in somelist if the object a is in somelist, and not some other object that compares equal to a?
Use the any() function and a generator expression:
any(o is a for o in l)
The behaviour of in is documented in the Common Sequence Operators section:
x in s
True if an item of s is equal to x, else False
Bold emphasis mine.
If you must use in, use a wrapper object with a custom __eq__ method that uses is, or build your own container where a custom __contains__ method uses is to test against each contained element.
The wrapper could look like this:
class IdentityWrapper(object):
def __init__(self, ob):
self.ob = ob
def __eq__(self, other):
return other is self.ob
Demo:
>>> IdentityWrapper(a) in l
False
>>> IdentityWrapper(a) in (l + [a])
True
The container could just use the same any() function outlined above:
class IdentityList(list):
def __contains__(self, other):
return any(o is other for o in self)
Demo:
>>> il = IdentityList(l)
>>> a in il
False
>>> a in IdentityList(l + [a])
True
If you do not want to change A behaviour, you may prepare thin wrapper for used container. To change how in operator behaves, magic method __contains__ needs to get overridden. Quoting docs:
Called to implement membership test operators. Should return true if
item is in self, false otherwise. For mapping objects, this should
consider the keys of the mapping rather than the values or the
key-item pairs.
Sample code:
class A(object):
def __init__(self, a):
self.a = a
def __eq__(self, other):
return self.a == other.a
class IdentityList(list):
def __contains__(self, obj):
return any(o is obj for o in self)
a = A(1)
b = A(1)
c = A(2)
container = [b, c]
identity_container = IdentityList(container)
assert a in container # not desired output (described in question)
assert a not in identity_container # desired output
It's easiest to illustrate what I'm trying to do with an example:
Class A(object):
someVariable = 0
def __init__(self):
self.someVariable = 1
with open('file.pkl','wb') as pfile:
pickle.dump(self,pfile)
self.someVariable = 2
self = pickle.load('file.pkl')
print self.someVariable == 1
blah = A()
And I would like this to print True, but I think that the self object is immutable in Python. It will be a pain to restructure my code, is there any way to quickly achieve the above?
You should pickle self.__dict__ which stores every attribute of the class.
And all you have to do is to unpickle it. (As you've figured, it's a dict.)
I'm not sure I understood what you really want, but I guess you are trying to persist an instance to disk. My take would be something like this:
class A(object):
some_variable = 0
def __init__(self, value=1):
self.some_variable = value
def save(self, name='file.pkl'):
with open(name,'wb') as pfile:
pickle.dump(self, pfile)
#staticmethod
def load(name='file.pkl'):
return pickle.load(open(name, 'rb'))
Then you can do:
>>> a = A(2)
>>> a.some_variable
2
>>> a.save('foo.pkl')
>>> a = A()
>>> a.some_variable
1
>>> a = A.load('foo.pkl')
>>> a.some_variable
2
Hello I have declared a class in Python and then I want to make a list of objects of this class and print it. I am new to python and I cannot figure out what I am doing wrong. I know C++ and this is what I would like to do
class Word:
def __init__(self,word,hor):
self.word=word
self.x1=0
self.y1=0
self.x2=0
self.y2=0
self.hor=hor
def get_dimensions(self):
return(self.x1,self.y1,self.x2,self.y2)
def set_dimensions(self,t):
self.x1=t[0]
self.y1=t[1]
self.x2=t[2]
self.y2=t[3]
def get_horizontal():
return self.hor
def display(self):
print word
def WordList(word_list,hor):
l=[]
for x in word_list:
w1=Word(x,hor)
l.append(w1)
return l
li=["123","23","43"]
li=WordList(li,True)
for x in li:
x.display #obviously something else has to be done here
Also I get the following compilation problem when I try to run it:
[<__main__.Word instance at 0x7ffc9320aa70>, <__main__.Word instance at 0x7ffc9320ab00>, <__main__.Word instance at 0x7ffc9320ab48>]
Can you help me?
You are attempting to print the method itself, rather than call it.
Use the following instead:
for x in li:
x.display()
You can also provide a custom str method;
class SomeClassHere(object):
def __init__(self, a):
self.a = a
def __str__(self):
return "Hello %s" % ( self.a, )
>>> a = SomeClassHere(a="world")
>>> print a
Hello world
To answer your additional question on whether the types match or not;
>>> class Hello(object):
... def __init__(self, a):
... self.a = a
...
>>> b = Hello(a=1)
>>> c = Hello(a=2)
>>> d = Hello(a=3)
>>> b == c
False
>>> c == d
False
>>> isinstance(b, Hello)
True
You can change this behaviour by modifying __eq__ and __cmp__ - see:
How is __eq__ handled in Python and in what order?
You need to fix two bugs:
def display(self):
print self.word #Added self here
and
for x in li:
x.display() #Added brackets here