Is there a way to change a class variable without adding 'foo = '? - python

I have a class, and would like to change an object of it (similar to the pop method of lists), without adding an foo = foo.bar()
In simpler terms, i'd like to do foo.bar() instead of foo = foo.bar(). Is this possible in python?
Here's some code that i have, which hopefully furthers understanding:
class mystr(str):
def pop(self, num):
self = list(self)
changed = self.pop(num) # The particular character that was removed
self = ''.join(self) # The rest of the string
# Somewhere in here i need to be able to change the actual variable that pop() was called on
return changed # Emulates python lists' way of returning the removed element.
my_var = mystr("Hello World!")
print(my_var.pop(4) # Prints 'o', as you would expect
print(my_var) # But this still prints 'Hello World!', instead of 'Hell World!'
# It isn't modified, which is what i want it to do

You can, but not with str.
What you're looking for is a way to mutate your object. For most classes you write yourself, doing that is straightforward:
class Foo:
def __init__(self):
self.stuff = 0
def example(self):
self.stuff += 1
Here, calling example on a Foo instance mutates it, by changing its stuff instance attribute.
str, however, is immutable. It stores its data in C-level data structures and provides no mutator methods, so there's no way to modify its data. Even if you used ctypes to bypass the protection, you'd just get a bunch of memory corruption bugs.
You can add your own attributes in a subclass, and those will be mutable, but if you do that to fake a mutable string, you might as well just not inherit from str. Inheriting from str in that case will only cause bugs, with some code looking at your "fake" data and other code looking at the "real" underlying str data.
Most likely, the way to go will be one of two options. The first is to just use regular strings without your subclass or the methods you want to add. The second is to write a class that doesn't inherit from str.

You could achieve that by encapsulating a string, rather then inheriting from it:
class mystr:
def __init__(self, string):
self._str = string
def pop(self, num):
string_list = list(self._str)
changed = string_list.pop(num) # The particular character that was removed
self._str = ''.join(string_list) # The rest of the string
return changed # Emulates python lists' way of returning the removed element.
def __repr__(self):
return self._str
Running the same code with this class instead will print:
o
Hell World!

Related

python class operations on members vs static methods

I need some help figuring out the right OOP design choice for my python class.
In my example, letters are appended to a string in separate steps. The string is then printed. For this application, it is not really important to the user to get the intermediate results.
So is it better to pass the string to the constructor and then use private methods for the operations and a dothings method calling them all?
class A:
def __init__(self, string: str()):
self.string = string
def _append_a(self):
self.string += "a"
def _append_b(self):
self.string += "b"
def dothings(self):
_append_a()
_append_b()
def export(self):
print(self.string)
Or is it better to have the string passed to each method?
class AA:
#staticmethod
def append_a(string):
string += "a"
return string
#staticmethod
def append_b(string):
string += "b"
return string
#staticmethod
def export(string):
print(string)
The interface of A looks a bit cleaner to me, one can just call dothings and then export.
However, class A would be a bit of a black box, while with class AA the user has some more insights to what is happening.
Is there a 'right' choice for this?
AA is easily dismissed. There is nothing object-oriented about it: it's just three regular functions collected into a single namespace. There's no shared state operated on by a set of methods. There's no suggestion that only the output of one function is a valid input to another. For example, the intention is probably to write something like
export(append_a(append_b("foo"))) # fooba
but nothing requires this pattern be followed. The functions aren't related to each other in anyway.
A has some things in common with the builder pattern. Given an initial string, you can append as and bs to it, but nothing else (without violating encapsulation provided by the methods. Eventually, you get the "final" value by calling export, so the work flow it represents is something like:
a = A("foo")
a.append_a()
a.append_a()
a.append_b()
a.append_b()
a.append_a()
a.export() # fooaabba
The class as shown is almost trivially simple, but demonstrates how to provide a well defined interface to building a string value from an initial seed. You can't just do anything you like with it: you can't prepend values, you can't remove existing characters, etc.
To conform more closely to the builder pattern, I would modify A as follows:
class A:
def __init__(self, string: str):
self.string = string
def append_a(self):
self.string += "a"
def append_b(self):
self.string += "b"
def append_ab(self):
self.append_a()
self.append_b()
def export(self):
return self.string + "c"
As long as you don't access the string attribute directly, this class limits the kind of string you can build:
You can start with an arbitrary stem (the argument to __init__)
You can append an a to the string
You can append a b to the string
You can append an ab to the string (but this is just a convenient shortcut for calling append_a followed by append_b, as the implementation implies)
You can end the string with c
You get your final value by calling export (which I modified just to make the point that you cannot add a c at any point, so there's no way to follow a c with another a, for example).
In some sense, it's kind of a dual to a regular expression: instead of recognizing whether or not a string matches the regular expression .*(a|b)*c, you create a string that will match the regular expression.

Can a Python class's __str___() return one of two strings?

I have a class for which I want to be able to print either a short string representation of an object or a longer string representation. Ideally, __str__() would accept a flag that chooses which string to return, and print() would accept that flag as well and use the correct version of __str__() accordingly, but nothing like that seems to exist.
I know that I can include print_short() and print_long() methods inside my class to choose the correct string, but this doesn't seem Pythonic, and violates the Python 3 change by which print() is a function. This would also bypass the use of __str__(), which again, seems unPythonic.
What's the most Pythonic way of handling this? Solutions involving __repr__() won't work, since I'm already using __repr__() as intended, to unambiguously represent the object itself.
The job of str is to provide "the" string representation of an object, whatever representation you decide is most useful.
If you want to control the formatting of an object, override __format__.
class MyClass:
def __format__(self, spec):
...
If you have code like
s = MyClass()
print("{:r}".format(s))
s.__format__ receives everything after the colon (in this case r) as its spec parameter; it is then entirely up to the definition of __format__ how it uses the spec in deciding what string value to return. You could do something like the following
class MyClass:
def __format__(self, spec):
if spec == 's':
return self._short_str()
elif spec == 'l':
return self._long_str()
else:
# This includes both no spec whatsoever, which is
# conventionally expected to behave like __str__
# and an unrecognized specification, which is just ignored.
return str(self)
def _long_str(self):
return "three"
def _short_str(self):
return "3"
def __str__(self):
return "III"
>>> x = MyClass()
>>> str(x)
'III'
>>> "{}".format(x)
'III'
>>> "{:whatever}".format(x)
'III'
>>> "{:s}".format(x)
'3'
>>> "{:l}".format(x)
'three'

Python class print object always returns an empty list

I have the following code:
class Mylist(list):
def __init__(self,lst=[]):
self.lst=list(lst)
def append(self,item):
self.lst.append(item)
m=Mylist([1,2])
m.append(3)
m
Intuitively, this code should print [1,2,3] or maybe [3]? but definitely not []. I am wondering why is this happening? Although when I use m.lst instead of just m, then it prints [1,2,3].
As MyList inherits from list, it already contains internal storage for items that append (and extend) would normally add to. When you print(m) it is this internal storage that is shown.
In your case you have then overridden append to redirect items to be added to a separate attribute (lst), meaning that internal storage remains empty.
Note that you have not overridden extend. Thus:
# this will add to the *internal* storage, not `.lst`
>>> m.extend(["my", "gosh"])`
>>> print(m)
['my', 'gosh']
Mylist doesn't in any way utilize the fact that it's subclassing list. Your code would work if list actually had a lst attribute that itself was a list, but this is not the case.
You need to use the exposed interface of the list object that you inherited from if you want your overridden methods to do things that are picked up by the underlying list object:
class MyList(list):
def __init__(self, iterable):
print('I was passed:', iterable)
super().__init__(iterable)
def append(self, element):
print('I am appending the element:', element)
super().append(element)
If you just want to use a list, you don't need to inherit from list, and shouldn't:
class Mylist: # no (list) here!
def __init__(self,lst=[]):
self.lst=list(lst)
def append(self,item):
self.lst.append(item)
m=Mylist([1,2])
m.append(3)
This works. Of course printing out m will just get you something like <__main__.MyList at 0x12345678>, because you haven't told it how you want to be printed. You need to add another method like this:
def __repr__(self):
return '{}({})'.format(type(self).__name__, self.lst)
And now you'll print out MyList([1, 2, 3]).
If you want to look like a list, you still don't inherit from list for that. In most cases, in Python, "looking like a list" is just a matter of duck-typing: you implement all the right methods, and everything just works.
However, you might want to consider inheriting from MutableSequence. Then, you just implement about 7 or 8 methods, and you get the whole rest of the list's behavior for free. And you're also providing a way that code that, for whatever reason, needs to explicitly check whether you "act like a list" can do so.
So, when should you inherit from list? When you want to use the list's internal storage and implementation as your own.
Here's a silly example. To the extent that it has any reason to exist at all, it's reasonable that it should be a list subclass:
class FreezableList(list):
def frozen_copy(self):
return tuple(self)
def __repr__(self):
return '{}({})'.format(type(self).__name__, self.lst)

Not able to print an array in python after appending values to it [duplicate]

So I have a class, called Vertex.
class Vertex:
'''
This class is the vertex class. It represents a vertex.
'''
def __init__(self, label):
self.label = label
self.neighbours = []
def __str__(self):
return("Vertex "+str(self.label)+":"+str(self.neighbours))
I want to print a list of objects of this class, like this:
x = [Vertex(1), Vertex(2)]
print x
but it shows me output like this:
[<__main__.Vertex instance at 0xb76ed84c>, <__main__.Vertex instance at 0xb76ed86c>]
Actually, I wanted to print the value of Vertex.label for each object.
Is there any way to do it?
If you just want to print the label for each object, you could use a loop or a list comprehension:
print [vertex.label for vertex in x]
But to answer your original question, you need to define the __repr__ method to get the list output right. It could be something as simple as this:
def __repr__(self):
return str(self)
If you want a little more infos in addition of Daniel Roseman answer:
__repr__ and __str__ are two different things in python. (note, however, that if you have defined only __repr__, a call to class.__str__ will translate into a call to class.__repr__)
The goal of __repr__ is to be unambiguous. Plus, whenerver possible, you should define repr so that(in your case) eval(repr(instance)) == instance
On the other hand, the goal of __str__ is to be readable; so it matter if you have to print the instance on screen (for the user, probably), if you don't need to do it, then do not implement it (and again, if str in not implemented will be called repr)
Plus, when type things in the Idle interpreter, it automatically calls the repr representation of your object. Or when you print a list, it calls list.__str__ (which is identical to list.__repr__) that calls in his turn the repr representaion of any element the list contains. This explains the behaviour you get and hopefully how to fix it
def __ str __ (self):
return f"Vertex: {self.label} {self.neighbours}"
#In most cases, this is probably the easiest and cleanest way to do it. Not fully sure how this code will interact with your list []. Lastly, any words or commas needed, just add them between the brackets; no further quotes needed.

Monkey patch __del__ to new function

For specific debugging purposes I'd like to wrap the del function of an arbitrary object to perform extra tasks like write the last value of the object to a file.
Ideally I want to write
monkey(x)
and it should mean that the final value of x is printed when x is deleted
Now I figured that del is a class method. So the following is a start:
class Test:
def __str__(self):
return "Test"
def p(self):
print(str(self))
def monkey(x):
x.__class__.__del__=p
a=Test()
monkey(a)
del a
However if I want to monkey specific objects only I suppose I need to dynamically rewrite their class to a new one?! Moreover I need to do this anyway, since I cannot access del of built-in types?
Anyone knows how to implement that?
While special 'double underscore' methods like __del__, __str__, __repr__, etc. can be monkey-patched on the instance level, they'll just be ignored, unless they are called directly (e.g., if you take Omnifarious's answer: del a won't print a thing, but a.__del__() would).
If you still want to monkey patch a single instance a of class A at runtime, the solution is to dynamically create a class A1 which is derived from A, and then change a's class to the newly-created A1. Yes, this is possible, and a will behave as if nothing has changed - except that now it includes your monkey patched method.
Here's a solution based on a generic function I wrote for another question:
Python method resolution mystery
def override(p, methods):
oldType = type(p)
newType = type(oldType.__name__ + "_Override", (oldType,), methods)
p.__class__ = newType
class Test(object):
def __str__(self):
return "Test"
def p(self):
print(str(self))
def monkey(x):
override(x, {"__del__": p})
a=Test()
b=Test()
monkey(a)
print "Deleting a:"
del a
print "Deleting b:"
del b
del a deletes the name 'a' from the namespace, but not the object referenced by that name. See this:
>>> x = 7
>>> y = x
>>> del x
>>> print y
7
Also, some_object.__del__ is not guaranteed to be called at all.
Also, I already answered your question here (in german).
You can also inherit from some base class and override the __del__ method (then only thing you would need would be to override class when constructing an object).
Or you can use super built-in method.
Edit: This won't actually work, and I'm leaving it here largely as a warning to others.
You can monkey patch an individual object. self will not get passed to functions that you monkey patch in this way, but that's easily remedied with functools.partial.
Example:
def monkey_class(x):
x.__class__.__del__ = p
def monkey_object(x):
x.__del__ = functools.partial(p, x)

Categories