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)
Related
I'm trying to find a way to represent a file structure as python objects so I can easily get a specific path without having to type out the string everything. This works for my case because I have a static file structure (Not changing).
I thought I could represent directories as class's and files in the directory as class/static variables.
I want to be able to navigate through python objects so that it returns the path I want i.e:
print(FileStructure.details.file1) # root\details\file1.txt
print(FileStructure.details) # root\details
What I get instead from the code below is:
print("{0}".format(FileStructure())) # root
print("{0}".format(FileStructure)) # <class '__main__.FileStructure'>
print("{0}".format(FileStructure.details)) # <class '__main__.FileStructure.details'>
print("{0}".format(FileStructure.details.file1)) # details\file1.txt
The code I have so far is...
import os
class FileStructure(object): # Root directory
root = "root"
class details(object): # details directory
root = "details"
file1 = os.path.join(root, "file1.txt") # File in details directory
file2 = os.path.join(root, "file2.txt") # File in details directory
def __str__(self):
return f"{self.root}"
def __str__(self):
return f"{self.root}"
I don't want to have to instantiate the class to have this work. My question is:
How can I call the class object and have it return a string instead
of the < class ....> text
How can I have nested classes use their parent classes?
Let's start with: you probably don't actually want this. Python3's pathlib API seems nicer than this and is already in wide support.
root = pathlib.Path('root')
file1 = root / 'details' / 'file1' # a Path object at that address
if file1.is_file():
file1.unlink()
else:
try:
file1.rmdir()
except OSError as e:
# directory isn't empty
But if you're dead set on this for some reason, you'll need to override __getattr__ to create a new FileStructure object and keep track of parents and children.
class FileStructure(object):
def __init__(self, name, parent):
self.__name = name
self.__children = []
self.__parent = parent
#property
def parent(self):
return self.__parent
#property
def children(self):
return self.__children
#property
def name(self):
return self.__name
def __getattr__(self, attr):
# retrieve the existing child if it exists
fs = next((fs for fs in self.__children if fs.name == attr), None)
if fs is not None:
return fs
# otherwise create a new one, append it to children, and return it.
new_name = attr
new_parent = self
fs = self.__class__(new_name, new_parent)
self.__children.append(fs)
return fs
Then use it with:
root = FileStructure("root", None)
file1 = root.details.file1
You can add a __str__ and __repr__ to help your representations. You could even include a path property
# inside FileStructure
#property
def path(self):
names = [self.name]
cur = self
while cur.parent is not None:
cur = cur.parent
names.append(cur.name)
return '/' + '/'.join(names[::-1])
def __str__(self):
return self.path
Up front: This is a bad solution, but it meets your requirements with minimal changes. Basically, you need instances for __str__ to work, so this cheats using the decorator syntax to change your class declaration into a singleton instantiation of the declared class. Since it's impossible to reference outer classes from nested classes implicitly, the reference is performed explicitly. And to reuse __str__, file1 and file2 were made into #propertys so they can use the str form of the details instance to build themselves.
#object.__new__
class FileStructure(object): # Root directory
root = "root"
#object.__new__
class details(object): # details directory
root = "details"
#property
def file1(self):
return os.path.join(str(self), 'file1')
#property
def file2(self):
return os.path.join(str(self), 'file2')
def __str__(self):
return f"{os.path.join(FileStructure.root, self.root)}"
def __str__(self):
return f"{self.root}"
Again: While this does produce your desired behavior, this is still a bad solution. I strongly suspect you've got an XY problem here, but this answers the question as asked.
There exists such class in HTMLgen:
import HTMLutil
class Directory(UserList)
def __cmp__(self, item)
def __init__(self, name='root', data=None)
def add_object(self, pathlist, object)
def ls(self, pad='')
def tree(self)
# Methods inherited by Directory from UserList
def __add__(self, list)
def __delitem__(self, i)
def __delslice__(self, i, j)
def __getitem__(self, i)
def __getslice__(self, i, j)
def __len__(self)
def __mul__(self, n)
def __mul__(self, n)
def __radd__(self, list)
def __repr__(self)
def __setitem__(self, i, item)
def __setslice__(self, i, j, list)
def append(self, item)
def count(self, item)
def index(self, item)
def insert(self, i, item)
def remove(self, item)
def reverse(self)
def sort(self, *args)
Unfortunately, this package is very old. When I tried to understand code for Directory.__cmp__, I failed. It is supposed to compare directory structures, but it calls a function cmp for that, and where that function comes from is unclear to me (types in Python 3 have no such function). I'm not sure it works any longer.
I thought about creating such package myself to test directory hierarchies (I created a file synchronization program). However, as suggested in answers above, pathlib might be a better approach, as well as dircmp from filecmp and rmtree from shutil.
The downside of these standard modules is that they are low-level, so if someone creates a library to deal with all these tasks in one place, that would be great.
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)
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)
Say I have a very simple data type:
class SimpleObject:
def __init__(self, property):
self.property = property
def update_property(self, value):
self.property = value
And I a special kind of list to store the data type:
class SimpleList(collections.MutableSequence):
def update_useful_property_of_list(self, value):
self.useful_property_of_list = value
And I store them:
simple1 = SimpleObject(1)
simple2 = SimpleObject(2)
simple_list = SimpleList([simple1, simple2])
Is there any way for the SimpleList object to know when one of the properties of its members changes? For example, how can I get simple_list to execute self.update_useful_property_of_list() when something like this happens:
simple1.update_property(3)
As noted in the comments, you are looking for the Observer design pattern. Simplest, way to do it in your example:
class SimpleObject:
def __init__(self, property, propertyChangeObserver = None):
self.property = property
self.propertyChangeObserver = propertyChangeObserver
def registerPropertyChangeObserver(self, propertyChangeObserver):
self.propertyChangeObserver = propertyChangeObserver
def update_property(self, value):
self.property = value
if self.propertyChangeObserver:
self.propertyChangeObserver.simpleObjectPropertyChanged(self)
and:
class SimpleList(collections.MutableSequence):
def __init__(self, collection):
super(SimpleList, self).__init__(collection)
for e in collection:
e.registerPropertyChangeObserver(self)
def simpleObjectPropertyChanged(self, simpleObject):
pass # react to simpleObject.property being changed
Because you've called your property "property" it's hard to demonstrate low coupling here :) I've called the method simpleObjectPropertyChanged for clarity, but in fact, SimpleList doesn't have to know that it stores SimpleObject instances - it only needs to know that they are observable instances. In a similar manner, SimpleObject doesn't know about SimpleList - it only knows about some class that needs to observe its state (an observer - hence the name of the pattern).
I have a class called dataList. It is basically a list with some metadata---myDataList.data contains the (numpy) list itself, myDataList.tag contains a description, etc. I would like to be able to make myDataList[42] return the corresponding element of myDataList.data, and I would like for Numpy, etc. to recognize it as a list (I.E., numpy.asarray(myDataList) returns a numpy array containing the data in myDataList). In Java, this would be as easy as declaring dataList as implementing the List interface, and then just defining the necessary functions. How would you do this in Python?
Thanks.
You can subclass list and provide additional methods:
class CustomList(list):
def __init__(self, *args, **kwargs):
list.__init__(self, args[0])
def foobar(self):
return 'foobar'
CustomList inherits the methods of Python's ordinary lists and you can easily let it implement further methods and/or attributes.
class mylist(list):
def __init__(self, *args, **kwargs):
super(mylist, self).__init__(*args, **kwargs) # advantage of using super function is that even if you change the parent class of mylist to some other list class, like your numpy list class, you won`t have to change the remaining code, which is what you would have to do incase of jena`s code snippet.
# whatever meta data you want to add, add here
self.tag = 'some tag'
self.id = 3
# you can also add custom methods
def foobar(self):
return 'foobar'
Now, you can create instance of mylist and use them as normal lists, with your additional meta data.
>>> a = mylist([1,2,3,4])
>>> a
[1,2,3,4]
>>> a[2] = 3 # access normal list features
>>> a.append(5) # access normal list features
>>> a
[1,2,3,4,5]
>>> a.tag # your custom meta data
'some tag'
>>> a.id # your custom meta data
3
>>> a.foobar() # your custom meta data
'foobar'
>>> a.meta1 = 'some more' # you can even add more meta data on the fly (which you cannot do in a regular list class)
>>> a.meta1
'some more' # your new meta data
Define __len__, __getitem__, __iter__ and optionally other magic methods that make up a container type.
For example, a simplified range implementation:
class MyRange(object):
def __init__(self, start, end):
self._start = start
self._end = end
def __len__(self):
return self._end - self._start
def __getitem__(self, key):
if key < 0 or key >= self.end:
raise IndexError()
return self._start + key
def __iter__(self):
return iter([self[i] for i in range(len(self))])