Python object's __iter__not getting called - python

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.

Related

Function to set namedtuple attributes?

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.

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.

Proper declaration of an empty Django PostgreSQL JSONField default value in migration file

I'm a little lost interpreting Django's explanation of applying a default value to a PostgreSQL JSONField:
If you give the field a default, ensure it’s a callable such as dict (for an empty default) or a callable that returns a dict (such as a function). Incorrectly using default={} creates a mutable default that is shared between all instances of JSONField.
So in my model file I've declared the default as such
foo = JSONField(default=dict())
however when I generate the migration operation for the new field this is the result
migrations.AddField(
model_name='bar',
name='foo',
field=django.contrib.postgres.fields.jsonb.JSONField(default={}))
I'm just not sure whether or not this result is in accordance with the documentation's suggestion. Is this valid, or should I modify the generated default to call dict()?
A callable is an object x that can be called, hence x() is valid, and will not raise an error because it is not callable (although there can be errors during the call, for example because the function somewhere yields an error).
dict() is actually completely equivalent to {}, that is not a callable, since {}(), will not result in constructing anything. But dict itself on the other hand is a reference to the dict class, and if we call it, we construct a new dict. So we should write it like:
# no brackets! We do not make a call, but pass the callable
foo = JSONField(default=dict)
So we do not call the dict class, we pass a reference to the class, and such classes are callable: if you call them, you typically construct a new instance (although this behavior can be changed).
Passing the callable is of vital importance here, since otherwise Django will each time use a reference to the same dictionary. As a result changes to one of the dictionaries will change the others that change the reference. If you store the dictionary and reload it, then this will be a different dictionary, but as long as you constructed two models, during the same Python run, these would be the same objects.
If you however pass a function, the function will be called, and thus produce two different objects, both empty dictionaries. But changes to the first dictionary will not reflect in the second one.
The same holds if you for instance would want to initialize a JSON field with a dictionary that contains data, instead of writing default={'a': 4}, one has to define it like:
def default_somemodel_dict():
return {'a': 4}
class SomeModel(models.Model):
foo = JSONField(default=default_somemodel_dict)

Python collections.MappingView

I was checking out the very nice collections library and more specific the Abstract Base Classes (ABC). One I could not get my head around: the MappingView.
What is its use? What is its advantage over Sized? An example perhaps?
Documentation says its base class is Sized, but on the other hand there is a len mixin... So do we have to implement len, or not?
For the documentation, see collections
MappingView is essentially the base class for user defined views. It implements the Sized interface by providing the __len__ attribute which is the length of its _mapping member, so if this implementation is fine for you, you do not need to implement your own __len__.
It holds common code for KeysView, ItemsView and ValuesView. These last classes can be used wherever a view like my_dict.keys(), my_dict.items() or my_dict.values() would be expected. If you create a new user defined kind of data and want to create a view that can be neither compared to keys, values or items, then you could subclass MappingView directly and implement differently the __contains__ and __iter__ functions.

Python builtin functions aren't really functions, right?

Was just thinking about Python's dict "function" and starting to realize that dict isn't really a function at all. For example, if we do dir(dict), we get all sorts of methods that aren't include in the usual namespace of an user defined function. Extending that thought, its similar to dir(list) and dir(len). They aren't function, but really types. But then I'm confused about the documentation page, http://docs.python.org/2/library/functions.html, which clearly says functions. (I guess it should really just says builtin callables)
So what gives? (Starting to seem that making the distinction of classes and functions is trivial)
It's a callable, as are classes in general. Calling dict() is effectively to call the dict constructor. It is like when you define your own class (C, say) and you call C() to instantiate it.
One way that dict is special, compared to, say, sum, is that though both are callable, and both are implemented in C (in cpython, anyway), dict is a type; that is, isinstance(dict, type) == True. This means that you can use dict as the base class for other types, you can write:
class MyDictSubclass(dict):
pass
but not
class MySumSubclass(sum):
pass
This can be useful to make classes that behave almost like a builtin object, but with some enhancements. For instance, you can define a subclass of tuple that implements + as vector addition instead of concatenation:
class Vector(tuple):
def __add__(self, other):
return Vector(x + y for x, y in zip(self, other))
Which brings up another interesting point. type is also implemented in C. It's also callable. Like dict (and unlike sum) it's an instance of type; isinstance(type, type) == True. Because of this weird, seemingly impossible cycle, type can be used to make new classes of classes, (called metaclasses). You can write:
class MyTypeSubclass(type):
pass
class MyClass(object):
__metaclass__ = MyTypeSubclass
or, in Python 3:
class MyClass(metaclass=MyTypeSubclass):
pass
Which give the interesting result that isinstance(MyClass, MyTypeSubclass) == True. How this is useful is a bit beyond the scope of this answer, though.
dict() is a constructor for a dict instance. When you do dir(dict) you're looking at the attributes of class dict. When you write a = dict() you're setting a to a new instance of type dict.
I'm assuming here that dict() is what you're referring to as the "dict function". Or are you calling an indexed instance of dict, e.g. a['my_key'] a function?
Note that calling dir on the constructor dict.__init__
dir(dict.__init__)
gives you what you would expect, including the same stuff as you'd get for any other function. Since a call to the dict() constructor results in a call to dict.__init__(instance), that explains where those function attributes went. (Of course there's a little extra behind-the-scenes work in any constructor, but that's the same for dicts as for any object.)

Categories

Resources