I had a problem with overriding str inside my inherited class. Is there a way to do something similar?
class Sentence(str):
def input(self, msg):
"""Extend allow to hold one changing object for various strings."""
self = Sentence(input(msg))
def simplify(self):
self = self.lower()
self.strip()
I want to change mine string contained in that class, for various use. There's a way to do this? Because I tried many things from stack, and no one help me.
There is a explain what I want to do:
In init, I initialize Sentence class:
self.sentence = Sentence("")
Mainloop, where user can change Sentence:
self.sentence.input("Your input:")
After it I want to simplify string for alghoritm:
self.sentence.simplify()
And that's all, after it I want to use self.sentence like string.
But in both methods:
def input(self, msg):
"""Extend allow to hold one changing object for various strings."""
self = Sentence(input(msg))
def simplify(self):
self = self.lower()
self.strip()
String wasn't changed.
Due to the optimizations languages such as Python perform on strings (i.e. they are inmutable so the same string can be reused) I don't think it's a good practice to inherit from str, instead, you could write a class that wraps the string:
class Sentence:
def __init__(self, msg: str):
self.msg = msg
def simplify(self):
self.msg = self.msg.lower().strip()
This way you can improve your implementation if for example you are changing the string too often and you run into performance problems.
Related
A bit of an odd question, but I'm wondering how to import an object from one class to another. I imagine adding more class methods and attributes as I expand my program, and I still want to be able to use old data. I am thinking something as follows:
class old_obj:
def __init__(self, text):
self.name = text
def set_amount(self, num):
self.amount = num
def introduce_yourself(self):
print("I am {} and I am {} many".format(self.name, self.amount))
oldest = old_obj("myself")
oldest.set_amount(15)
also_old = old_obj("Bach")
class new_obj:
def __init__(self):
#some code
#more code
I want to be able to write something like:
renewed = new_obj(oldest)
also_new = new_obj(also_old)
Here, I want to retain the 15 from oldest.amount, but not complain that also_old.amount is None. In particular, I want to retain any attributes that oldest has, while not requiring that it have all possible attributes. Is there a way for me to copy over instances of a class to a new class?
Edit: edited for clarity
You could copy the object instance dict to the new class.
from copy import deepcopy
class old_obj:
def __init__(self, text):
self.name = text
def set_amount(self, num):
self.amount = num
def introduce_yourself(self):
print("I am {} and I am {} many".format(self.name, self.amount))
oldest = old_obj("myself")
class new_obj:
def __init__(self, my_old_obj):
for var, val in my_old_obj.__dict__.items():
setattr(self, var, deepcopy(val))
#some code
#more code
newest = new_obj(oldest)
I did a deepcopy of the value assuming you want unique values in the new object. But that can also be problematic because not everything can be copied (file objects for instance). There can be other oddities when duplicating attributes such as what you want to do with a generator. And if this is something like a GUI widget, it could get stranger still.
But for a lot of object types, this would work.
Slightly different take:
Your new class has a set of concerns that are probably similar to your old class. This should guide the way you update it and build out the behavior in question. With this in mind...
Provide a class method in your new class to allow construction of the new object from the old object. Don’t make this behavior a part of __init__. Your __init__ should have a more limited responsibility. For the class method, updating the new object’s __dict__ using the old object’s __dict__ would do the job.
Don’t use inheritance to make new versions of classes. Use inheritance to move from general to specific or abstract to concrete. Otherwise, you end up with code that is hard to understand and update. (Imagine several generations down of just sub-classing in order to add some new methods.)
If the number of methods and attributes is growing, you might want to consider whether or not you’re encapsulating data/behaviors that should be split into multiple classes. The guiding principle is that you should encapsulate the data/behaviors that are likely to change together. That is, when you change the way you’re implementing your program, things that don’t need to change should probably be encapsulated separate from things that need changing. If you find that a lot of your static data is bound up with an object class that you’re frequently updating (but wanting to just import the old data unchanged), then you’ve probably got two different sets of concerns, at least.
You can simply initialize the new object by passing it the old one.
class old_obj:
def __init__(self, text):
self.text = text
oldest = old_obj("myself")
class new_obj:
def __init__(self, old_inst):
self.text = old_inst.text
renewed = new_obj(oldest)
print(renewed.text)
First, make your new_obj class inherit from old_obj, so that new_obj has all the methods old_obj had:
class new_obj(olb_obj):
Then, in __init__ method of the new class you can check what is passed as the argument - a string or an object:
def __init__(self, arg):
if isinstance(arg, str):
self.text = arg
elif isinstance(arg, old_obj):
self.text = arg.text
else:
raise TypeError
I have the next situation. The goal of the following method is to return the object created from the incoming string. So I have:
class Situation(Generator):
pass
And the method inside parent class:
class Generator(object):
def createsituation(self, stringsituation="situation"):
return "Instance of Situation"
The incoming string always equals to string "situation". Is it possible in python?
You can easily map strings to classes, yes. Classes are just more objects, you can store them in other Python objects.
You can manually build a dictionary mapping strings to classes:
classes = {'situation': Situation}
You can automate this a little by creating a class decorator, perhaps:
classes = {}
def register(cls):
classes[cls.__name__.lower()] = cls
return cls
#register
class Situation(Generator):
# ...
Each class you prefix with #register will be added to the dictionary, with the class name lowercased as the key.
or you can use the globals() function to get a dictionary of all globals in your module. The latter is a little... overkill and also a security hazard, you could end up giving end-users way more access than you bargained for, as that also gives them other classes and functions you didn't mean to expose.
Once you have a dictionary, just access the right class and call it:
class Generator(object):
def createsituation(self, stringsituation="situation"):
return classes[stringsituation]()
If I understood you correctly, you want to create the Situation object from Generator's createsituation method. So you need the appropriate constructor in Situation class with passed string as an argument. Little changes in your code will achieve this:
class Situation(object):
def __init__(self, string):
print string
class Generator(object):
def createsituation(self, stringsituation="situation"):
return Situation(stringsituation)
g = Generator()
sitObj = g.createsituation("new_situation") # prints "new_situation" from Situation constructor
I have the next situation. The goal of the following method is to return the object created from the incoming string. So I have:
class Situation(Generator):
pass
And the method inside parent class:
class Generator(object):
def createsituation(self, stringsituation="situation"):
return "Instance of Situation"
The incoming string always equals to string "situation". Is it possible in python?
You can easily map strings to classes, yes. Classes are just more objects, you can store them in other Python objects.
You can manually build a dictionary mapping strings to classes:
classes = {'situation': Situation}
You can automate this a little by creating a class decorator, perhaps:
classes = {}
def register(cls):
classes[cls.__name__.lower()] = cls
return cls
#register
class Situation(Generator):
# ...
Each class you prefix with #register will be added to the dictionary, with the class name lowercased as the key.
or you can use the globals() function to get a dictionary of all globals in your module. The latter is a little... overkill and also a security hazard, you could end up giving end-users way more access than you bargained for, as that also gives them other classes and functions you didn't mean to expose.
Once you have a dictionary, just access the right class and call it:
class Generator(object):
def createsituation(self, stringsituation="situation"):
return classes[stringsituation]()
If I understood you correctly, you want to create the Situation object from Generator's createsituation method. So you need the appropriate constructor in Situation class with passed string as an argument. Little changes in your code will achieve this:
class Situation(object):
def __init__(self, string):
print string
class Generator(object):
def createsituation(self, stringsituation="situation"):
return Situation(stringsituation)
g = Generator()
sitObj = g.createsituation("new_situation") # prints "new_situation" from Situation constructor
I have two classes (let's call them Working and ReturnStatement) which I can't modify, but I want to extend both of them with logging. The trick is that the Working's method returns a ReturnStatement object, so the new MutantWorking object also returns ReturnStatement unless I can cast it to MutantReturnStatement. Saying with code:
# these classes can't be changed
class ReturnStatement(object):
def act(self):
print "I'm a ReturnStatement."
class Working(object):
def do(self):
print "I am Working."
return ReturnStatement()
# these classes should wrap the original ones
class MutantReturnStatement(ReturnStatement):
def act(self):
print "I'm wrapping ReturnStatement."
return ReturnStatement().act()
class MutantWorking(Working):
def do(self):
print "I am wrapping Working."
# !!! this is not working, I'd need that casting working !!!
return (MutantReturnStatement) Working().do()
rs = MutantWorking().do() #I can use MutantWorking just like Working
print "--" # just to separate output
rs.act() #this must be MutantReturnState.act(), I need the overloaded method
The expected result:
I am wrapping Working.
I am Working.
--
I'm wrapping ReturnStatement.
I'm a ReturnStatement.
Is it possible to solve the problem? I'm also curious if the problem can be solved in PHP, too. Unless I get a working solution I can't accept the answer, so please write working code to get accepted.
There is no casting as the other answers already explained. You can make subclasses or make modified new types with the extra functionality using decorators.
Here's a complete example (credit to How to make a chain of function decorators?). You do not need to modify your original classes. In my example the original class is called Working.
# decorator for logging
def logging(func):
def wrapper(*args, **kwargs):
print func.__name__, args, kwargs
res = func(*args, **kwargs)
return res
return wrapper
# this is some example class you do not want to/can not modify
class Working:
def Do(c):
print("I am working")
def pr(c,printit): # other example method
print(printit)
def bla(c): # other example method
c.pr("saybla")
# this is how to make a new class with some methods logged:
class MutantWorking(Working):
pr=logging(Working.pr)
bla=logging(Working.bla)
Do=logging(Working.Do)
h=MutantWorking()
h.bla()
h.pr("Working")
h.Do()
this will print
h.bla()
bla (<__main__.MutantWorking instance at 0xb776b78c>,) {}
pr (<__main__.MutantWorking instance at 0xb776b78c>, 'saybla') {}
saybla
pr (<__main__.MutantWorking instance at 0xb776b78c>, 'Working') {}
Working
Do (<__main__.MutantWorking instance at 0xb776b78c>,) {}
I am working
In addition, I would like to understand why you can not modify a class. Did you try? Because, as an alternative to making a subclass, if you feel dynamic you can almost always modify an old class in place:
Working.Do=logging(Working.Do)
ReturnStatement.Act=logging(ReturnStatement.Act)
Update: Apply logging to all methods of a class
As you now specifically asked for this. You can loop over all members and apply logging to them all. But you need to define a rule for what kind of members to modify. The example below excludes any method with __ in its name .
import types
def hasmethod(obj, name):
return hasattr(obj, name) and type(getattr(obj, name)) == types.MethodType
def loggify(theclass):
for x in filter(lambda x:"__" not in x, dir(theclass)):
if hasmethod(theclass,x):
print(x)
setattr(theclass,x,logging(getattr(theclass,x)))
return theclass
With this all you have to do to make a new logged version of a class is:
#loggify
class loggedWorker(Working): pass
Or modify an existing class in place:
loggify(Working)
There is no "casting" in Python.
Any subclass of a class is considered an instance of its parents. Desired behavior can be achieved by proper calling the superclass methods, and by overriding class attributes.
update: with the advent of static type checking, there is "type casting" - check bellow.
What you can do on your example, is to have to have a subclass initializer that receives the superclass and copies its relevant attributes - so, your MutantReturnstatement could be written thus:
class MutantReturnStatement(ReturnStatement):
def __init__(self, previous_object=None):
if previous_object:
self.attribute = previous_object.attribute
# repeat for relevant attributes
def act(self):
print "I'm wrapping ReturnStatement."
return ReturnStatement().act()
And then change your MutantWorking class to:
class MutantWorking(Working):
def do(self):
print "I am wrapping Working."
return MutantReturnStatement(Working().do())
There are Pythonic ways for not having a lot of self.attr = other.attr lines on the __init__method if there are lots (like, more than 3 :-) ) attributes you want to copy -
the laziest of which wiuld be simply to copy the other instance's __dict__ attribute.
Alternatively, if you know what you are doing, you could also simply change the __class__ attribute of your target object to the desired class - but that can be misleading and carry you to subtle errors (the __init__ method of the subclass would not be called, would not work on non-python defined classes, and other possible problems), I don't recomment this approach - this is not "casting", it is use of introspection to bruteforce an object change and is only included for keeping the answer complete:
class MutantWorking(Working):
def do(self):
print "I am wrapping Working."
result = Working.do(self)
result.__class__ = MutantReturnStatement
return result
Again - this should work, but don't do it - use the former method.
By the way, I am not too experienced with other OO languages, that allow casting - but is casting to a subclass even allowed in any language? Does it make sense? I think casting s only allowed to parentclasses.
update: When one works with type hinting and static analysis in the ways describd in PEP 484, sometimes the static analysis tool can't figure out what is going on. So, there is the typing.cast call: it does absolutely nothing in runtime, just return the same object that was passed to it, but the tools then "learn" that the returned object is of the passed type, and won't complain about it. It will remove typing errors in the helper tool, but I can't emphasise enough it does not have any effect in runtime:
In [18]: from typing import cast
In [19]: cast(int, 3.4)
Out[19]: 3.4
No direct way.
You may define MutantReturnStatement's init like this:
def __init__(self, retStatement):
self.retStatement = retStatement
and then use it like this:
class MutantWorking(Working):
def do(self):
print "I am wrapping Working."
# !!! this is not working, I'd need that casting working !!!
return MutantReturnStatement(Working().do())
And you should get rid from inheriting ReturnStatement in your wrapper, like this
class MutantReturnStatement(object):
def act(self):
print "I'm wrapping ReturnStatement."
return self.retStatement.act()
You don't need casting here. You just need
class MutantWorking(Working):
def do(self):
print "I am wrapping Working."
Working().do()
return MutantReturnStatement()
This will obviously give the correct return and desired printout.
What you do is not a casting, it is a type conversion. Still, you could write something like
def cast_to(mytype: Type[any], obj: any):
if isinstance(obj, mytype):
return obj
else:
return mytype(obj)
class MutantReturnStatement(ReturnStatement):
def __init__(self, *args, **kwargs):
if isinstance(args[0], Working):
pass
# your custom logic here
# for the type conversion.
Usage:
cast_to(MutantReturnStatement, Working()).act()
# or simply
MutantReturnStatement(Working()).act()
(Note that in your example MutantReturnStatement does not have .do() member function.)
I have a class that represents a pretty complex object. The objects can be created by many ways: incremental building, by parsing text strings in different formats and by analyzing binary files. So far my strategy was as follows:
Have the constructor (__init__, in my case) initialize all the internal variables to None
Supply different member functions to populate the object
Have those functions return the new, modified object to the caller so we can do sd = SuperDuper().fromString(s)
For example:
class SuperDuper:
def __init__(self):
self.var1 = None
self.var2 = None
self.varN = None
## Generators
def fromStringFormat1(self, s):
#parse the string
return self
def fromStringFormat2(self, s):
#parse the string
return self
def fromAnotherLogic(self, *params):
#parse params
return self
## Modifiers (for incremental work)
def addThis(self, p):
pass
def addThat(self, p):
pass
def removeTheOtherOne(self, p):
pass
The problem is that the class becomes very huge. Unfotunately I am not familiar with OOP pattern designs, but I assume that there is a more ellegant solution for this problem. Is taking the generator functions out of the class (so that fromString(self, s) becomes superDuperFromString(s) a good idea?
What might be a better idea in your case is dependency injection and inversion of control. The idea is to create another class that has all of the settings that you are parsing out of all of these different sources. Then subclasses can define the method to actually parse it. Then when you instantiate the class, pass an instance of the settings class to it:
class Settings(object):
var1 = None
var2 = None
var3 = None
def configure_superduper(self, superduper):
superduper.var1 = self.var1
# etc
class FromString(Settings):
def __init__(self, string):
#parse strings and set var1, etc.
class SuperDuper(object):
def __init__(self, settings): # dependency injection
settings.configure_superduper(self) # inversion of control
# other initialization stuff
sup = SuperDuper(object, FromString(some_string))
Doing it this way has the advantage of adhering more closely to the single responsibility principle which says that a class should only have one (likely to occur) reason to change. If you change the way you're storing any of these strings, then the class has to change. Here, we're isolating that into one simple, separate class for each source of data.
If on the other hand, you think that the data that's being stored is more likely to change than the way it's stored, you might want to go with class methods as Ignacio is suggesting because this is (slightly) more complicated and doesn't really buy you much in that case because when that happens you have to change two classes in this scheme. Of course it doesn't really hurt much either because you'll only have to change one more assignment.
I don't believe it would be, since those all relate directly to the class regardless.
What I would do is make the constructor take arguments to initialize the fields (defaulting to None of course), then turn all the from*() methods into classmethods that construct new objects and return them.
I don't think it is a bad design to have conversion/creation methods inside the class. You could always move it to a separate class and then you would have a Simple Factory which is a very light-weight design pattern.
I'd keep them in the class though :)
Have those functions return the new, modified object to the caller so we can do sd = SuperDuper().fromString(s)
Rarely is this a good idea. While some Python library classes do this, it's not the best approach.
Generally, you want to do this.
class SuperDuper( object ):
def __init__(self, var1=None, var2=None, var3=None):
self.var1 = var1
self.var2 = var2
self.varN = var3
def addThis(self, p):
pass
def addThat(self, p):
pass
def removeTheOtherOne(self, p):
pass
class ParseString( object ):
def __init__( self, someString ):
pass
def superDuper( self ):
pass
class ParseString_Format1( ParseString ):
pass
class ParseString_Format2( ParseString ):
pass
def parse_format1( string ):
parser= ParseString_Format1( string )
return parser.superDuper()
def parse_format2( string ):
parser= ParseString_Format2( string )
return parser.superDuper()
def fromAnotherLogic( **kw ):
return SuperDuper( **kw )
There are two unrelated responsibilities: the object and the string representations of the object.
Do Not Conflate Objects and String Representations.
Objects and Parsing must be kept separate. After all, the compiler is not part of the code that's produced. An XML parser and the Document Object Model are generally separate objects.