Sorry if this has been asked before. Is it possible to create class in Python dynamically where attributes is not defined in the __init__ method of the class.
For example with this class
class Person(object):
def __init__(self):
...
I can dynamically put in the attributes during initialization like this:
person = Person(name='Joe')
and access it like this:
person.name
>>> Joe
Thank you
The easiest way to do this is to assign the keyword argument dict to the __dict__ attribute of the class:
class Person(object):
def __init__(self, **kw):
self.__dict__ = kw
person = Person(name='Joe')
print person.name
prints
Joe
To add attributes after object creation, use
def add_attributes(self, **kw):
self.__dict__.update(kw)
You could also use .update() in the constructor.
This can be achieved by using descriptors (detailed explanation). This also enables you to add attributes after the object has been created.
Related
I have a class:
class Test():
pass
I know the class name is "Test". How can I get class Test? A class is an object of class. I would like to get the class object based on its name, the text "Test".
In my project I have many classes defined. I would like to instantiate a class based on its name (without using an if statement).
If the class is defined in the global namespace, you can do it this way:
class Test:
pass
test_class = globals()["Test"]
print(test_class) # -> <class '__main__.Test'>
I don't suggest following such a convention, as this is very bad practice. A class is not an object of class, it's just a class that has been defined. Any objects you define using that class will be an object of that class and have its own instance. Please don't use the same name for different classes, this is almost never maintainable and you should never do it this way.
I have class attributes in my class, that I want to set dynamically, here's a code example
class Something:
attribute1 = 42 # this is shared between all class instances
def _init_(self, value):
self.value = value
my question is: Is there a way to set that class attribute (attribute1) to some value, the same way that I can set my object instance attributes like this:
something = Something(value)
Yes just do
Something.attribute1 = "some value"
Class attributes can be accessed via the class name. You can do this inside any function defined in the class or even outside of it.
I have a baseclass that contains nummerical attributes that are simply passed to it on initialization as a dictionary and then added to the instance's dictionary:
class baseclass(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def calcValue(self):
return sum(vars(self).values())
Now I have a derieved class from this class, that adds additional attributes to the class, e.g.;
class childclass(baseclass):
def __init__(self, stringValue, **kwargs):
super(childclass, self).__init__(kwargs)
self.name = stringValue
Now I would like to have a function in my baseclass that only iterates over all attributes that were added to the class but not the one that were added as child attributes. For example if I create an instance of child class like this:
instance = childclass("myname", a=1, b=2, c=3)
and then call the calcValue method, it should return 1+2+3 = 6
instance.calcValue()
but since vars(self) will return the full dictionary, uncluding the string from the childclass attribute, which of course can then not be added. Is there a way to only acces the attributes of the instance that belong to the respective derieved class?
You are storing all your attributes as ordinary values on the instance's __dict__. Which means that without any further hints, they are indistinguishable one from another.
Python has a couple mechanisms to treat attributes in special manners. If you would declare the attributes in your base class in the class itself, and just init their values inside the __init__ method, it would be possible to introspect the base class' __dict__ (and not the instance's __dict__), or the __annotations__ attribute in the same class.
As it is in the example, though, one easy thing is to use an special attribute to take note of the attributes that are added on the base class, and you then consult this as the attributes' name source:
class baseclass(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
self._numeric_attrs = set(kwargs.keys())
def calcValue(self):
return sum(getattr(self, attr) for attr in self._numeric_attrs)
A simple, safe and effective - but with added overhead - would be to store the base class attributes in a distinct attribute and use __getattr__ to serve them:
class BaseClass(object):
def __init__(self, **kwargs):
self._attribs = kwargs
def __getattr__(self, name):
try:
return self._attribs[name]
except KeyError:
raise AttributeError("object {} has no attribute {}".format(type(self).__name__, name))
def calcValue(self):
return sum(self._attribs.values())
I usually try to avoid __getattr__ as it makes the code harder to inspect and maintain, but since your class has already no definite API it doesn't make much difference here.
I have a class called A:
>>> class A:
def __init__(self):
self.register = {}
>>>
class A will be sub-classed by class B. class B however, contains methods that need to be registered as a name: function pair in instances of class A's dictionary. This is so class A can do work using the methods.
Here is an example of what I mean:
>>> class B(A):
def foo(self):
pass
def bar(self):
pass
>>> b = B()
>>> b.register # foo and bar were registered
{'key': <foo function>, 'key2': <bar function>}
>>>
Is there an idiomatic way to solve this? Or is something like this not possible, and it would be better to change my codes structure.
Note this is not a duplicate of Auto-register class methods using decorator because my register is not global, it is an instance variable of a class. This means using a meta-class like shown in the selected answer would not work.
I think the link to this question you mentioned in your post really can be used to solve your problem, if I understand it correctly.
The information you're trying to register is global information. While you want each instance to have a register containing this global information, all you really need to do is have __init__ copy the global register into the instance register.
If you will declare all classes you need, and after that worry about instance registers have references to all declared methods in all subclasses, you just need to performa a "register" information when declaring the subclasses themselves. That is easy to do in Python 3.6 (but not 3.5) with the new __init_subclass__ mechanism. In Python 3.5 and before that, it is easier performed using a metaclass.
class FallbackDict(dict):
def __init__(self, fallback):
self.fallback = fallback
def __missing__(self, key):
value = self.fallback[key]
self[key] = value
return value
class A:
register = {}
def __init__(self):
# instance register shadows global register
# for access via "self."
self.register = FallbackDict(__class__.register)
def __init_subclass__(cls):
for attrname, value in cls.__dict__.items():
if callable(value):
__class__.register[attrname] = value
The code here is meant to be simple - the custom dict class will "copy on read" values of the A.regiser dictionary into the instance dictionary. If you need a more consistent dictionary that include this behavior (for example, one that will iterate correctly the keys, values and items of both itself and the fallback dictionary) you'd better implement the "FallbackDict" class as an instance of collections.abc.MutableMapping instead (and just use an aggregate dictionary to actually keep the data)
You don't need the custom dict at all if you plan to create all your classes that register new methods before creating any instance of "A" - or if newly created classes don't have to update the existing instances - but in that case, you should copy A.register to the instance's "self.register" inside __init__.
If you can't change to Python 3.6 you will also need a custom metaclass to trigger the __init_subclass__ method above. Just keep it as is, so that your code is ready to move to Python 3.6 and eliminate the metaclass, and add a metaclass something like:
class MetaA(type):
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace)
cls.__init_subclass__()
class A:
...
#clasmethod
def __init_subclass__(cls):
# as above
...
The title is pretty much self explanatory, but I think this is better explained with an example.
class Dog():
def __init__(self, name):
self.name = name
def get_name(self):
return self.name
def get_color(self):
return body_color()
class personality_1():
def get_happiness(self):
return happiness_with_owner()
def get_sadness(self):
return sadness()
## A lot more personality methods here
class SocialDog(Dog):
# Override regular method
def get_color(self):
return face_color()
# I want to override the personality 1 class but not completely, just one method
class personality_2(>>>How to inherit from personality_1?<<<):
# Now, I would like to override just one method of personality 1:
def get_happiness(self):
return happiness_with_others()
Hopefully the logic is correct. I was trying to use super() with no success. Hopefully I can find a solution without using an explicit call to the parent class.
Any thoughts?
Thanks in advance!
To inherit from the class you specified, according to the code you provided, all that is required is to define the class personality_2 like this:
class SocialDog(Dog):
#...
class personality_2(Dog.personality_1):
#...
Now, as for your problem when trying to use super(), this might be because your base classes of Dog and Dog.personality_1 do not inherit from the python default class object which is required in order to use the super() method. See this answer for details. If that is what you are after, all you need to do is modify your class declarations for Dog and Dog.personality_1 (or whatever they ultimately derive from) to the following:
class Dog(object):
#...
class personality_1(object):
#...
Then you can treat SocialDog.personality_2 just like any other subclass. If you are using python 2, remember when using super() that you need to use the fully qualified name:
super(SocialDog.personality_2, self).super_class_method()
super(SocialDog.personality_2, self).super_class_field
Use the name of the outer class to reach the inner class:
class SocialDog(Dog):
class personality_2(Dog.personality_1):
# ...
That said, this is a very weird thing you're doing, hiding the personality classes inside the dog classes, then using them outside...
If a personality is that tightly coupled to a specific class like Dog or SocialDog, what makes personality_2 think it's safe to mess with the behaviour of personality_1? In fact, the personality methods should probably be Dog or SocialDog methods instead.
Or, if it doesn't really matter which dog gets which personality, why not leave the personality classes up at the module level, where they can be instantiated and inherited like any other class? Your various Dog-derived classes would then take an optional personality argument when created:
class WolfPersonality(DogPersonality):
# ...
class Wolf(Dog):
def __init__(self, personality=None):
if personality is None:
personality = WolfPersonality()
self.personality = personality
# ...
# Later...
wolf = Wolf()
wolf_puppy = Wolf(FriendlyDogPersonality())