Delete attribute from class instance python - python

I have example class:
class A():
other_attribute = 2
def __init__(self):
setattr(A,"my_attribute",1)
a = A()
How can I delete my_attribute and other_attribute from instance?
PS. I edited code to better explain problem. For example I have class, which dynamically adds attributes
class A():
def __init__(self, attribute_name, attribute_value):
setattr(A, attribute_name, attribute_value)
a = A("my_attribute", 123)
I created my_attribute, in instance a, but then I do not need it anymore. But at other instances are other attributes, which I do not want to change.

other_attribute and my_attribute are not an attributes on the instance. They are attributes on the class. You'd have to delete attributes from there, or provide an instance attribute with the same name (and a different value) to mask the class attribute.
Deleting the attributes from the class means that they'll not be available anymore on any instance.
You cannot 'delete' class attributes on individual instances. If an attribute is not to be shared by all instances, don't make them class attributes.

other_attribute is shared by all instances of A, that means it is a part of
A.__dict__
dictionary. You can do this for one instance of a class if you initialize an attribute in the constructor:
class A:
def __init__(self):
self.attrib = 2
self.attrib2 = 3
a = A()
print "Before " + str(a.__dict__)
del a.__dict__["attrib"];
print "After " + str(a.__dict__)
Output is:
Before {'attrib2': 3, 'attrib': 2}
After {'attrib2': 3}

Related

Simple Question : about python class parenthesis

Look at the code below.
class A :
def __init__(self, a = "Hello") :
self.a = a
print(A().a) # 1
print(A.a) # 2
1 is not error
2 is error - AttributeError: type object 'A' has no attribute 'a'
What is the difference between the two results?
In your code A refers the the type of a class and also to its constructor/initialiser. A is called the class and when you construct an object of type A with the constructor you get an instance of that class.
A # Refers to the class A
A() # is an instance of class A
There is a difference between a class property and an instance property. Consider the following code:
class A:
propertyA = "hello"
def __init__(self, string="world"):
self.propertyB = string
In this snippet propertyA is a class property while propertyB is an instance property. Each instance of type A has its own propertyB and you must instantiate and object (an instance) first.
A.propertyA # Class property, does not need an instance
A().propertyB # instance property, needs an instance
In your code the constructor for A is the code written in the __init__. This code will be called when you type A(). Note that you specified a default value for the parameter a but if you don't you would call the constructor like this:
A("hello") # or:
A(a="hello")
Note that classes, instances and constructors are fundamentals of OOP (and by extension Python), you really should learn this, it avoids lots of basic errors.
You need to create an instance of the class first:
class A :
def __init__(self, a = "Hello") :
self.a = a
class_instance = A()
print(class_instance.a)
You can set the value of "a" when creating the instance by typing in the parenthesis:
class_instance = A("this is the value of a")
you can change the value after the creation like so:
class_instance.a = "New value of a"
A().a is creating an instance and returns the a value of the instance.
A.a cannot be executed because A is the Class name and doesn't have any attributes if you don't create an instance first

Private Class Variables in Python?

I'd like to be able to extend a class without inheriting one of the class variables.
Given this scenario:
class A:
aliases=['a','ay']
class B(A):
pass
print(B.aliases)
I would rather get an error that B has not defined the aliases variable rather than have B accidentally called ay.
One could imagine a solution where aliases becomes a member of the instantiated object (self.aliases) and is set in __init__ but I really want to be able to access the aliases using the cls object rather than an instance of the class.
Any suggestions?
Python does not have REALY private attributes. But you can define it with a double underscore (__):
class A:
__aliases=['a','ay']
class B(A):
pass
print(B.__aliases) # yields AttributeError
But you still will be able to access it with:
print(B._A__aliases)
This is kindof a ganky work around but here you go:
class K:
def __init__(self):
self.mems = dir(self)
def defaultMembers():
k = K()
return(k.mems)
class A:
aliases=['a','ay']
class B(A):
def __init__(self):
for k in set(dir(self))-set(defaultMembers()):
print("removing "+k)
setattr(self, k, None)
a = A()
b = B()
print(b.aliases)
#None
print(a.aliases)
#['a','ay']
I guess all you really need is the setattr(self, "aliases", None) still this results in a None and not a non-variable. Unfortunately calsses don't support deletion because I tried to use del first.

Access a class property by both class name and parent class name

Consider this snippet:
def populate(l):
l.append(1)
class First:
__obj__ = []
class Second(First):
populate(First.__obj__)
def __init__(self):
pass
def __call__(self):
for i in Second.__obj__:
print(i)
a = Second()
a()
When run, it will output 1, so it seems that First.__obj___ and Second.__obj__ point to the same object. Is it true and how does class property work in the case of inheritance?
The name __obj__ is an attribute of the First class. Because the Second class inherits the First class, it also inherits the class attribute __obj__. Both First.__obj__ and Second.__obj__ are referencing the same list object. An instance's self.__obj__ also references the same object.
This is because lists are mutable. This would not be the case with an immutable type like str.

How to keep track of class instances?

Toward the end of a program I'm looking to load a specific variable from all the instances of a class into a dictionary.
For example:
class Foo():
def __init__(self):
self.x = {}
foo1 = Foo()
foo2 = Foo()
...
Let's say the number of instances will vary and I want the x dict from each instance of Foo() loaded into a new dict. How would I do that?
The examples I've seen in SO assume one already has the list of instances.
One way to keep track of instances is with a class variable:
class A(object):
instances = []
def __init__(self, foo):
self.foo = foo
A.instances.append(self)
At the end of the program, you can create your dict like this:
foo_vars = {id(instance): instance.foo for instance in A.instances}
There is only one list:
>>> a = A(1)
>>> b = A(2)
>>> A.instances
[<__main__.A object at 0x1004d44d0>, <__main__.A object at 0x1004d4510>]
>>> id(A.instances)
4299683456
>>> id(a.instances)
4299683456
>>> id(b.instances)
4299683456
#JoelCornett's answer covers the basics perfectly. This is a slightly more complicated version, which might help with a few subtle issues.
If you want to be able to access all the "live" instances of a given class, subclass the following (or include equivalent code in your own base class):
from weakref import WeakSet
class base(object):
def __new__(cls, *args, **kwargs):
instance = object.__new__(cls, *args, **kwargs)
if "instances" not in cls.__dict__:
cls.instances = WeakSet()
cls.instances.add(instance)
return instance
This addresses two possible issues with the simpler implementation that #JoelCornett presented:
Each subclass of base will keep track of its own instances separately. You won't get subclass instances in a parent class's instance list, and one subclass will never stumble over instances of a sibling subclass. This might be undesirable, depending on your use case, but it's probably easier to merge the sets back together than it is to split them apart.
The instances set uses weak references to the class's instances, so if you del or reassign all the other references to an instance elsewhere in your code, the bookkeeping code will not prevent it from being garbage collected. Again, this might not be desirable for some use cases, but it is easy enough to use regular sets (or lists) instead of a weakset if you really want every instance to last forever.
Some handy-dandy test output (with the instances sets always being passed to list only because they don't print out nicely):
>>> b = base()
>>> list(base.instances)
[<__main__.base object at 0x00000000026067F0>]
>>> class foo(base):
... pass
...
>>> f = foo()
>>> list(foo.instances)
[<__main__.foo object at 0x0000000002606898>]
>>> list(base.instances)
[<__main__.base object at 0x00000000026067F0>]
>>> del f
>>> list(foo.instances)
[]
You would probably want to use weak references to your instances. Otherwise the class could likely end up keeping track of instances that were meant to have been deleted. A weakref.WeakSet will automatically remove any dead instances from its set.
One way to keep track of instances is with a class variable:
import weakref
class A(object):
instances = weakref.WeakSet()
def __init__(self, foo):
self.foo = foo
A.instances.add(self)
#classmethod
def get_instances(cls):
return list(A.instances) #Returns list of all current instances
At the end of the program, you can create your dict like this:
foo_vars = {id(instance): instance.foo for instance in A.instances}
There is only one list:
>>> a = A(1)
>>> b = A(2)
>>> A.get_instances()
[<inst.A object at 0x100587290>, <inst.A object at 0x100587250>]
>>> id(A.instances)
4299861712
>>> id(a.instances)
4299861712
>>> id(b.instances)
4299861712
>>> a = A(3) #original a will be dereferenced and replaced with new instance
>>> A.get_instances()
[<inst.A object at 0x100587290>, <inst.A object at 0x1005872d0>]
You can also solve this problem using a metaclass:
When a class is created (__init__ method of metaclass), add a new instance registry
When a new instance of this class is created (__call__ method of metaclass), add it to the instance registry.
The advantage of this approach is that each class has a registry - even if no instance exists. In contrast, when overriding __new__ (as in Blckknght's answer), the registry is added when the first instance is created.
class MetaInstanceRegistry(type):
"""Metaclass providing an instance registry"""
def __init__(cls, name, bases, attrs):
# Create class
super(MetaInstanceRegistry, cls).__init__(name, bases, attrs)
# Initialize fresh instance storage
cls._instances = weakref.WeakSet()
def __call__(cls, *args, **kwargs):
# Create instance (calls __init__ and __new__ methods)
inst = super(MetaInstanceRegistry, cls).__call__(*args, **kwargs)
# Store weak reference to instance. WeakSet will automatically remove
# references to objects that have been garbage collected
cls._instances.add(inst)
return inst
def _get_instances(cls, recursive=False):
"""Get all instances of this class in the registry. If recursive=True
search subclasses recursively"""
instances = list(cls._instances)
if recursive:
for Child in cls.__subclasses__():
instances += Child._get_instances(recursive=recursive)
# Remove duplicates from multiple inheritance.
return list(set(instances))
Usage: Create a registry and subclass it.
class Registry(object):
__metaclass__ = MetaInstanceRegistry
class Base(Registry):
def __init__(self, x):
self.x = x
class A(Base):
pass
class B(Base):
pass
class C(B):
pass
a = A(x=1)
a2 = A(2)
b = B(x=3)
c = C(4)
for cls in [Base, A, B, C]:
print cls.__name__
print cls._get_instances()
print cls._get_instances(recursive=True)
print
del c
print C._get_instances()
If using abstract base classes from the abc module, just subclass abc.ABCMeta to avoid metaclass conflicts:
from abc import ABCMeta, abstractmethod
class ABCMetaInstanceRegistry(MetaInstanceRegistry, ABCMeta):
pass
class ABCRegistry(object):
__metaclass__ = ABCMetaInstanceRegistry
class ABCBase(ABCRegistry):
__metaclass__ = ABCMeta
#abstractmethod
def f(self):
pass
class E(ABCBase):
def __init__(self, x):
self.x = x
def f(self):
return self.x
e = E(x=5)
print E._get_instances()
Another option for quick low-level hacks and debugging is to filter the list of objects returned by gc.get_objects() and generate the dictionary on the fly that way. In CPython that function will return you a (generally huge) list of everything the garbage collector knows about, so it will definitely contain all of the instances of any particular user-defined class.
Note that this is digging a bit into the internals of the interpreter, so it may or may not work (or work well) with the likes of Jython, PyPy, IronPython, etc. I haven't checked. It's also likely to be really slow regardless. Use with caution/YMMV/etc.
However, I imagine that some people running into this question might eventually want to do this sort of thing as a one-off to figure out what's going on with the runtime state of some slice of code that's behaving strangely. This method has the benefit of not affecting the instances or their construction at all, which might be useful if the code in question is coming out of a third-party library or something.
Here's a similar approach to Blckknght's, which works with subclasses as well. Thought this might be of interest, if someone ends up here. One difference, if B is a subclass of A, and b is an instance of B, b will appear in both A.instances and B.instances. As stated by Blckknght, this depends on the use case.
from weakref import WeakSet
class RegisterInstancesMixin:
instances = WeakSet()
def __new__(cls, *args, **kargs):
o = object.__new__(cls, *args, **kargs)
cls._register_instance(o)
return o
#classmethod
def print_instances(cls):
for instance in cls.instances:
print(instance)
#classmethod
def _register_instance(cls, instance):
cls.instances.add(instance)
for b in cls.__bases__:
if issubclass(b, RegisterInstancesMixin):
b._register_instance(instance)
def __init_subclass__(cls):
cls.instances = WeakSet()
class Animal(RegisterInstancesMixin):
pass
class Mammal(Animal):
pass
class Human(Mammal):
pass
class Dog(Mammal):
pass
alice = Human()
bob = Human()
cannelle = Dog()
Animal.print_instances()
Mammal.print_instances()
Human.print_instances()
Animal.print_instances() will print three objects, whereas Human.print_instances() will print two.
Using the answer from #Joel Cornett I've come up with the following, which seems to work. i.e. i'm able to total up object variables.
import os
os.system("clear")
class Foo():
instances = []
def __init__(self):
Foo.instances.append(self)
self.x = 5
class Bar():
def __init__(self):
pass
def testy(self):
self.foo1 = Foo()
self.foo2 = Foo()
self.foo3 = Foo()
foo = Foo()
print Foo.instances
bar = Bar()
bar.testy()
print Foo.instances
x_tot = 0
for inst in Foo.instances:
x_tot += inst.x
print x_tot
output:
[<__main__.Foo instance at 0x108e334d0>]
[<__main__.Foo instance at 0x108e334d0>, <__main__.Foo instance at 0x108e33560>, <__main__.Foo instance at 0x108e335a8>, <__main__.Foo instance at 0x108e335f0>]
5
10
15
20
(For Python)
I have found a way to record the class instances via the "dataclass" decorator while defining a class. Define a class attribute 'instances' (or any other name) as a list of the instances you want to record. Append that list with the 'dict' form of created objects via the dunder method __dict__. Thus, the class attribute 'instances' will record instances in the dict form, which you want.
For example,
from dataclasses import dataclass
#dataclass
class player:
instances=[]
def __init__(self,name,rank):
self.name=name
self.rank=rank
self.instances.append(self.__dict__)

Why does declaring a descriptor class in the __init__ function break the descriptor functionality?

In class B below I wanted the __set__ function in class A to be called whenever you assign a value to B().a . Instead, setting a value to B().a overwrites B().a with the value. Class C assigning to C().a works correctly, but I wanted to have a separate instance of A for each user class, i.e. I don't want changing 'a' in one instance of C() to change 'a' in all other instances. I wrote a couple of tests to help illustrate the problem. Can you help me define a class that will pass both test1 and test2?
class A(object):
def __set__(self, instance, value):
print "__set__ called: ", value
class B(object):
def __init__(self):
self.a = A()
class C(object):
a = A()
def test1( class_in ):
o = class_in()
o.a = "test"
if isinstance(o.a, A):
print "pass"
else:
print "fail"
def test2( class_in ):
o1, o2 = class_in(), class_in()
if o1.a is o2.a:
print "fail"
else:
print "pass"
Accordingly to the documentation:
The following methods only apply when an instance of the class containing
the method (a so-called descriptor
class) appears in the class dictionary
of another new-style class, known as
the owner class. In the examples
below, “the attribute” refers to the
attribute whose name is the key of the
property in the owner class’ __dict__.
Descriptors can only be implemented as
new-style classes themselves.
So you can't have descriptors on instances.
However, since the descriptor gets a ref to the instance being used to access it, just use that as a key to storing state and you can have different behavior depending on the instance.
Here's a class that can pass the original tests, but don't try using it in most situations. it fails the isinstance test on itself!
class E(object):
def __new__(cls, state):
class E(object):
a = A(state)
def __init__(self, state):
self.state = state
return E(state)
#>>> isinstance(E(1), E)
#False
I was bitten by a similar issue in that I wanted to class objects with attributes governed by a descriptor. When I did this, I noticed that the attributes were being overwritten in all of the objects such that they weren't individual.
I raised a SO question and the resultant answer is here: class attribute changing value for no reason
A good document link discussing descriptors is here: http://martyalchin.com/2007/nov/24/python-descriptors-part-2-of-2/
An example descriptor from the aforementioned link is below:
class Numberise(object):
def __init__(self, name):
self.name = name
def __get__(self, instance, owner):
if self.name not in instance.__dict__:
raise (AttributeError, self.name)
return '%o'%(instance.__dict__[self.name])
def __set__(self, instance, value):
print ('setting value to: %d'%value)
instance.__dict__[self.name] = value

Categories

Resources