Related
I would like to replace an object instance by another instance inside a method like this:
class A:
def method1(self):
self = func(self)
The object is retrieved from a database.
It is unlikely that replacing the 'self' variable will accomplish whatever you're trying to do, that couldn't just be accomplished by storing the result of func(self) in a different variable. 'self' is effectively a local variable only defined for the duration of the method call, used to pass in the instance of the class which is being operated upon. Replacing self will not actually replace references to the original instance of the class held by other objects, nor will it create a lasting reference to the new instance which was assigned to it.
As far as I understand, If you are trying to replace the current object with another object of same type (assuming func won't change the object type) from an member function. I think this will achieve that:
class A:
def method1(self):
newObj = func(self)
self.__dict__.update(newObj.__dict__)
It is not a direct answer to the question, but in the posts below there's a solution for what amirouche tried to do:
Python object conversion
Can I dynamically convert an instance of one class to another?
And here's working code sample (Python 3.2.5).
class Men:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a men! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_men(self):
print('I made The Matrix')
class Women:
def __init__(self, name):
self.name = name
def who_are_you(self):
print("I'm a women! My name is " + self.name)
def cast_to(self, sex, name):
self.__class__ = sex
self.name = name
def method_unique_to_women(self):
print('I made Cloud Atlas')
men = Men('Larry')
men.who_are_you()
#>>> I'm a men! My name is Larry
men.method_unique_to_men()
#>>> I made The Matrix
men.cast_to(Women, 'Lana')
men.who_are_you()
#>>> I'm a women! My name is Lana
men.method_unique_to_women()
#>>> I made Cloud Atlas
Note the self.__class__ and not self.__class__.__name__. I.e. this technique not only replaces class name, but actually converts an instance of a class (at least both of them have same id()). Also, 1) I don't know whether it is "safe to replace a self object by another object of the same type in [an object own] method"; 2) it works with different types of objects, not only with ones that are of the same type; 3) it works not exactly like amirouche wanted: you can't init class like Class(args), only Class() (I'm not a pro and can't answer why it's like this).
Yes, all that will happen is that you won't be able to reference the current instance of your class A (unless you set another variable to self before you change it.) I wouldn't recommend it though, it makes for less readable code.
Note that you're only changing a variable, just like any other. Doing self = 123 is the same as doing abc = 123. self is only a reference to the current instance within the method. You can't change your instance by setting self.
What func(self) should do is to change the variables of your instance:
def func(obj):
obj.var_a = 123
obj.var_b = 'abc'
Then do this:
class A:
def method1(self):
func(self) # No need to assign self here
In many cases, a good way to achieve what you want is to call __init__ again. For example:
class MyList(list):
def trim(self,n):
self.__init__(self[:-n])
x = MyList([1,2,3,4])
x.trim(2)
assert type(x) == MyList
assert x == [1,2]
Note that this comes with a few assumptions such as the all that you want to change about the object being set in __init__. Also beware that this could cause problems with inheriting classes that redefine __init__ in an incompatible manner.
Yes, there is nothing wrong with this. Haters gonna hate. (Looking at you Pycharm with your in most cases imaginable, there's no point in such reassignment and it indicates an error).
A situation where you could do this is:
some_method(self, ...):
...
if(some_condition):
self = self.some_other_method()
...
return ...
Sure, you could start the method body by reassigning self to some other variable, but if you wouldn't normally do that with other parametres, why do it with self?
One can use the self assignment in a method, to change the class of instance to a derived class.
Of course one could assign it to a new object, but then the use of the new object ripples through the rest of code in the method. Reassiging it to self, leaves the rest of the method untouched.
class aclass:
def methodA(self):
...
if condition:
self = replace_by_derived(self)
# self is now referencing to an instance of a derived class
# with probably the same values for its data attributes
# all code here remains untouched
...
self.methodB() # calls the methodB of derivedclass is condition is True
...
def methodB(self):
# methodB of class aclass
...
class derivedclass(aclass):
def methodB(self):
#methodB of class derivedclass
...
But apart from such a special use case, I don't see any advantages to replace self.
You can make the instance a singleton element of the class
and mark the methods with #classmethod.
from enum import IntEnum
from collections import namedtuple
class kind(IntEnum):
circle = 1
square = 2
def attr(y): return [getattr(y, x) for x in 'k l b u r'.split()]
class Shape(namedtuple('Shape', 'k,l,b,u,r')):
self = None
#classmethod
def __repr__(cls):
return "<Shape({},{},{},{},{}) object at {}>".format(
*(attr(cls.self)+[id(cls.self)]))
#classmethod
def transform(cls, func):
cls.self = cls.self._replace(**func(cls.self))
Shape.self = Shape(k=1, l=2, b=3, u=4, r=5)
s = Shape.self
def nextkind(self):
return {'k': self.k+1}
print(repr(s)) # <Shape(1,2,3,4,5) object at 139766656561792>
s.transform(nextkind)
print(repr(s)) # <Shape(2,2,3,4,5) object at 139766656561888>
I have a situation where I'm making a bunch of classes, and a bunch of them are really basically the same, so I'd like to make them in a loop. They are being used with a registration system, so there's no problem one the USAGE side, but I'm not sure how to actually define a class with a variable determining the class name...
Simple example:
classList = ['foo', 'bar', 'baz']
for className in classList:
class {{{className}}}_calc(BaseCalc):
def __init__ (self, dataFrame):
self.column = dataFrame[className]
def calc ():
return self.column.sum()
This is a very simplified case, obviously. I can't change the arguments to init because there are a whole bunch of these already existing, that are part of a larger structure.
The rest of the example is using pandas syntax, just to give an idea of how this is being used... but it's actually being used with a SQL DB, and is much more complicated... I just don't want to have to defend "why are you doing this in the first place?" I have good reasons, leave it at that.
classname is in {{{ }}} in the class line to denote that it's a variable, and not actually syntactically correct there. The question is "how do I denote what I have used {{{ }}} for?" I think.
The answer may be metaclasses, but I'm still not sure how to make the NAME of my class variable....
ETA: Trying to use #python_user answer:
classList = ['foooo', 'bar', 'baaz']
class Base ():
def __init__ (self, buq):
self.buq = buq
def getBuq(self):
return 'buq: ' + self.buq
for cls in classList:
class TEMP(Base):
className = cls
def __init__ (self):
self.qux = len(cls)
Base.__init__(self, cls)
def blee(self, inpt):
return inpt+ self.qux
TEMP.__name__ = f'{cls}'
TEMP.__qualname__ = f'{cls}'
globals()[cls] = TEMP
f = foo()
f.getBuq()
>>>> 'buq: baaz'
This is only giving me the baaz class. All three are giving baaz... Am I doing something really dumb?
You can do like so, using globals()
classList = ['foo', 'bar', 'baz']
for className in classList:
class Temp:
def __init__ (self, dataFrame):
self.column = dataFrame[className]
def calc ():
return self.column.sum()
Temp.__name__ = className
globals()[className] = Temp
You can then do foo() to create an object of class foo. You have to call with the args required for the __init__ method for the actual example. This is just to show it works.
print(type(foo()).__name__) # foo
print(type(bar()).__name__) # bar
print(type(baz()).__name__) # baz
If you want to change your class names then you can do
Temp.__name__ = f'{className}_calc'
globals()[f'{className}_calc'] = Temp
As pointed out by wim in the comments you need to also set __qualname__. Temp.__qualname__ = f'{className}_calc'
Edit:
As name lookups in methods of a class are performed at runtime (not at compile time), the code snippet has a bug. className would always refer to the last element in the classList (baz in this case), this name exists outside the scope of the loop and will be the value for className in the methods for ALL classes. (eg : self.column = dataFrame[className]). <--- This is always dataFrame['baz']
To fix this, one has to declare a class level variable called className and assign className (the one from the loop) to that. So at compile time this value will be bound to the class. All reference to className inside the methods of the class needs to be changed to self.className for the code to work as expected.
class Temp:
className = className # note this line
def __init__ (self, dataFrame):
self.column = dataFrame[self.className] # and this line with the original snippet
You can use the type function, however, to create such dynamic classes. names = ['name1', 'name2'] Suppose you have to create 10 class objects in python, and do something with them, like: obj_1 = MyClass() other_object.
Hope I could help you.
Well, there is a a kind of messy way to do this using the "exec()" function which takes any string and executes it; then you can build your classes as a string and run that. Here is an example which builds your classes, you can see that they are declared by looking in the global namespace which is printed at the end.
classList = ['foo', 'bar', 'baz']
class BaseCalc():
def __init__ (self, dataFrame):
self.column = dataFrame[className]
def calc ():
return self.column.sum()
for className in classList:
template = '''class %s_calc(BaseCalc):
def __init__ (self, dataFrame):
self.column = dataFrame[className]
def calc ():
return self.column.sum()''' % className
exec(template)
print(globals())
class Test():
def __init__(self):
self.__test = "cats"
print(self.__test)
def __example(self):
print("Hello World")
x = Test()
print(x.__dict__)
With the code I wrote above, the print statement will show to access the variable test, I will need to write _Test__test, however as shown I can print the variable if I call it directly afterwards within the __init__ method. So my question is, if I can access it directly after it has been declared by its name i.e self.__test, at which point does it become mangled?
Attributes accessed via .__ are mangled anywhere in the class body (But an inner class declaration would get to it first.).
Think of it as syntactic sugar.
In the context of the Test class body, self.__test is an alias to the mangled name self._Test__test; in context, they mean exactly the same thing.
A demonstration would make this clearer. First, some helper classes.
class PrintAttrAccess:
def __getattr__(self, name):
print(name)
class Empty: pass
Now for the demonstration:
class Test:
print('IN TEST BODY')
(lambda: PrintAttrAccess().__in_lambda)() # Anywhere in the class body works.
classfoo = Empty()
classfoo.__foo = 'foo'
print("Same thing?", classfoo.__foo is classfoo._Test__foo)
print("vars() of classfoo:", vars(classfoo))
class Inner:
print('IN INNER')
PrintAccess().__inner
def __init__(self):
print('IN INIT')
print("Who am I?", self)
self.__test = "cats"
print(self._Test__test) # It's ALREADY MANGLED!
# This line means exactly the same as the one above.
print(self.__test)
localfoo = Empty()
localfoo.__spam = 'spam' # "self" isn't special.
print("vars() of localfoo:", vars(localfoo))
def outside_method(self):
print('OUTSIDE BODY')
print("Who am I?", self)
self.__test = "dogs"
print(self._Test__test)
print(self.__test) # Sugar doesn't apply outside of class body.
Test.outside_method = outside_method # Add a new method to Test class.
Test().outside_method() # init and call as method.
The output is:
IN TEST BODY
_Test__in_lambda
Same thing? True
vars() of classfoo: {'_Test__foo': 'foo'}
IN INNER
_Inner__inner
IN INIT
Who am I? <__main__.Test object at 0x000001CCF3048978>
cats
cats
vars() of localfoo: {'_Test__spam': 'spam'}
OUTSIDE BODY
Who am I? <__main__.Test object at 0x000001CCF3048978>
cats
dogs
If I can access it directly after it has been declared by its name i.e self.__test, at which point does it become mangled?
It becomes mangled when you reference it from outside the class.
Your line 5, print(self.__test) isn't mangled because you're referencing it from inside the class. It's only mangled once you refer to it from outside the class. Thus, you would call
print(x._Test__test)
Note that, you could also use self._Test__test within your class.
class Test():
def __init__(self):
self.__test = "cats"
def get(self):
return self._Test__test
x = Test()
print(x.get()) ## cats
I think this article explains it pretty well: The Meaning of Underscores in Python.
I am curious how to create a custom method for a class at runtime...
I mean for example with name of method, name of parameters, body of method read from database and assign this method to a class or to an instance.
I have a found possibility to add method that is already written:
class A:
def __init__(self):
pass
def method(self):
return True
A.method = method
a = A()
print(a.method())
but I am interested in completely assembling a new method from scratch:
name = "method"
params = ["self"] # Params in list should be a strings
body = "return True"
# To create method from pieces
Is it possible using __dict__ ? Or how else this be done?
Methods are another attribute on the object that is the class. They can be added like other attributes:
Code:
class A:
def __init__(self):
pass
def method(self):
return True
def another_method(self):
return False
setattr(A, 'another_method', another_method)
Test Code:
a = A()
print(a.another_method())
Results:
False
Methods from a string:
Add if you really need to get your methods from a database or such you can use exec like:
method_string = """
def yet_another_method(self):
return type(self).__name__
"""
exec(method_string)
setattr(A, 'yet_another_method', yet_another_method)
a = A()
print(a.yet_another_method())
Results:
A
This answer has to be treated with care, using exec or eval can run arbitary code and may compromise your system. So if you rely on user-input to create the function you mustn't use this!!!
The warning aside you can simply create anything using exec:
exec("""
def method():
return True
""")
>>> method()
True
So what you basically need is just a way to get your requirements in there:
functionname = 'funfunc'
parameters = ['a', 'b']
body = 'return a + b'
exec("""
def {functionname}({parameters}):
{body}
""".format(
functionname=functionname,
parameters=', '.join(parameters),
body='\n'.join([' {line}'.format(line=line) for line in body.split('\n')])))
The body will be indented so that it's valid syntax and the parameter list will be joined using ,. And the test:
>>> funfunc(1, 2)
3
One of the best solutions that I have found is the following:
def import_code(code, name, add_to_sys_modules=0):
"""
Import dynamically generated code as a module. code is the
object containing the code (a string, a file handle or an
actual compiled code object, same types as accepted by an
exec statement). The name is the name to give to the module,
and the final argument says wheter to add it to sys.modules
or not. If it is added, a subsequent import statement using
name will return this module. If it is not added to sys.modules
import will try to load it in the normal fashion.
import foo
is equivalent to
foofile = open("/path/to/foo.py")
foo = importCode(foofile,"foo",1)
Returns a newly generated module.
"""
import sys,imp
module = imp.new_module(name)
exec(code,module.__dict__)
if add_to_sys_modules:
sys.modules[name] = module
return module
class A:
def __init__(self):
pass
name = "method"
params = ["self"] # Params in list should be a strings
body = "return True"
scratch = "def {0}({1}):\n\t{2}".format(name, ','.join(params), body)
new_module = import_code(scratch, "test")
A.method = new_module.method
a = A()
print(a.method())
Original function import_code by the following link http://code.activestate.com/recipes/82234-importing-a-dynamically-generated-module/
Using this solution I can dynamically create methods, load them in runtime and link to whatever I want object !!
This question already has answers here:
Getting the name of a variable as a string
(32 answers)
Closed 3 years ago.
While building a new class object in python, I want to be able to create a default value based on the instance name of the class without passing in an extra argument. How can I accomplish this? Here's the basic pseudo-code I'm trying for:
class SomeObject():
defined_name = u""
def __init__(self, def_name=None):
if def_name == None:
def_name = u"%s" % (<INSTANCE NAME>)
self.defined_name = def_name
ThisObject = SomeObject()
print ThisObject.defined_name # Should print "ThisObject"
Well, there is almost a way to do it:
#!/usr/bin/env python
import traceback
class SomeObject():
def __init__(self, def_name=None):
if def_name == None:
(filename,line_number,function_name,text)=traceback.extract_stack()[-2]
def_name = text[:text.find('=')].strip()
self.defined_name = def_name
ThisObject = SomeObject()
print ThisObject.defined_name
# ThisObject
The traceback module allows you to peek at the code used to call SomeObject().
With a little string wrangling, text[:text.find('=')].strip() you can
guess what the def_name should be.
However, this hack is brittle. For example, this doesn't work so well:
ThisObject,ThatObject = SomeObject(),SomeObject()
print ThisObject.defined_name
# ThisObject,ThatObject
print ThatObject.defined_name
# ThisObject,ThatObject
So if you were to use this hack, you have to bear in mind that you must call SomeObject()
using simple python statement:
ThisObject = SomeObject()
By the way, as a further example of using traceback, if you define
def pv(var):
# stack is a list of 4-tuples: (filename, line number, function name, text)
# see http://docs.python.org/library/traceback.html#module-traceback
#
(filename,line_number,function_name,text)=traceback.extract_stack()[-2]
# ('x_traceback.py', 18, 'f', 'print_var(y)')
print('%s: %s'%(text[text.find('(')+1:-1],var))
then you can call
x=3.14
pv(x)
# x: 3.14
to print both the variable name and its value.
Instances don't have names. By the time the global name ThisObject gets bound to the instance created by evaluating the SomeObject constructor, the constructor has finished running.
If you want an object to have a name, just pass the name along in the constructor.
def __init__(self, name):
self.name = name
You can create a method inside your class that check all variables in the current frame and use hash() to look for the self variable.
The solution proposed here will return all the variables pointing to the instance object.
In the class below, isinstance() is used to avoid problems when applying hash(), since some objects like a numpy.array or a list, for example, are unhashable.
import inspect
class A(object):
def get_my_name(self):
ans = []
frame = inspect.currentframe().f_back
tmp = dict(frame.f_globals.items() + frame.f_locals.items())
for k, var in tmp.items():
if isinstance(var, self.__class__):
if hash(self) == hash(var):
ans.append(k)
return ans
The following test has been done:
def test():
a = A()
b = a
c = b
print c.get_my_name()
The result is:
test()
#['a', 'c', 'b']
This cannot work, just imagine this: a = b = TheMagicObjet(). Names have no effect on Values, they just point to them.
One horrible, horrible way to accomplish this is to reverse the responsibilities:
class SomeObject():
def __init__(self, def_name):
self.defined_name = def_name
globals()[def_name] = self
SomeObject("ThisObject")
print ThisObject.defined_name
If you wanted to support something other than global scope, you'd have to do something even more awful.
In Python, all data is stored in objects. Additionally, a name can be bound with an object, after which that name can be used to look up that object.
It makes no difference to the object what names, if any, it might be bound to. It might be bound to dozens of different names, or none. Also, Python does not have any "back links" that point from an object to a name.
Consider this example:
foo = 1
bar = foo
baz = foo
Now, suppose you have the integer object with value 1, and you want to work backwards and find its name. What would you print? Three different names have that object bound to them, and all are equally valid.
print(bar is foo) # prints True
print(baz is foo) # prints True
In Python, a name is a way to access an object, so there is no way to work with names directly. You could search through various name spaces until you find a name that is bound with the object of interest, but I don't recommend this.
How do I get the string representation of a variable in python?
There is a famous presentation called "Code Like a Pythonista" that summarizes this situation as "Other languages have 'variables'" and "Python has 'names'"
http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables
If you want an unique instance name for a class, try __repr__() or id(self)
class Some:
def __init__(self):
print(self.__repr__()) # = hex(id(self))
print(id(self))
It will print the memory address of the instance, which is unique.
Inspired by the answers of unutbu and Saullo Castro, I have created a more sophisticated class that can even be subclassed. It solves what was asked for in the question.
"create a default value based on the instance name of the class
without passing in an extra argument."
Here's what it does, when an instance of this class or a subclass is created:
Go up in the frame stack until the first frame which does not belong to a method of the current instance.
Inspect this frame to get the attributes self.creation_(name/file/module/function/line/text).
Perform an an additional check whether an object with name self.creation_name was actually defined in the frame's locals() namespace to make 100% sure the found creation_name is correct or raise an error otherwise.
The Code:
import traceback, threading, time
class InstanceCreationError(Exception):
pass
class RememberInstanceCreationInfo:
def __init__(self):
for frame, line in traceback.walk_stack(None):
varnames = frame.f_code.co_varnames
if varnames is ():
break
if frame.f_locals[varnames[0]] not in (self, self.__class__):
break
# if the frame is inside a method of this instance,
# the first argument usually contains either the instance or
# its class
# we want to find the first frame, where this is not the case
else:
raise InstanceCreationError("No suitable outer frame found.")
self._outer_frame = frame
self.creation_module = frame.f_globals["__name__"]
self.creation_file, self.creation_line, self.creation_function, \
self.creation_text = \
traceback.extract_stack(frame, 1)[0]
self.creation_name = self.creation_text.split("=")[0].strip()
super().__init__()
threading.Thread(target=self._check_existence_after_creation).start()
def _check_existence_after_creation(self):
while self._outer_frame.f_lineno == self.creation_line:
time.sleep(0.01)
# this is executed as soon as the line number changes
# now we can be sure the instance was actually created
error = InstanceCreationError(
"\nCreation name not found in creation frame.\ncreation_file: "
"%s \ncreation_line: %s \ncreation_text: %s\ncreation_name ("
"might be wrong): %s" % (
self.creation_file, self.creation_line, self.creation_text,
self.creation_name))
nameparts = self.creation_name.split(".")
try:
var = self._outer_frame.f_locals[nameparts[0]]
except KeyError:
raise error
finally:
del self._outer_frame
# make sure we have no permament inter frame reference
# which could hinder garbage collection
try:
for name in nameparts[1:]: var = getattr(var, name)
except AttributeError:
raise error
if var is not self: raise error
def __repr__(self):
return super().__repr__()[
:-1] + " with creation_name '%s'>" % self.creation_name
A simple example:
class MySubclass(RememberInstanceCreationInfo):
def __init__(self):
super().__init__()
def print_creation_info(self):
print(self.creation_name, self.creation_module, self.creation_function,
self.creation_line, self.creation_text, sep=", ")
instance = MySubclass()
instance.print_creation_info()
#out: instance, __main__, <module>, 68, instance = MySubclass()
If the creation name cannot be determined properly an error is raised:
variable, another_instance = 2, MySubclass()
# InstanceCreationError:
# Creation name not found in creation frame.
# creation_file: /.../myfile.py
# creation_line: 71
# creation_text: variable, another_instance = 2, MySubclass()
# creation_name (might be wrong): variable, another_instance
I think that names matters if they are the pointers to any object..
no matters if:
foo = 1
bar = foo
I know that foo points to 1 and bar points to the same value 1 into the same memory space.
but supose that I want to create a class with a function that adds a object to it.
Class Bag(object):
def __init__(self):
some code here...
def addItem(self,item):
self.__dict__[somewaytogetItemName] = item
So, when I instantiate the class bag like below:
newObj1 = Bag()
newObj2 = Bag()
newObj1.addItem(newObj2)I can do this to get an attribute of newObj1:
newObj1.newObj2
The best way is really to pass the name to the constructor as in the chosen answer. However, if you REALLY want to avoid asking the user to pass the name to the constructor, you can do the following hack:
If you are creating the instance with 'ThisObject = SomeObject()' from the command line, you can get the object name from the command string in command history:
import readline
import re
class SomeObject():
def __init__(self):
cmd = readline.get_history_item(readline.get_current_history_length())
self.name = re.split('=| ',cmd)[0]
If you are creating the instance using 'exec' command, you can handle this with:
if cmd[0:4] == 'exec': self.name = re.split('\'|=| ',cmd)[1] # if command performed using 'exec'
else: self.name = re.split('=| ',cmd)[0]