How would I copy all the properties of a class to a new instance of the class.
In the example below, with the way python works, when I use b=a, it assigns b and a to the same memory address. When i make a change to "b" the change is also made to "a."
Both elements of the list are stored at the same address
class test:
def __init__(self, name="Name",data=[]):
self.name=name
self.data=data
list=[]
a = test("First Name",["DATA1","DATA2","DATA3"])
b=a
list.append(a)
list.append(b)
I'm wanting to achieve something similar to how the list class allows you to do this to copy the list to a new memory address.
list1=[1,2,3]
list2=list(list1)
So in my case.
a = test("First Name",["DATA1","DATA2","DATA3"])
b=test(a)
without having to
b=test(a.name,a.data)
EDIT
Id like to achive the same effect as
b=copy.deepcopy(a)
but through this usage.
b=test(a)
Use copy:
import copy
b = copy.deepcopy(a)
You may want to write a copy constructor. For example...
import copy
class Foo:
def __init__(self, data):
self._data = data
#classmethod
def from_foo(cls, class_instance):
data = copy.deepcopy(class_instance._data)
return cls(data)
This achieved what I was wanting to do.
class Test:
def __init__(self, arg):
if isinstance(somearg, self.__class__):
self.__dict__ = somearg.__dict__.copy()
else:
self.var = arg
Usage:
a=Test(123)
b=Test(a)
Related
I'm new to python so I don't know much.
I was defining a function to work with lists and I want that function to be used like an attribute. For example to sort a list we use: list.sort()
Basically, instead of using the function like function(list) I want to use it like this: list.function()
You have to create a class
class MyClass():
def function(self, param):
print(param)
myClass = MYClass()
myClass.function()
You can see here or here for more details
You'll have to make a class that inherits the list class.
class MyList(list):
def __init__(self, *args):
super().__init__(*args)
def all_caps(self):
return [item.upper() if isinstance(item, str) else item for item in self]
mylist = MyList(['hi', 'hello', 1234])
mylist.all_caps()
You will have to create a custom class that inherit from original list and then using builtins module assign new extended class to previous list:
import builtins
class my_list(list):
def f(self):
return sum(self)
builtins.list = my_list
arr = list([1,2,3])
x = arr.f()
print(x)
Output:
6
Warning
Remember that you need to create every list using list() function to make sure your method will work.
Is there a copy constructor in python ? If not what would I do to achieve something similar ?
The situation is that I am using a library and I have extended one of the classes there with extra functionality and I want to be able to convert the objects I get from the library to instances of my own class.
I think you want the copy module
import copy
x = copy.copy(y) # make a shallow copy of y
x = copy.deepcopy(y) # make a deep copy of y
you can control copying in much the same way as you control pickle.
In python the copy constructor can be defined using default arguments. Lets say you want the normal constructor to run the function non_copy_constructor(self) and the copy constructor should run copy_constructor(self, orig). Then you can do the following:
class Foo:
def __init__(self, orig=None):
if orig is None:
self.non_copy_constructor()
else:
self.copy_constructor(orig)
def non_copy_constructor(self):
# do the non-copy constructor stuff
def copy_constructor(self, orig):
# do the copy constructor
a=Foo() # this will call the non-copy constructor
b=Foo(a) # this will call the copy constructor
A simple example of my usual implementation of a copy constructor:
import copy
class Foo:
def __init__(self, data):
self._data = data
#classmethod
def from_foo(cls, class_instance):
data = copy.deepcopy(class_instance._data) # if deepcopy is necessary
return cls(data)
For your situation, I would suggest writing a class method (or it could be a static method or a separate function) that takes as an argument an instance of the library's class and returns an instance of your class with all applicable attributes copied over.
Building on #Godsmith's train of thought and addressing #Zitrax's need (I think) to do the data copy for all attributes within the constructor:
class ConfusionMatrix(pd.DataFrame):
def __init__(self, df, *args, **kwargs):
try:
# Check if `df` looks like a `ConfusionMatrix`
# Could check `isinstance(df, ConfusionMatrix)`
# But might miss some "ConfusionMatrix-elligible" `DataFrame`s
assert((df.columns == df.index).all())
assert(df.values.dtype == int)
self.construct_copy(df, *args, **kwargs)
return
except (AssertionError, AttributeError, ValueError):
pass
# df is just data, so continue with normal constructor here ...
def construct_copy(self, other, *args, **kwargs):
# construct a parent DataFrame instance
parent_type = super(ConfusionMatrix, self)
parent_type.__init__(other)
for k, v in other.__dict__.iteritems():
if hasattr(parent_type, k) and hasattr(self, k) and getattr(parent_type, k) == getattr(self, k):
continue
setattr(self, k, deepcopy(v))
This ConfusionMatrix class inherits a pandas.DataFrame and adds a ton of other attributes and methods that need to be recomputed unless the other matrix data can be copied over. Searching for a solution is how I found this question.
I have a similar situation differing in that the new class only needs to copy attributes. Thus using #Dunham's idea and adding some specificity to #meisterluk's suggestion, #meisterluk's "copy_constructor" method could be:
from copy import deepcopy
class Foo(object):
def __init__(self, myOne=1, other=None):
self.two = 2
if other <> None:
assert isinstance(other, Foo), "can only copy instances of Foo"
self.__dict__ = deepcopy(other.__dict__)
self.one = myOne
def __repr__(self):
out = ''
for k,v in self.__dict__.items():
out += '{:>4s}: {}, {}\n'.format(k,v.__class__,v)
return out
def bar(self):
pass
foo1 = Foo()
foo2 = Foo('one', foo1)
print '\nfoo1\n',foo1
print '\nfoo2\n',foo2
The output:
foo1
two: <type 'int'>, 2
one: <type 'int'>, 1
foo2
two: <type 'int'>, 2
one: <type 'str'>, one
The following solution probably repeats some of the previous ones in a simple form. I don't know how it is "pythocally" right, but it works and was quite convenient in the certain case I used it.
class Entity:
def __init__(self, code=None, name=None, attrs=None):
self.code = code
self.name = name
self.attrs = {} if attrs is None else attrs
def copy(self, attrs=None):
new_attrs = {k: v.copy() for k, v in self.attrs.items()} if attrs is None else attrs
return Entity(code=self.code, name=self.name, attrs=new_attrs)
Usage:
new_entity = entity.copy()
This is a more complicated version that allows to interfere in the copying process. I used it in only one place. Also note that objects contained in self.attrs also have such kind of "copying constructor".
This solution is not generic but is very simple and provides quite much control.
you can achieve like this code
without using any copy module
Python dosen't support method overloding
so we can not make copy constructor ##
class student():
name: str
age: int
def __init__(self, other=None):
if other != None and isinstance(other, student):
self.name = other.name
self.age = other.age
elif not(isinstance(other,student)) and other!=None:
raise TypeError
def printInfo(s):
print(s.name, s.age)
I'm working on a code dealing with dict data on python.
While implementing such class, I have to define a lot of properties. It's not that hard, but recently I thought it would be much better if I could use something like helper function.
For example, let's assume that I have a class like the following.
class MyClass(object):
def __init__(self, data):
self.data = data
#property
def version(self):
return self.data["version"]
If I could write this class in something like the following.
class MyClass(object):
def __init__(self, data):
self.data = data
define_own_property("data", "version")
It looks trivial, but if I can do that, I think I can reuse a lot of validation/exception handling cases.
Any idea? :D
You can achieve something like that by just writing a function to return the accessor you want:
def define_own_property(attr, key):
def prop(self):
return getattr(self, attr)[key]
return property(prop)
class MyClass(object):
def __init__(self, data):
self.data = data
version = define_own_property("data", "version")
Note that you must do version = ... There is no way to make a simple function call define_own_property add a property to the class being defined, because that class doesn't yet exist so you can't reference it.
Another possibility is to give your class an attribute that is a list or dict or something containing the relevant parameters ("data", "version", etc.), then write a class decorator that reads these parameters and auto-creates the series of properties. This would remove the need to define the properties inside the class at all; you would just give a list of the things you wanted the properties to access, and use the decorator once on the class.
It seems like you could use a descriptor:
class Descr(object):
def __init__(self,attr,key):
self.attr = attr
self.key = key
def __get__(self,obj,type=None):
return getattr(obj,self.attr)[self.key]
def __set__(self,obj,value):
getattr(obj,self.attr)[self.key] = value
def __delete__(self,obj):
del getattr(obj,self.attr)[self.key]
class MyClass(object):
def __init__(self, data):
self.data = data
version = Descr("data","version")
foobar = Descr("data","foobar")
a = MyClass({})
a.version = 1
print a.version
a.foobar = 'string'
print a.data
I have a class that keeps track of its instances in a class variable, something like this:
class Foo:
by_id = {}
def __init__(self, id):
self.id = id
self.by_id[id] = self
What I'd like to be able to do is iterate over the existing instances of the class. I can do this with:
for foo in Foo.by_id.values():
foo.do_something()
but it would look neater like this:
for foo in Foo:
foo.do_something()
is this possible? I tried defining a classmethod __iter__, but that didn't work.
If you want to iterate over the class, you have to define a metaclass which supports iteration.
x.py:
class it(type):
def __iter__(self):
# Wanna iterate over a class? Then ask that class for iterator.
return self.classiter()
class Foo:
__metaclass__ = it # We need that meta class...
by_id = {} # Store the stuff here...
def __init__(self, id): # new isntance of class
self.id = id # do we need that?
self.by_id[id] = self # register istance
#classmethod
def classiter(cls): # iterate over class by giving all instances which have been instantiated
return iter(cls.by_id.values())
if __name__ == '__main__':
a = Foo(123)
print list(Foo)
del a
print list(Foo)
As you can see in the end, deleting an instance will not have any effect on the object itself, because it stays in the by_id dict. You can cope with that using weakrefs when you
import weakref
and then do
by_id = weakref.WeakValueDictionary()
. This way the values will only kept as long as there is a "strong" reference keeping it, such as a in this case. After del a, there are only weak references pointing to the object, so they can be gc'ed.
Due to the warning concerning WeakValueDictionary()s, I suggest to use the following:
[...]
self.by_id[id] = weakref.ref(self)
[...]
#classmethod
def classiter(cls):
# return all class instances which are still alive according to their weakref pointing to them
return (i for i in (i() for i in cls.by_id.values()) if i is not None)
Looks a bit complicated, but makes sure that you get the objects and not a weakref object.
Magic methods are always looked up on the class, so adding __iter__ to the class won't make it iterable. However the class is an instance of its metaclass, so the metaclass is the correct place to define the __iter__ method.
class FooMeta(type):
def __iter__(self):
return self.by_id.iteritems()
class Foo:
__metaclass__ = FooMeta
...
Try this:
You can create a list with a global scope, define a list in the main module as follows:
fooList = []
Then add:
class Foo:
def __init__(self):
fooList.append(self)
to the init of the foo class
Then everytime you create an instance of the Foo class it will be added to the fooList list.
Now all you have to do is iterate through the array of objects like this
for f in fooList:
f.doSomething()
You can create a comprehension list and then call member methods as follows:
class PeopleManager:
def __init__(self):
self.People = []
def Add(self, person):
self.People.append(person)
class Person:
def __init__(self,name,age):
self.Name = name
self.Age = age
m = PeopleManager()
[[t.Name,t.Age] for t in m.People]
call to fill the object list:
m = PeopleManager()
m.Add( Person("Andy",38))
m.Add( Person("Brian",76))
You can create a class list and then call append in the init method as follows:
class Planet:
planets_list = []
def __init__(self, name):
self.name = name
self.planets_list.append(self)
Usage:
p1 = Planet("earth")
p2 = Planet("uranus")
for i in Planet.planets_list:
print(i.name)
How can I implement recursion in a deep copy function object? This is the relevant code (if you want more then please ask):
PS: I would like the recursion to iterate through a filtered list of references. The goal is to download and insert any missing objects.
copy.py
from put import putter
class copier:
def __init__(self, base):
self.base = base
def copyto(self, obj):
put = putter(obj)
for x in self.base.__dict__:
put(x)
put.py
class putter:
def __init__(self, parent):
self.parent = parent
def put(self, name, obj):
self.parent.__dict__[name] = obj
Check out the documentation for copy.deepcopy, if you can implement what you want with __getinitargs__(), __getstate__() and __setstate__(), then that will save you a lot of grief. Otherwise, you will need to reimplement it yourself, it should look something like:
def deepcopyif(obj, shouldcopyprop):
copied = {} # Remember what has already been copied
def impl(obj):
if obj in copied:
return copied[obj]
newobj = *** Create a copy ***
copied[obj] = newobj # IMPORTANT: remember the new object before recursing
for name, value in obj.__dict__: # or whatever...
if shouldcopyprop(obj.__class__, name): # or whatever
value = impl(value) # RECURSION: this will copy the property value
newobj.__dict__[prop] = value
return newobj
return impl(obj)