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

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.

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

Python class inheritance - Base is modified by a subclass

Let's say I have a class called Test with an attribute items. Then I create a subclass called Best. Which has a method that modifies the classes attribute items. But it even modifies Test's items and I what it to modify items only for Best.
class Test():
items = []
class Best(Test):
def method(self):
type(self).items.append("a test")
>>> Best().method()
>>> Best.items
["a test"]
>>> Test.items
["a test"] # This is what I don't want.
You have declared items as an attribute of the superclass itself, so all instances of Test and it's subclasses will share the same list. Instead declare it in Test's __ init __ method, so there is one list per instance.
In Best, just append to self.items, and only the Best instance's list will be updated.
class Test(object):
def __ init __(self)
self.items = []
class Best(Test): # Best must inherit from Test
def method(self):
self.items.append("a test")
In Python you can get what you are asking by using "private" members...
class Base(object):
def __init__(self):
self.__mine = 42 # note the double underscore
def baseMethod(self):
return self.__mine
class Derived(Base):
def __init__(self):
Base.__init__(self)
self.__mine = 99
def derivedMethod(self):
return self.__mine
obj = Derived()
print(obj.baseMethod(), obj.derivedMethod()) ## ==> 42, 99
this works because at compile time Python will replace the name __mine with _Base__mine when compiling Base and with _Derived__mine when compiling Derived.
Note however that in Python while this is possible in my experience it's not used very often. Deriving a class in many cases is just not needed thanks to "duck typing" and to delegation, something that is not possible in languages like C++ or Java.
The only possible way to do this is to create a new items on the subclass -- where else is this new list meant to come from? Also type(self) is redundant. The lookup machinery looks up attributes on the class if it cannot find the attribute on the instance. Better yet, if you don't need an instance then declare the method to be a class method.
eg.
class Test:
items = []
#classmethod
def method_test(cls):
cls.items.append('test')
class Best(Test):
items = []
#classmethod
def method_best(cls):
cls.items.append('best')
Test.method_test()
assert Test.items == ['test']
assert Best.items == []
Test.items = []
Best.method_test()
Best.method_best()
assert Test.items == []
assert Best.items == ['test', 'best']
Note that method_test works on the Best class when called from the Best class.
Your Best class is modifying Test (which I assume it's supposed to be inheriting from) because Best doesn't have its own items list. When you access Best.items, you're accessing the list where it is inherited from (i.e. from Test class). If you want a different list, you need to create it explicitly in the subclass Best:
class Best(Test):
items = [] # hide the inherited list with our own list
# ...
Your code doesn't do what you describe.
For one thing, Best is not a subclass of Test.
For another Best.method() produces
NameError: name 'self' is not defined
items is a Test class attribute.
t = Test()
t.items.append(1)
changes Test.items.
As defined B.items gives an AttributeError.
Even if I change:
class Best():
def method(self):
...
Best.method() does not run; method is an instance method. I need to use Best().method(). But then I get the items AttributeError.
class Best(Test):
def method(self):
...
does what you desribe. Best().method() modifies the Test.items - because the Test class attribute is shared with the subclass.
As shown in other answers, simply defining items for Best decouples its value from the Test class attribute
class Best(Test):
items = ['other']
...

Delete attribute from class instance 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}

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__)

Can I iterate over a class in Python?

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)

Categories

Resources