Overriding the default constructor when creating a deepcopy in Python - python

Let's say I have this class (simplified for the sake of clarity):
class Foo:
def __init__(self, creator_id):
self._id = get_unique_identifier()
self._owner = creator_id
self._members = set()
self._time = datetime.datetime.now()
get_creator(creator_id).add_foo(self._id)
def add_member(self, mbr_id):
self._members.add(mbr_id)
and I want to make a __deepcopy__() method for it. From what I can tell, the way that these copies are generally made is to create a new instance using the same constructor parameters as the old one, however in my case, that will result in a different identifier, a different time, and a different member set, as well as the object being referenced by the creator's object twice, which will result in breakages.
One possible workaround would be to create the new instance then modify the incorrect internal data to match, but this doesn't fix the issues where the new object's ID will still be present in the creator's data structure. of course, that could be removed manually, but that wouldn't be clean or logical to follow.
Another workaround is to have an optional copy_from parameter in the constructor, but this would add complexity to the constructor in a way that could be confusing, especially since it would only be used implicitly by the object's __deepcopy__() method. This still looks like the best option if there isn't a better way.
#...
def __init__(self, creator_id, copy_from=None):
if isinstance(copy_from, Foo):
# copy all the parameters manually
pass
else:
# normal constructor
pass
#...
Basically, I'm looking for something similar to the copy constructor in C++, where I can get a reference to the original object and then copy across its parameters without having to add unwanted complexity to the original constructor.
Any ideas are appreciated. Let me know if I've overlooked something really simple.

Related

How to copy an object in revit API using python

Is there a way I can copy a Filter Element Collector object?
For example, the original object is pointing at 0x000000000000156B and I want the copied object to be pointing at a different location so I can keep making modificacions without changing the original object.
Here's some code to illustrate my idea:
Col1 = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls)
#Some code to copy the object and assign it to Col2
Col2 = Col2.WhereElementIsNotElementType().ToElements() #Changing Col2 shouldn't change Col1.
I know there's no such method within the FilteredElementCollector class, but there should be a way to do this, right?
I also read about deepcopy but couldn't get it to work on Revit.
Any help will be highly appreciated, Thanks!
I normally use the FilteredElementCollector method by wrapping it in a Python list. Then you can combine, refine, split, copy, sort - bascially do anything you want to it with all the ease that Python offers.
For your problem above, you could create the FilteredElementCollector, and spin it off into lists as required:
rawWalls = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls)
Col1 = list(rawWalls)
print 'There are',len(Col1),'wall types+instances in Col1'
Col2 = list(rawWalls.WhereElementIsNotElementType().ToElements())
print 'There are',len(Col2),'wall instances in Col2'
As you've already figured out, it's not possible to create a copy of a FilteredElementCollector. However, you could create a functionally identical one by recording which methods are called on the original and duplicating those method calls when you need to make a copy. The class below does just that:
class CopyableFilteredElementCollector(FilteredElementCollector):
def __init__(self, doc):
# Initialize the underlying FilteredElementCollector
FilteredElementCollector.__init__(self, doc)
# Save the document
self._doc = doc
# Calls to methods that constrain the FilteredElementCollector will be recorded here
self._log = []
def copy(self):
# Create a brand new instance
copy = CopyableFilteredElementCollector(self._doc)
# Replay the log on the new instance
for method_name, args in self._log:
getattr(copy, method_name)(*args)
# The copy now references the same document as the original,
# and has had the same methods called on it
return copy
We need to override each method that restrict the elements returned by the FilteredElementCollector to record its invocation in the log. The most straightforward way to do that would be by defining override methods in the class body like this:
def OfCategory(self, category):
# Add an entry to the log containing the name of the method that was called
# and a tuple of its arguments that can be expanded with the splat operator
self._log.append(('OfCategory', (category,)))
# Call the original method
FilteredElementCollector.OfCategory(self, category)
# Return self just like the original method does
return self
Defining an override for every single method gets repetitive, so let's employ some metaprogramming voodoo instead:
# Methods of FilteredElementCollector that constrain which elements it returns
constraint_methods = [
'OfCategory',
'OfClass',
'WhereElementIsElementType',
'WhereElementIsNotElementType',
'WherePasses',
# et cetera
]
# A factory function that produces override methods similar to the one defined above
def define_method(method_name):
def method(self, *args):
self._log.append((method_name, args))
getattr(FilteredElementCollector, method_name)(self, *args)
return self
return method
# Create an override for each method and add it to the CopyableFilteredElementCollector class
for method_name in constraint_methods:
setattr(CopyableFilteredElementCollector, method_name, define_method(method_name))
I won't go as far as to claim that my approach is a good idea, but it's an option if your use case requires making copies of a FilteredElementCollector rather than creating new ones from scratch.

Python attribute that holds other existing attributes in a list

I am currently working on a python-sqlite project, and i am novice to both.
I have created a class that has some attributes declared inside the __init__ method. I need another attribute that will be a list or array, that will contain some of the already declared attributes of the class. What i want is my list to contain just a reference of the original attributes.
I need this structure in order to be able to call these attributes together, to iterate on them, but i want to be able to call them separately, too.
At first I tried to create that list attribute inside the __init__ method, after the rest declarations. When I create an instance, however, and change the initial value of one of the attributes, the attribute in the list is not updated.
Then I tried to create that same list attribute inside another method of the class, instead of inside the init, and call it from inside my code, and it did what I wanted to.
Why does the different approach has different results?
Here is the code at both cases:
Case #1
class Tools():
def __init__(self):
self.name = "defaultname"
self.manufacturer = "defaultmanuf"
self.tooldetails = [self.name, self.manufacturer]
def get_details(self):
return self.tooldetails
Case #2
class Tools():
def __init__(self):
self.name = "defaultname"
self.manufacturer = "defaultmanuf"
def _set_detail_list(self):
self.tooldetails = [self.name, self.manufacturer]
def get_details(self):
_set_detail_list()
return self.tooldetails
And when I create an instance:
tool1 = Tools()
tool1.name = 'abc'
tool1.get_details()
The first case gives me ["defaultname", "defaultmanuf"] while the second gives me ["abc","defaultmanuf"].
My question is what is the reason python gives me different output for each case? It seems like I miss something important about how initialization is working..
dir() and other similar functions or magic methods could be able to give me what i want, but i think they are not flexible enough if you want many different lists with different sets of attributes. Unluckily, introspection doesn't work very well with sqlite string-formatted commands..
Plus i am curious of the way python works, which I believe is very important..
Thanks!!
Case #1
When your list is created within __init__, it contains pointers to 2 strings. But the link between name and tooldetails is irrevocably broken once your list is created. If you update name, tooldetails will not dynamically update, unless you tell Python to explicitly update tooldetails with new data.
Case #2
Here you explicitly tell Python to reconstruct tooldetails via the method _set_detail_list, which is called within get_details. You update name and then tell Python to rebuild the tooldetails list. Therefore, if you update name followed by get_details, your list will be updated.

Init in classes - is the first argument a stand in for the instance?

I have been trying to fully understand this for a while now, and practically speaking I think I understand what happens but I can't seem to find anywhere that confirms wether I understood it correctly:
class test(object):
def __init__(self, this):
self.something = this
example = test("writing")
My question is: In the above example, is it correct that self is simply a stand-in for the instance I am creating? Meaning that when i create an instance and assign it to "example", then "example is put in place of self and behind the scenes does something resembling this:
class test(object):
def __init__(example, this):
example.something = this
example = test("writing")
Furthermore, does that also mean that as long as I am still working with this on a class basis (say in tandem with another class) I should still be using self.something, while I should be using example.something if I am working with it on an instance level?
I hope that made somewhat sense, im still trying to wrap my head properly around all of it, so let me know if I need to try and rephrase it.
For reference sake, should someone else end up asking the same, this reply: Python __init__ and self what do they do? almost did the trick for me, and only really left me a bit in doubt about the above questions.
This is correct. self is the instance of the class (i.e. the object) and you use it inside the class code (inside it's methods).
While the first argument can be named something else (example in your second code), the convention is that we always use self or the code might be highly confusing for other programmers. But you got the gist right by doing that, the example variable in the class (i.e. the self in your first code) and the example variable outside of the class is basically the same thing.
By the way, I'd also avoid the following two things:
having a class name that starts with a small leter case,
using a variable name this (since a variable named this does in some other languages essentially what self does in Python).
In Python, variables do not "contain" objects, they refer to them. So:
class test(object):
def __init__(self, this):
self.something = this
example = test("writing")
In this case example is a reference to the new object, but so is self. It is perfectly legal, and common, to have multiple references to the same object.
If you did:
another = example
this would not create a new object but have another reference to the same object. another, example (and self) would be references to the same single object.
You can test this by looking at the object's unique identifier, using id(). Add:
another = example
print id(another)
print id(example)
you will find that their id's are the same.

What happens when we edit(append, remove...) a list and can we execute actions each time a list is edited

I would like to know if there is a way to create a list that will execute some actions each time I use the method append(or an other similar method).
I know that I could create a class that inherits from list and overwrite append, remove and all other methods that change content of list but I would like to know if there is an other way.
By comparison, if I want to print 'edited' each time I edit an attribute of an object I will not execute print("edited") in all methods of the class of that object. Instead, I will only overwrite __setattribute__.
I tried to create my own type which inherits of list and overwrite __setattribute__ but that doesn't work. When I use myList.append __setattribute__ isn't called. I would like to know what's realy occured when I use myList.append ? Is there some magic methods called that I could overwrite ?
I know that the question have already been asked there : What happens when you call `append` on a list?. The answer given is just, there is no answer... I hope it's a mistake.
I don't know if there is an answer to my request so I will also explain you why I'm confronted to that problem. Maybe I can search in an other direction to do what I want. I have got a class with several attributes. When an attribute is edited, I want to execute some actions. Like I explain before, to do this I am use to overwrite __setattribute__. That works fine for most of attributes. The problem is lists. If the attribute is used like this : myClass.myListAttr.append(something), __setattribute__ isn't called while the value of the attribute have changed.
The problem would be the same with dictionaries. Methods like pop doesn't call __setattribute__.
If I understand correctly, you would want something like Notify_list that would call some method (argument to the constructor in my implementation) every time a mutating method is called, so you could do something like this:
class Test:
def __init__(self):
self.list = Notify_list(self.list_changed)
def list_changed(self,method):
print("self.list.{} was called!".format(method))
>>> x = Test()
>>> x.list.append(5)
self.list.append was called!
>>> x.list.extend([1,2,3,4])
self.list.extend was called!
>>> x.list[1] = 6
self.list.__setitem__ was called!
>>> x.list
[5, 6, 2, 3, 4]
The most simple implementation of this would be to create a subclass and override every mutating method:
class Notifying_list(list):
__slots__ = ("notify",)
def __init__(self,notifying_method, *args,**kw):
self.notify = notifying_method
list.__init__(self,*args,**kw)
def append(self,*args,**kw):
self.notify("append")
return list.append(self,*args,**kw)
#etc.
This is obviously not very practical, writing the entire definition would be very tedious and very repetitive, so we can create the new subclass dynamically for any given class with functions like the following:
import functools
import types
def notify_wrapper(name,method):
"""wraps a method to call self.notify(name) when called
used by notifying_type"""
#functools.wraps(method)
def wrapper(*args,**kw):
self = args[0]
# use object.__getattribute__ instead of self.notify in
# case __getattribute__ is one of the notifying methods
# in which case self.notify will raise a RecursionError
notify = object.__getattribute__(self, "_Notify__notify")
# I'd think knowing which method was called would be useful
# you may want to change the arguments to the notify method
notify(name)
return method(*args,**kw)
return wrapper
def notifying_type(cls, notifying_methods="all"):
"""creates a subclass of cls that adds an extra function call when calling certain methods
The constructor of the subclass will take a callable as the first argument
and arguments for the original class constructor after that.
The callable will be called every time any of the methods specified in notifying_methods
is called on the object, it is passed the name of the method as the only argument
if notifying_methods is left to the special value 'all' then this uses the function
get_all_possible_method_names to create wrappers for nearly all methods."""
if notifying_methods == "all":
notifying_methods = get_all_possible_method_names(cls)
def init_for_new_cls(self,notify_method,*args,**kw):
self._Notify__notify = notify_method
namespace = {"__init__":init_for_new_cls,
"__slots__":("_Notify__notify",)}
for name in notifying_methods:
method = getattr(cls,name) #if this raises an error then you are trying to wrap a method that doesn't exist
namespace[name] = notify_wrapper(name, method)
# I figured using the type() constructor was easier then using a meta class.
return type("Notify_"+cls.__name__, (cls,), namespace)
unbound_method_or_descriptor = ( types.FunctionType,
type(list.append), #method_descriptor, not in types
type(list.__add__),#method_wrapper, also not in types
)
def get_all_possible_method_names(cls):
"""generates the names of nearly all methods the given class defines
three methods are blacklisted: __init__, __new__, and __getattribute__ for these reasons:
__init__ conflicts with the one defined in notifying_type
__new__ will not be called with a initialized instance, so there will not be a notify method to use
__getattribute__ is fine to override, just really annoying in most cases.
Note that this function may not work correctly in all cases
it was only tested with very simple classes and the builtin list."""
blacklist = ("__init__","__new__","__getattribute__")
for name,attr in vars(cls).items():
if (name not in blacklist and
isinstance(attr, unbound_method_or_descriptor)):
yield name
Once we can use notifying_type creating Notify_list or Notify_dict would be as simple as:
import collections
mutating_list_methods = set(dir(collections.MutableSequence)) - set(dir(collections.Sequence))
Notify_list = notifying_type(list, mutating_list_methods)
mutating_dict_methods = set(dir(collections.MutableMapping)) - set(dir(collections.Mapping))
Notify_dict = notifying_type(dict, mutating_dict_methods)
I have not tested this extensively and it quite possibly contains bugs / unhandled corner cases but I do know it worked correctly with list!

Defining a class property within __init__ as opposed to within another class method -- python

EDIT
Note, it was brought to my attention that Instance attribute attribute_name defined outside __init__ is a possible duplicate, which I mostly agree with (I didn't come upon this because I didn't know to search for pylint). However, I would like to keep this question open because of the fact that I want to be able to reinitialize my class using the same method. The general consensus in the previous question was to return each parameter from the loadData script and then parse it into the self object. This is fine, however, I would still have to do that again within another method to be able to reinitialize my instance of class, which still seems like extra work for only a little bit more readability. Perhaps the issue is my example. In real life there are about 30 parameters that are read in by the loadData routine, which is why I am hesitant to have to parse them in two different locations.
If the general consensus here is that returning the parameters are the way to go then we can go ahead and close this question as a duplicate; however, in the mean time I would like to wait to see if anyone else has any ideas/a good explanation for why.
Original
This is something of a "best practices" question. I have been learning python recently (partially to learn something new and partially to move away from MATLAB). While working in python I created a class that was structured as follows:
class exampleClass:
"""
This is an example class to demonstrate my question to stack exchange
"""
def __init__( self, fileName ):
exampleClass.loadData( self, fileName )
def loadData( self, fileName ):
"""
This function reads the data specified in the fileName into the
current instance of exampleClass.
:param fileName: The file that the data is to be loaded from
"""
with open(fileName,'r') as sumFile:
self.name = sumFile.readLine().strip(' \n\r\t')
Now this makes sense to me. I have an init class that populated the current instance of the class by calling to a population function. I also have the population function which would allow me to reinitialize a given instance of this class if for some reason I need to (for instance if the class takes up a lot of memory and instead of creating separate instances of the class I just want to have one instance that I overwrite.
However, when I put this code into my IDE (pycharm) it throws a warning that an instance attribute was defined outside of __init__. Now obviously this doesn't affect the operation of the code, everything works fine, but I am wondering if there is any reason to pay attention to the warning in this case. I could do something where I initialize all the properties to some default value in the init method before calling the loadData method but this just seems like unnecessary work to me and like it would slow down the execution (albeit only a very small amount). I could also have essentially two copies of the loadData method, one in the __init__ method and one as an actual method but again this just seems like unnecessary extra work.
Overall my question is what would the best practice be in this situation be. Is there any reason that I should restructure the code in one of the ways I mentioned in the previous paragraph or is this just an instance of an IDE with too broad of a code-inspection warning. I can obviously see some instances where this warning is something to consider but using my current experience it doesn't look like a problem in this case.
I think it's a best practice to define all of your attributes up front, even if you're going to redefine them later. When I read your code, I want to be able to see your data structures. If there's some attribute hidden in a method that only becomes defined under certain circumstances, it makes it harder to understand the code.
If it is inconvenient or impossible to give an attribute it's final value, I recommend at least initializing it to None. This signals to the reader that the object includes that attribute, even if it gets redefined later.
class exampleClass:
"""
This is an example class to demonstrate my question to stack exchange
"""
def __init__( self, fileName ):
# Note: this will be modified when a file is loaded
self.name = None
exampleClass.loadData( self, fileName )
Another choice would be for loadData to return the value rather than setting it, so your init might look like:
def __init__(self, fileName):
self.name = self.loadData(fileName)
I tend to think this second method is better, but either method is fine. The point is, make your classes and objects as easy to understand as possible.

Categories

Resources