How to create properties at runtime with Python? - python

So I'm trying to figure out if what I want to do is even possible. I am writing some test code for an application, and I have objects that contain properties representing some of the elements we have in the interface for our product. What I want to do is be able to pass in the application runner and the data object to a new class and have it dynamically generate a set of accessor properties based upon a subset of the properties in the data object. My idea so far:
Create a subclass of property that includes metadata required for extracting the extra information from the interface
Refactor the existing data objects to use the new property subclass for relevant fields in the UI
Create a new generator class that accepts the UI driver object and the data object that
reflects the data object to get a list of all the members of it that are of the new property subclass type
stores the information from the UI based upon the metadata in the property subclass to members of the generator class instance (planning on using setattr)
create properties at run time to make the members created in (b) read-only and provide an interface consistent with existing code (ie using .[name] instead of .[name]())
I think I have everything figured out except step 3c. Is there a way to create properties dynamically at runtime? Any help would be greatly appreciated.

Not sure that's what you want. But you could define dynamic read-only property with getattr and setattr method. Here is an example:
class X(object):
data = {'x' : 123, 'y' : 456}
def __getattr__(self, name):
if name in self.data:
return self.data[name]
raise AttributeError(name)
def __setattr__(self, name, value):
if name in self.data:
return None
return super(X, self).__setattr__(name, value)
a = X()
print a.x, a.y
a.x = 0
print a.x

Related

Promote instantiated class/object to a class in python?

Is there are a way in Python to store instantiated class as a class 'template' (aka promote object to a class) to create new objects of same type with same fields values, without relying on using data that was used to create original object again or on copy.deepcopy?
Like, for example I have the dictionary:
valid_date = {"date":"30 february"} # dict could have multiple items
and I have the class:
class AwesomeDate:
def __init__(self, dates_dict):
for key, val in dates_dict.items():
setattr(self, key, val);
I create the instance of the class like:
totally_valid_date = AwesomeDate(valid_date)
print(totally_valid_date.date) # output: 30 february
and now I want to use it to create new instances of the AwesomeDate class using the totally_valid_date instance as a template, i.e. like:
how_make_it_work = totally_valid_date()
print(how_make_it_work.date) # should print: 30 february
Is there are way to do so or no? I need a generic solution, not a solution for this specific example.
I don't really see the benefit of having a class act both as a template to instances, and as the instance itself, both conceptually and coding-wise. In my opinion, you're better off using two different classes - one for the template, one for the objects it is able to create.
You can think about awesome_date as a template class that stores the valid_date attributes upon initialization. Once called, the template returns an instance of a different class that has the expected attributes.
Here's a simple implementation (names have been changed to generalize the idea):
class Thing:
pass
class Template:
def __init__(self, template_attrs):
self.template_attrs = template_attrs
def __call__(self):
instance = Thing()
for key, val in self.template_attrs.items():
setattr(instance, key, val)
return instance
attrs = {'date': '30 february'}
template = Template(template_attrs=attrs)
# Gets instance of Thing
print(template()) # output: <__main__.Thing object at 0x7ffa656f8668>
# Gets another instance of Thing and accesses the date attribute
print(template().date) # output: 30 february
Yes, there are ways to do it -
there could even be some tweaking of inheriting from type and meddling with __call__ to make all instances automatically become derived classes. But I don't think that would be very sane. Python's own enum.Enum does something along this, because it has some use for the enum values - but the price is it became hard to understand beyond the basic usage, even for seasoned Pythonistas.
However, having a custom __init_subclass__ method that can inject some code to run prior to __init__ on the derived class, and then a method that will return a new class bound with the data that the new classes should have, can suffice:
import copy
from functools import wraps
def wrap_init(init):
#wraps(init)
def wrapper(self, *args, **kwargs):
if not getattr(self, "_initalized", False):
self.__dict__.update(self._template_data or {})
self._initialized = True
return init(self, *args, **kwargs)
wrapper._template_wrapper = True
return wrapper
class TemplateBase:
_template_data = None
def __init_subclass__(cls, *args, **kwargs):
super().__init_subclass__(*args, **kwargs)
if getattr(cls.__init__, "_template_wraper", False):
return
init = cls.__init__
cls.__init__ = wrap_init(init)
def as_class(self):
cls= self.__class__
new_cls = type(cls.__name__ + "_templated", (cls,), {})
new_cls._template_data = copy.copy(self.__dict__)
return new_cls
And using it:
class AwesomeDate(TemplateBase):
def __init__(self, dates_dict):
for key, val in dates_dict.items():
setattr(self, key, val)
On the REPL we have:
In [34]: x = AwesomeDate({"x":1, "y":2})
In [35]: Y = x.as_class()
In [36]: y = Y({})
In [37]: y.x
Out[37]: 1
Actually, __init_subclass__ itself could be supressed, and decorating __init__ could be done in one shot on the as_class method. This code takes some care so that mixin classes can be used, and it will still work.
It seems like you are going for something along the lines of the prototype design pattern.
What is the prototype design pattern?
From Wikipedia: Prototype pattern
The prototype pattern is a creational design pattern in software development. It is used when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects. This pattern is used to avoid subclasses of an object creator in the client application, like the factory method pattern does and to avoid the inherent cost of creating a new object in the standard way (e.g., using the 'new' keyword) when it is prohibitively expensive for a given application.
From Refactoring.guru: Prototype
Prototype is a creational design pattern that lets you copy existing objects without making your code dependent on their classes. The Prototype pattern delegates the cloning process to the actual objects that are being cloned. The pattern declares a common interface for all objects that support cloning. This interface lets you clone an object without coupling your code to the class of that object. Usually, such an interface contains just a single clone method.
The implementation of the clone method is very similar in all classes. The method creates an object of the current class and carries over all of the field values of the old object into the new one. You can even copy private fields because most programming languages let objects access private fields of other objects that belong to the same class. An object that supports cloning is called a prototype. When your objects have dozens of fields and hundreds of possible configurations, cloning them might serve as an alternative to subclassing. Here’s how it works: you create a set of objects, configured in various ways. When you need an object like the one you’ve configured, you just clone a prototype instead of constructing a new object from scratch.
Implementing this for your problem, along with your other ideas
From your explanation, it seems like you want to:
Provide a variable containing a dictionary, which will be passed to the __init__ of some class Foo
Instantiate class Foo and pass the variable containing the dictionary as an argument.
Implement __call__ onto class Foo, allowing us to use the function call syntax on an object of class Foo.
The implementation of __call__ will COPY/CLONE the “template” object. We can then do whatever we want with this copied/cloned instance.
The Code (edited)
import copy
class Foo:
def __init__(self, *, template_attrs):
if not isinstance(template_attrs, dict):
raise TypeError("You must pass a dict to instantiate this class.")
self.template_attrs = template_attrs
def __call__(self):
return copy.copy(self)
def __repr__(self):
return f"{self.template_attrs}"
def __setitem__(self, key, value):
self.template_attrs[key] = value
def __getitem__(self, key):
if key not in self.template_attrs:
raise KeyError(f"Key {key} does not exist in '{self.template_attrs=}'.")
return self.template_attrs[key]
err = Foo(template_attrs=1) # Output: TypeError: You must pass a dict to instantiate this class.
# remove err's assignment to have code under it run
base = Foo(template_attrs={1: 2})
print(f"{base=}") # Output: base={1: 2}
base_copy = base()
base_copy["hello"] = "bye"
print(f"{base_copy=}") # Output: base_copy={1: 2, 'hello': 'bye'}
print(f"{base_copy[1]=}") # Output: base_copy[1]=2
print(f"{base_copy[10]=}") # Output: KeyError: "Key 10 does not exist in 'self.template_attrs={1: 2, 'hello': 'bye'}'."
I also added support for subscripting and item assignment through __getitem__ and __setitem__ respectively. I hope that this helped a bit with your problem! Feel free to comment on this if I missed what you were asking.
Reasons for edits (May 16th, 2022 at 8:49 PM CST | Approx. 9 hours after original answer)
Fix code based on suggestions by comment from user jsbueno
Handle, in __getitem__, if an instance of class Foo is subscripted with a key that doesn't exist in the dict.
Handle, in __init__, if the type of template_attrs isn't dict (did this based on the fact that you used a dictionary in the body of your question)

Is there any way to create user defined data types in python without using a class

Is it possible to create user defined data types in python without using class, like using structure. Please explain, because I am new in python. Thank You
To create a type without using a class statement, you can use the type builtin:
class type(name, bases, dict)
With three arguments, return a new type object. This is essentially a dynamic form of the class statement. The name string is the class name and becomes the __name__ attribute; the bases tuple itemizes the base classes and becomes the __bases__ attribute; and the dict dictionary is the namespace containing definitions for class body and is copied to a standard dictionary to become the __dict__ attribute. For example, the following two statements create identical type objects:
class X:
a = 1
X = type('X', (object,), dict(a=1))
See also Type Objects.

Python style with attributes in class definition

I have a class with some attributes I want to use the methods. What is the most pythonic way to use it?. Is there documentation I can read about these styles issues?. I use pylint and pep8 to fix this kind of issues, but these program don't show any errors in this example with the attribute
class A(object):
BLOCK_SIZE = 8192
def func1(self):
print self.BLOCK_SIZE
def func2(self):
print A.BLOCK_SIZE
If I understand correctly this two case are the same, but I don't
know if is better to refer the class name or use the self reference.
Thanks
You should prefer self.
There are two types of fields - Class variables and Object variables.
Class variables are shared in the sense that they are accessed by all objects (instances) of that class. There is only copy of the class variable and when any one object makes a change to a class variable, the change is reflected in all the other instances as well.
Object variables are owned by each individual object/instance of the class. In this case, each object has its own copy of the field i.e. they are not shared and are not related in any way to the field by the same name in a different instance of the same class.
By using A.BLOCK_SIZE - you get class variable while by using self.BLOCK_SIZE you get an attribute of the specific object.
Check this to get a detailed example and explanations.
https://www.ibiblio.org/g2swap/byteofpython/read/class-and-object-vars.html
A class attribute can more or less be used as the default value for an instance attribute. The language allow a class attribute to be read either from the class itself or from any instance of the class, provided the instance has no attribute of same name.
But things go differently for write access: A.BLOCK_SIZE=16384 will change the global class attribute, while self.BLOCK_SIZE=16384 will create (or update) an instance attribute of same name.
Here is a little example with your class:
>>> a = A()
>>> a.func1() # access the class attribute
8192
>>> a.func2() # access the class attribute too
8192
>>> a.BLOCK_SIZE=4096 # create an instance attribute of same name
>>> a.func1() # access the INSTANCE attribute
4096
>>> a.func2() # still access the class attribute
8192
That's the reason why you should under common circonstances use the instance semantics (self.BLOCK_SIZE) because it does not rely on the class name and allows per instance override.
The class semantics A.BLOCK_SIZE should only be used if you want to change the class attribute, or need to use the class attribute even if an instance attribute exists.

Create objects from dictionary description

The Python MongoDB driver, PyMongo, returns results as dictionaries. I'm trying to figure out the best way to use such a dictionary in an object constructor.
Keep the dictionary as an attribute
self.dict = building_dict
Then each property of the building would be reachable through building.dict["property"].
A better attribute name could be used. Maybe a one-letter attribute. This doesn't look so elegant.
Parse dictionary to create attributes
self.name = building_dict['name']
self.construction_date = building_dict['construction_date']
...
In my model, the dictionaries can be pretty big but this task can be automated in the constructor to perform actions/checks on the values before or after the assignment.
Edit: The use of getters/setters is independent of options 1. and 2. above.
In solution 2., I'd avoid name collision between attributes and their getters by prefixing all dictionary keys by an underscore before making them attributes.
As a side-issue, the dictionary may contain the description of embedded documents, so the constructor should go through the whole dictionary to seek embedded documents that have their specific class in the code and instantiate those classes right away.
Update
I'll most probably use an ODM such as MongoEngine for my project and it will deal with those issues.
Outside of this specific use case (link with MongoDB, existing ODMs,...), the question is still relevant so I'm leaving below the best answer I could come up with.
The best you can do is to create an object. You can instantiate a classwith your dict like this:
building_dict = {'property': 4, 'name': 'my name'} # example dict
my_item = type('MyClass', (), building_dict) # instantiating class MyClass
You can access it afterwards like every other object:
print(my_item.property)
# 4
print(my_item.name)
# my name
My favorite solution so far stores elements as attributes and uses getters/setters:
class Building(object):
def __init__(self, dictionary):
# Check the values
# ...
# Find sub-dictionaries describing instances of another class
# stored as embedded documents in the base, call their
# constructor on sub-directories, then replace each sub-directory
# with the corresponding class instance.
# ...
# Set attributes from dictionary
for key in dictionary:
setattr(self, '_'+key, dictionary[key])
# Add default values if needed, etc.
# ...
# Usual getter/setter stuff
#property
def name(self):
try:
return self._name
except AttributeError as e:
# deal with missing name

what is the dict class used for

Can someone explain what the dict class is used for? This snippet is from Dive Into Python
class FileInfo(dict):
"store file metadata"
def __init__(self, filename=None):
self["name"] = filename
I understand the assignment of key=value pairs with self['name'] = filename but what does inheriting the dict class have to do with this? Please help me understand.
If you're not familiar with inheritance concept of object-oriented programming have a look at least at this wiki article (though, that's only for introduction and may be not for the best one).
In python we use this syntax to define class A as subclass of class B:
class A(B):
pass # empty class
In your example, as FileInfo class is inherited from standard dict type you can use instances of that class as dictionaries (as they have all methods that regular dict object has). Besides other things that allows you assign values by key like that (dict provides method for handing this operation):
self['name'] = filename
Is that the explanation you want or you don't understand something else?
It's for creating your own customized Dictionary type.
You can override __init__, __getitem__ and __setitem__ methods for your own special purposes to extend dictionary's usage.
Read the next section in the Dive into Python text: we use such inheritance to be able to work with file information just the way we do using a normal dictionary.
# From the example on the next section
>>> f = fileinfo.FileInfo("/music/_singles/kairo.mp3")
>>> f["name"]
'/music/_singles/kairo.mp3'
The fileinfo class is designed in a way that it receives a file name in its constructor, then lets the user get file information just the way you get the values from an ordinary dictionary.
Another usage of such a class is to create dictionaries which control their data. For example you want a dictionary who does a special thing when things are assigned to, or read from its 'sensor' key. You could define your special __setitem__ function which is sensitive with the key name:
def __setitem__(self, key, item):
self.data[key] = item
if key == "sensor":
print("Sensor activated!")
Or for example you want to return a special value each time user reads the 'temperature' key. For this you subclass a __getitem__ function:
def __getitem__(self, key):
if key == "temperature":
return CurrentWeatherTemperature()
else:
return self.data[key]
When an Class in Python inherits from another Class, it means that any of the methods defined on the inherited Class are, by nature, defined on the newly created Class.
So when FileInfo inherits dict it means all of the functionality of the dict class is now available to FileInfo, in addition to anything that FileInfo may declare, or more importantly, override by re-defining the method or parameter.
Since the dict Object in Python allows for key/value name pairs, this enables FileInfo to have access to that same mechanism.

Categories