Function to set namedtuple attributes? - python

I have a namedtuple that's a private property of a class instance. I want to create a new tuple based off an instance's namedtuple, but tuples are immutable, so I create a new one and just insert what I want. Is there a better way of doing this? It's extremely redundant, and I would like a specific function or so that would just take a namedtuple as a parameter and as the other parameter the attribute you want to change and it returns the new namedtuple. What would this look like?

There's a _replace method for that:
new_namedtuple = old_namedtuple._replace(field_name=new_value)
Plus, it'll avoid the bug in your current code, where if two fields share the same value, your code might end up replacing the wrong one.

Related

Inhibiting a method called on a dataclass member

My dataclass has a field that holds an array of data in a custom type (actually it is a PyROOT std vector). However, for the user it is supposed to be visible as a list. This is simple enough with dataclass getters and setters, that convert the vector to list and vice versa. However, this works only if the user initialises the field with a full list. If the user wants to append to the list, it, obviously, doesn't work, as there is no permanent list associated with the field.
I wonder if there is a way to inhibit the ".append()" call on the field and call instead the vector's push_back()? Or perhaps there is a good Pythonic way to deal with it in general?
The context is, that I need the dataclass fields in the PyROOT format, as later I am storing the data in ROOT TTrees. However, I am creating this interface, so that the user does not need to know ROOT to use the dataclass. I know that I could create both the vector and the list that would hold the same data, but that seems like a waste of memory, and I am not certain how to update the vector each time the list is modified, anyway.
According to the Python Docs, “Lists are mutable sequences, typically used to store collections of homogeneous items (where the precise degree of similarity will vary by application).” (emphasis added)
With that in mind, I would start off with something like this:
from collections.abc import MutableSequence
class ListLike(MutableSequence):
def __init__(self):
self.backing_data = object() # Replace with the type your using
ListLike()
When you run that code, you’ll get the error: TypeError: Can't instantiate abstract class ListLike with abstract methods __delitem__, __getitem__, __len__, __setitem__, insert. Once you implement those methods, you’ll have have a type that acts a lot like list, but isn’t.
To make ListLikes act even more like lists, use this code to compare the two:
example_list = list()
example_list_like = ListLike()
list_attributes = [attribute for attribute in dir(example_list)]
list_like_attributes = [attribute for attribute in dir(example_list_like)]
for attribute in list_attributes:
if attribute not in list_like_attributes:
print(f"ListLikes don't have {attribute}")
print("-----------")
for attribute in list_like_attributes:
if attribute not in list_attributes:
print(f"lists don't have {attribute}")
and change your implementation accordingly.

Python object's __iter__not getting called

I have a Python 2.7 class (call it Child), that is a child of another class (Parent) that is itself a subclass of dict.
I'm trying to define __iter__ in Child in the hopes that when someone does a dict(child_object) I can control how it is converted to a dict. I must be misunderstanding something though, because it seems the dict() call is bypassing calling __iter__ completely and is instead going to the underlying dict.
I did some research and from the dict() method's docs I see that it may be seeing the object as a mapping first, and therefore using that instead of the iterable's __iter__. Is that the case, and if so, is there a way I can overwrite some method that is being called on the mapping?
When you use dict() on a mapping (or use dictionary.update(...) passing in a mapping), then Python will not use __iter__. Python looks for a .keys() method to detect mappings. In that case, if the mapping happens to be a dict or a subclass of dict, then a fast path is picked that copies key-value pairs directly from the underlying C structures. You can't prevent this with custom Python functions.
Put differently, if you must define a custom mapping type that lets you control how dict() copies key-value pairs from it, you should not subclass dict. Implement your own mapping type by subclassing collections.Mapping or collections.MutableMapping or a class from the UserDict module.

Can I override what {} brackets do in python?

I've created a subclass of dict as per this question. What I'd like to do is be able to create a new dictionary of my subclass by using bracket notation. Namely, when I have {"key":"value"}, I'd like it to call mydict(("key","value")). Is this possible?
No. And for good reasons: it would violate the expectations of people reading the code. It would also likely break any third-party libraries that you import which would (reasonably) expect dict literals to be standard python dictionaries.
A better method to fix this without lots of extra typing is to simply add a static .from method on your custom dictionary class that attempts to consume the literal and returns an instance of your custom dictionary.
MyDict.from({
"key": "value"
})
Where an implementation of from might look something like
#classmethod
def from(cls, dictionary):
new_inst = cls()
for key, value of dictionary.items():
new_inst[key] = value
return newInst
Edit based on comment:
user2357112 correctly points out that you could just use the constructor as long as the dict constructor's signature is the same as your custom class:
some_instance = MyDict({"key": "value"})
If you've messed with it though you'll have to go the custom route a la from.

How to create a dynamically updating list of class instances, satisfying a particular condition? (Python)

I want to create a list of class instances that automatically updates itself following a particular condition on the instance attributes.
For example, I have a list of object of my custom class Person() and I want to be able to generate a list that always contains all the married persons, i.e. all persons having the attribute 'MAR_STATUS' equal to 'MARRIED'.
Is this possible at all in Python? I have used a C++ precompiler for microsimulations that had a very handy built-in called "actor_set" which did exactly this. But I have no idea of how it was implemented in C++.
Thank you.
List comprehension:
[person for person in people if person.MAR_STATUS == 'MARRIED']
If you need to assign it to a variable and you want that variable to automatically update on every access, you can put this same code in a lambda, a normal function, or, if your variable is a class member, in a property getter.
It is poor form to have "action at a distance" / mutations / side-effects unless it is very carefully controlled.
That said, imperative language will let you do this, if you really want to, as follows. Here we use python's [property getters and setters]:
MARRIED_SET = set()
def updateMarriedSet(changedPerson):
if hasattr(changedPerson,'married') and changedPerson.married==Person.MARRIED:
MARRIED_SET.add(changedPerson)
else:
MARRIED_SET.discard(changedPerson)
class Person(object):
...
#property
def married(self):
"""The person is married"""
return self._married
#married.setter
def married(self, newStatus):
self._married = newStatus
updateMarriedSet(self)
#married.deleter
def married(self):
del self._married
updateMarriedSet(self)
I can imagine this might, possibly, be useful to ensure accesses to getMarriedPeople() runs in O(1) time rather than amortized O(1) time.
The simple way is to generate the list on the fly e.g., as shown in #sr2222's answer.
As an alternative you could call an arbitrary callback each time MAR_STATUS changes. Use __new__ if Person instances are immutable or make MAR_STATUS a property and call registered callbacks in the setter method (see notifications in traits library for a more complex implementation).

Inserting additional items into an inherited list in Django/Python

I'm using some subclasses in my Django app, and I'm continuing that logic through to my admin implementation.
Currently, I have this admin defintion:
class StellarObjectAdmin(admin.ModelAdmin):
list_display = ('title','created_at','created_by','updated_at','updated_by)
Now, I have a Planet class, that is a subclass of StellarObject, with an additional field. I want to add this field to the list_display (not replace StellarObject's display entirely).
If I try something like this:
class PlanetAdmin(StellarObjectAdmin):
list_display.insert(1,'size')
I get the following error:
name 'list_display' is not defined
I will admit, I'm very new to python, and inheritance in general, so I'm sure that there is something simple I am missing.
Thank you
You'll need to use:
StellarObjectAdmin.list_display.insert(1, 'size')
Also, you'll need to change list_display from a tuple (which is immutable) to a list. Eg: list_display = [ ... ].
Finally, you'll probably be surprised by what happens: by inserting the item, you're going to be changing the list on StellarObjectAdmin. What you probably want to do is:
list_display = list(StellarObjectAdmin.list_display) # copy the list
list_display.insert(1, 'size')
Which will create a new copy of the list for your PlanetAdmin class.
This happens because of the way Python does inheritance. Basically, Python never injects names into a namespace (eg, some languages inject a magic this "variable" into methods, while Python forces you to explicitly define the equivalent — self — as the first argument of methods), and since a class is just another namespace, nothing (like, eg, values in its super classes) gets injected into it.
When you've got a class, B, which inherits from another class, A, and you try to look up a property on B — B.foo — it first checks to see if foo is in B's namespace, and if it isn't, it goes on to check A's namespace, and so on.
I hope that's clear… If not, I can clarify (or try to find relevant documentation).
David is spot on. Also, as a note, if you want to reference the variable within the class, you'll need to use 'self.'
Example:
Class A:
mylist = [1,2,3]
def display_list(self):
for i in self.mylist:
print i

Categories

Resources