This question already has answers here:
How to copy a class?
(9 answers)
Closed 8 years ago.
In the example below, I am deepcopying a base class and messing with the attributes of the copy. Why is this messing with the attributes of the original class? Is there any way to avoid this? The current code structure I am working with can't support multiple inheritance, so I really want to be able to somehow copy the class.
>>> class Base(object):
... foo = "bar"
...
>>> base_copy = copy.deepcopy(Base)
>>> del base_copy.foo
>>>
>>> base_again = copy.deepcopy(Base)
>>> hasattr(base_again, 'foo')
False
>>>
copy() and deepcopy() are designed to copy objects not classes. When you pass a class the original class is returned.
Python documentation says :
This module does not copy types like module, method, stack trace, stack frame, file, socket, window, array, or any similar types. It does “copy” functions and classes (shallow and deeply), by returning the original object unchanged; this is compatible with the way these are treated by the pickle module.
Indeed when testing with your code we have:
In [8]: base_copy is Base
Out[8]: True
You could try messing with type() as suggested in the other answer but it's pretty hackish.
You could do
class B(A):
pass
It's the closest I can think of that would make a copy.
As stated in copy documentation:
This module does not copy types like module, method, stack trace,
stack frame, file, socket, window, array, or any similar types. It
does “copy” functions and classes (shallow and deeply), by returning
the original object unchanged
You can try to do it using metaclasses:
class Base(object):
foo = "bar"
# Create a new class called `base_copy` with attributes and base classes
# from Base without inheriting from Base
base_copy = type('base_copy', Base.__bases__, dict(Base.__dict__))
# Will delete attribute on `base_copy` class
del base_copy.foo
base_again = type('base_again', Base.__bases__, dict(Base.__dict__))
print(hasattr(base_again, 'foo')) # True
You can try using deepcopy on dict(Base.__dict__) object to copy objects like list, dict and others.
Define all variables inside the constructor.
You can create a new constructor which, on the basis of the argument provided, decides which all fields should exist in the object of the class.
Class Foo:
def __init__(self):
self.param0 = 0
self.param1 = 0
def __init__(self,i):
if i == 0:
self.param0 = 0
if i == 1:
self.param1 = 1
Related
This is a two-part query, which broadly relates to class attributes referencing mutable and immutable objects, and how these should be dealt with in code design. I have abstracted away the details to provide an example class below.
In this example, the class is designed for two instances which, through an instance method, can access a class attribute that references a mutable object (a list in this case), each can “take” (by mutating the object) elements of this object into their own instance attribute (by mutating the object it references). If one instance “takes” an element of the class attribute, that element is subsequently unavailable to the other instance, which is the effect I wish to achieve. I find this a convenient way of avoiding the use of class methods, but is it bad practice?
Also in this example, there is a class method that reassigns an immutable object (a Boolean value, in this case) to a class attribute based on the state of an instance attribute. I can achieve this by using a class method with cls as the first argument and self as the second argument, but I’m not sure if this is correct. On the other hand, perhaps this is how I should be dealing with the first part of this query?
class Foo(object):
mutable_attr = ['1', '2']
immutable_attr = False
def __init__(self):
self.instance_attr = []
def change_mutable(self):
self.instance_attr.append(self.mutable_attr[0])
self.mutable_attr.remove(self.mutable_attr[0])
#classmethod
def change_immutable(cls, self):
if len(self.instance_attr) == 1:
cls.immutable_attr = True
eggs = Foo()
spam = Foo()
If you want a class-level attribute (which, as you say, is "visible" to all instances of this class) using a class method like you show is fine. This is, mostly, a question of style and there are no clear answers here. So what you show is fine.
I just want to point out that you don't have to use a class method to accomplish your goal. To accomplish your goal this is also perfectly fine (and in my opinion, more standard):
class Foo(object):
# ... same as it ever was ...
def change_immutable(self):
"""If instance has list length of 1, change immutable_attr for all insts."""
if len(self.instance_attr) == 1:
type(self).immutable_attr = True
Or even:
def change_immutable(self):
"""If instance has list length of 1, change immutable_attr for all insts."""
if len(self.instance_attr) == 1:
Foo.immutable_attr = True
if that's what you want to do. The major point being that you are not forced into using a class method to get/set class level attributes.
The type builtin function (https://docs.python.org/2/library/functions.html#type) simply returns the class of an instance. For new style classes (most classes nowadays, ones that ultimately descend from object) type(self) is the same as self.__class__, but using type is the more idiomatic way to access an object's type.
You use type when you want to write code that gets an object's ultimate type, even if it's subclassed. This may or may not be what you want to do. For example, say you have this:
class Baz(Foo):
pass
bazzer = Baz()
bazzer.change_mutable()
bazzer.change_immutable()
Then the code:
type(self).immutable_attr = True
Changes the immutable_attr on the Baz class, not the Foo class. That may or may not be what you want -- just be aware that only objects that descend from Baz see this. If you want to make it visible to all descendants of Foo, then the more appropriate code is:
Foo.immutable_attr = True
Hope this helps -- this question is a good one but a bit open ended. Again, major point being you are not forced to use class methods to set/get class attrs -- but not that there's anything wrong with that either :)
Just finally note the way you first wrote it:
#classmethod
def change_immutable(cls, self):
if len(self.instance_attr) == 1:
cls.immutable_attr = True
Is like doing the:
type(self).immutable_attr = True
way, because the cls variable will not necessarily be Foo if it's subclassed. If you for sure want to set it for all instances of Foo, then just setting the Foo class directly:
Foo.immutable_attr = True
is the way to go.
This is one possibility:
class Foo(object):
__mutable_attr = ['1', '2']
__immutable_attr = False
def __init__(self):
self.instance_attr = []
def change_mutable(self):
self.instance_attr.append(self.__class__.__mutable_attr.pop(0))
if len(self.instance_attr) == 1:
self.__class__.__immutable_attr = True
#property
def immutable_attr(self):
return self.__class__.__immutable_attr
So a little bit of explanation:
1. I'm making it harder to access class attributes from the outside to protect them from accidental change by prefixing them with double underscore.
2. I'm doing pop() and append() in one line.
3. I'm setting the value for __immutable_attr immediately after modifying __mutable_attr if the condition is met.
4. I'm exposing immutable_attr as read only property to provide easy way to check it's value.
5. I'm using self.__class__ to access class of the instance - it's more readable than type(self) and gives us direct access to attributes with double underscore.
This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 9 years ago.
i just have a puzzling question abou class attributes in python.
consider the following class below:
class A:
__lst = []
def add(self, str):
self.__lst.append(str)
print len(self.__lst)
i tried to make two instances x and y and i got this:
>>> x = A()
>>> x.add('aaa')
1
>>> x.add('bbb')
2
>>> y = A()
>>> y.add('aaa')
3
>>> y.add('bbb')
4
i was expecting that the instance of y will have a separate copy of the list attribute but it seems that the list just gets bigger even if you use another object to add elements to the list. it's simply weird.
can anybody please enlighten me on this matter?
thanks a lot in advance for your help. :-)
If you define an attribute inside of the class body then it will be a class attribute, and it will be shared by all instances. In your code self.__lst is going to be a reference to A.__lst.
To have a separate list for each attribute, define it as self.__lst inside of the __init__() function:
class A(object):
def __init__(self):
self.__lst = []
def add(self, s):
self.__lst.append(s)
print len(self.__lst)
In addition to the change referenced above, I also made some minor modifications so that your code follows some Python best practices: inheriting from object (new-style class) and not using str (or any other built-in name) as a variable name.
Variables declared inside a class but not by means of self are class-level properties (like your __lst). They are equivalent to Java's static. If you want your property to be unique for all instances, you need to declare them via self (i.e., self.__lst).
Why are constructors indeed called "Constructors"? What is their purpose and how are they different from methods in a class?
Also, can there be more that one __init__ in a class? I tried the following, can someone please explain the result?
>>> class test:
def __init__(self):
print "init 1"
def __init__(self):
print "init 2"
>>> s=test()
init 2
Finally, is __init__ an operator overloader?
There is no function overloading in Python, meaning that you can't have multiple functions with the same name but different arguments.
In your code example, you're not overloading __init__(). What happens is that the second definition rebinds the name __init__ to the new method, rendering the first method inaccessible.
As to your general question about constructors, Wikipedia is a good starting point. For Python-specific stuff, I highly recommend the Python docs.
Why are constructors indeed called "Constructors" ?
The constructor (named __new__) creates and returns a new instance of the class. So the C.__new__ class method is the constructor for the class C.
The C.__init__ instance method is called on a specific instance, after it is created, to initialise it before being passed back to the caller. So that method is the initialiser for new instances of C.
How are they different from methods in a class?
As stated in the official documentation __init__ is called after the instance is created. Other methods do not receive this treatment.
What is their purpose?
The purpose of the constructor C.__new__ is to define custom behaviour during construction of a new C instance.
The purpose of the initialiser C.__init__ is to define custom initialisation of each instance of C after it is created.
For example Python allows you to do:
class Test(object):
pass
t = Test()
t.x = 10 # here you're building your object t
print t.x
But if you want every instance of Test to have an attribute x equal to 10, you can put that code inside __init__:
class Test(object):
def __init__(self):
self.x = 10
t = Test()
print t.x
Every instance method (a method called on a specific instance of a class) receives the instance as its first argument. That argument is conventionally named self.
Class methods, such as the constructor __new__, instead receive the class as their first argument.
Now, if you want custom values for the x attribute all you have to do is pass that value as argument to __init__:
class Test(object):
def __init__(self, x):
self.x = x
t = Test(10)
print t.x
z = Test(20)
print t.x
I hope this will help you clear some doubts, and since you've already received good answers to the other questions I will stop here :)
Classes are simply blueprints to create objects from. The constructor is some code that are run every time you create an object. Therefor it does'nt make sense to have two constructors. What happens is that the second over write the first.
What you typically use them for is create variables for that object like this:
>>> class testing:
... def __init__(self, init_value):
... self.some_value = init_value
So what you could do then is to create an object from this class like this:
>>> testobject = testing(5)
The testobject will then have an object called some_value that in this sample will be 5.
>>> testobject.some_value
5
But you don't need to set a value for each object like i did in my sample. You can also do like this:
>>> class testing:
... def __init__(self):
... self.some_value = 5
then the value of some_value will be 5 and you don't have to set it when you create the object.
>>> testobject = testing()
>>> testobject.some_value
5
the >>> and ... in my sample is not what you write. It's how it would look in pyshell...
coonstructors are called automatically when you create a new object, thereby "constructing" the object. The reason you can have more than one init is because names are just references in python, and you are allowed to change what each variable references whenever you want (hence dynamic typing)
def func(): #now func refers to an empty funcion
pass
...
func=5 #now func refers to the number 5
def func():
print "something" #now func refers to a different function
in your class definition, it just keeps the later one
There is no notion of method overloading in Python. But you can achieve a similar effect by specifying optional and keyword arguments
I am trying to modify __getattribute__() method for an instance, as you may already know, __getattirbute__ is read-only attribute in Python (edit: appereantly, for some objects it is, and for others it isn't). What I have in mind is, create a new object like this:
def create_new_instace(old_instance):
class temp(old_instance.__class__):
def __init__(self,*args,**kwargs):
"Since we will copy an already inited instance"
pass
def __getattribute__(self,attr):
# do stuff
new_instance = temp()
# magically copy all attrs of old_instance to new_instance
return new_instance
Is this kind of thing possible? I am not having a particular problem, I just want to know how to do this.
Actually, yes. Check difference between __getattribute__ and __getattr__ method here
You can assign new value to the instance's field __getattribute__ except if __setattr__ explicitly prohibits that. Try this in your python prompt:
>>>class A(object):
>>> pass
>>>A().__getattribute__ = myFunc
>>>A().__getattr__ = myFunc
If the __setattr__ won't allow you to do so, you have to do something like solution you proposed. Check module copy for 'magically copying' attributes.
It is possible for Python 2.2+, just the way you attempt it, read here (search for getattirbute) for the specific things you should take into consideration:
http://www.python.org/download/releases/2.2/descrintro/
I am not sure I understand your goal. If you simply want to create a new object that is a duplicate of another object, you can use
from copy import copy
new_instance = copy( old_instance )
This creates a shallow copy. There is also copy.deepcopy for deep copies of objects.
If you want a derived class that has a copy of another instances attributes (an possibly other customizations, that you need to make dynamically for some reason), you can use:
from copy import copy
def create_new_instance( old_instance ):
class NewClass( old_instance.__class__ ):
"""
dynamic custom class
"""
# ... customizations
new_instance = copy( old_instance )
new_instance.__class__ = NewClass
This won't work for some system class types, for which __class__ isn't assignable. (e.g. list, tuple, str, I think).
In these cases you can define your derived class with __new__ ... but I'm not sure if there is a "standard" way to define the arguments -- you might be reduced to going through cases.
Note that unless you have other reasons for creating the new class dynamically, you needn't define it inside your function.
This question already has answers here:
Usage of __slots__?
(14 answers)
Can't set attributes on instance of "object" class
(7 answers)
Closed 7 months ago.
For example, this code is Python:
a = object()
a.b = 3
throws AttributeError: 'object' object has no attribute 'b'
But, this piece of code:
class c(object): pass
a = c()
a.b = 3
is just fine. Why can I assign property b, when class x does not have that property? How can I make my classes have only properties defined?
The object type is a built-in class written in C and doesn't let you add attributes to it. It has been expressly coded to prevent it.
The easiest way to get the same behavior in your own classes is to use the __slots__ attribute to define a list of the exact attributes you want to support. Python will reserve space for just those attributes and not allow any others.
class c(object):
__slots__ = "foo", "bar", "baz"
a = c()
a.foo = 3 # works
a.b = 3 # AttributeError
Of course, there are some caveats with this approach: you can't pickle such objects, and code that expects every object to have a __dict__ attribute will break. A "more Pythonic" way would be to use a custom __setattr__() as shown by another poster. Of course there are plenty of ways around that, and no way around setting __slots__ (aside from subclassing and adding your attributes to the subclass).
In general, this is not something you should actually want to do in Python. If the user of your class wants to store some extra attributes on instances of the class, there's no reason not to let them, and in fact a lot of reasons why you might want to.
You can override the behavior of the __setattr__ magic method like so.
class C(object):
def __setattr__(self, name, value):
allowed_attrs = ('a', 'b', 'c')
if name not in allowed_attrs:
# raise exception
# or do something else
pass
self.__dict__[name] = value
Of course, this will only prevent you from setting attributes like a.b (the dot form). You can still set the attributes using a.__dict__[b] = value. In that case, you should override the __dict__ method too.
Python generally allows you to set any attribute on any object. This is a special case where the object class acts differently. There are also some modules implemented in C that act similarly.
If you want your object to behave like this, you can define a __setattr__(self, name, value) method that explicitly does a raise AttributeError() if you try to set a member that's not on the "approved list" (see http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/389916)
Creating an object instance has no features. Therefore setting attributes on an instance of a the base object type is expressly disabled. You must subclass it to be able to create attributes.
Hint: If you want a simple object to use as something on which to store properties, you can do so by creating an anonymous function with lambda. Functions, being objects, are able to store attributes as well, so this is perfectly legit:
>>> a = lambda: None
>>> a.b = 3
>>> a.b
3
This happens because when you say a.b = 3, it creates a variable in a that represents b. For example,
class a: pass
print a.b
returns AttributeError: class a has no attribute b
However this code,
class a: pass
a.b = 3
print a.b
returns 3 as it sets the value of b in a, to 3.