How do I create a tuple with an attribute using Python? - python

I have a class WeightedArc defined as follows:
class Arc(tuple):
#property
def tail(self):
return self[0]
#property
def head(self):
return self[1]
#property
def inverted(self):
return Arc((self.head, self.tail))
def __eq__(self, other):
return self.head == other.head and self.tail == other.tail
class WeightedArc(Arc):
def __new__(cls, arc, weight):
self.weight = weight
return super(Arc, cls).__new__(arc)
This code clearly doesn't work, because self isn't defined for WeightArc.__new__. How do I assign the attribute weight to the WeightArc class?

The fixed-up version of your original code is:
class WeightedArc(Arc):
def __new__(cls, arc, weight):
self = tuple.__new__(cls, arc)
self.weight = weight
return self
Another approach to look at the verbose option for collections.namedtuple to see an example of how to subclass tuple:
>>> from collections import namedtuple, OrderedDict
>>> _property = property
>>> from operator import itemgetter as _itemgetter
>>> Arc = namedtuple('Arc', ['head', 'tail'], verbose=True)
class Arc(tuple):
'Arc(head, tail)'
__slots__ = ()
_fields = ('head', 'tail')
def __new__(_cls, head, tail):
'Create new instance of Arc(head, tail)'
return _tuple.__new__(_cls, (head, tail))
#classmethod
def _make(cls, iterable, new=tuple.__new__, len=len):
'Make a new Arc object from a sequence or iterable'
result = new(cls, iterable)
if len(result) != 2:
raise TypeError('Expected 2 arguments, got %d' % len(result))
return result
def __repr__(self):
'Return a nicely formatted representation string'
return 'Arc(head=%r, tail=%r)' % self
def _asdict(self):
'Return a new OrderedDict which maps field names to their values'
return OrderedDict(zip(self._fields, self))
def _replace(_self, **kwds):
'Return a new Arc object replacing specified fields with new values'
result = _self._make(map(kwds.pop, ('head', 'tail'), _self))
if kwds:
raise ValueError('Got unexpected field names: %r' % kwds.keys())
return result
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return tuple(self)
head = _property(_itemgetter(0), doc='Alias for field number 0')
tail = _property(_itemgetter(1), doc='Alias for field number 1')
You can cut, paste, and modify this code, or just subclass from it as shown in the namedtuple docs.
To extend this class, build off of the fields in Arc:
WeightedArc = namedtuple('WeightedArc', Arc._fields + ('weight',))

Another approach to look at the verbose option for collections.namedtuple to see an example of how to subclass tuple
Better yet, why not use namedtuple ourselves? :)
class Arc(object):
def inverted(self):
d = self._asdict()
d['head'], d['tail'] = d['tail'], d['head']
return self.__class__(**d)
class SimpleArc(Arc, namedtuple("SimpleArc", "head tail")): pass
class WeightedArc(Arc, namedtuple("WeightedArc", "head tail weight")): pass

Related

Intuative way to inherit validating classes

I've been using this style of inheritance to validate values set on instances of objects, but I'm wondering if there is a more fluent way to do this.
I'm following a spec where items of a certain classification (Foo) contain elements of a certain composition (Fe).
class Typed:
def __set__(self, obj, value):
assert isinstance(value, self._type), 'Incorrect type'
class Integer(Typed):
_type = int
class Float(Typed):
_type = float
class Positive(Typed):
def __set__(self, obj, value):
super().__set__(obj, value)
assert value >= 0, 'Positive Values Only Accepted'
class PositiveInteger(Integer, Positive):
pass
class PositiveFloat(Float, Positive):
pass
class Sized(Typed):
def __set__(self, obj, value):
super().__set__(obj, value)
assert value <= 2**self.size-1, f'{value} is too High'
class Fe(Sized, PositiveInteger):
name = 'Integer, 8 bit unsigned'
size = 8
class Foo(Fe):
name = 'Classificaion1'
def __set__(self, obj, id):
super().__set__(obj, id)
obj._id = id
def __get__(self, obj, objType=None):
return obj._id
def __del__(self):
pass
If you really need this level of abstraction, this is possibly the best way you can do it. My suggestion bellow can maybe save one line per class.
If you can afford to have attributes like "size" and "type" to be defined
on the final class, a richer base class and a declarative structure containing the checks as "lambda functions" can be used like this.
Note the usage of __init_subclass__ to check if all the parametes
needed for the guard expressions are defined:
from typing import Sequence
GUARDS = {
"typed": ((lambda self, value: "Incorrect type" if not instance(value, self._type) else None), ("_typed",)),
"positive": ((lambda self, value: "Only positive values" if value < 0 else None), ()),
"sized": ((lambda self, value: None if value <= 2 ** self.size - 1 else f"{value} must be smaller than 2**{self.size}"), ("size",)),
}
class DescriptorBase:
guards: Sequence[str]
def __init_subclass__(cls):
_sentinel = object()
for guard_name in cls.guards:
guard = GUARDS[guard_name]
required_attrs = guard[1]
missing = []
for attr in required_attrs:
if getattr(cls, attr, _sentinel) is _sentinel:
missing.append(attr)
if missing:
raise TypeError("Guarded descriptor {cls.__name__} did not declare required attrs: {missing}")
def __set_name__(self, owner, name):
self._name = f"_{name}""
def __set__(self, instance, value):
errors = []
for guard_name in self.guards:
if (error:= GUARDS[guard_name](self, value)) is not None:
errors.append(error)
if errors:
raise ValueError("\n".join(errors))
setattr (instance, self._name, value)
def __get__(self, instance, owner):
if instance is None:
return self
return getattr(instance, self.name)
def __del__(self, instance):
delattr(instance, self._name)
class Foo(DescriptorBase):
guards = ("typed", "positive", "sized")
size = 8
type_ = int
# No other code required here: __get__, __set__, __del__ handled in superclass
class UseAttr:
# Actual smart-attr usage:
my_foo = Foo()
Actually, if you want the class hierarchy, with less lines (no need to declare a __set__ method in each class), this approach can be used as well:
just change __init_superclass__ to collect "guards" in all superclasses,
and consolidate a single guards list on the class being defined, and then
define your composable guard-classes just as:
class Positive(BaseDescriptor):
guards = ("positive",)
class Sized(BaseDescriptor):
guards = ("sized",)
size = None
class Foo(Positive, Sized):
size = 8
class Fe(Foo):
name = "Fe name"
Actually, the change needed for this to work can be as simple as:
def __init_subclass__(cls):
_sentinel = object()
all_guards = []
for supercls in cls.__mro__:
all_guards.extend(getattr(supercls, "guards", ()))
# filter unique:
seem = {}
new_guards = []
for guard in all_guards:
if guard not in seem:
new_guards.append(guard)
seem.add(guard)
cls.guards = new_guards
for guard_name in cls.guards:
Also note that you could also collect the contents of the "GUARDS" registry from each defined class, instead of having to declare everything as lambdas before hand. I think you can get the idea from here on.

Python is adding values to multiple instances

I have created a descriptor for lists.
After testing it seems that every time I append a value to a list of one instance, it is being added to another instance as well.
Even weirder, in the unittests it keeps appending to the list, and not resetting on every test.
My descriptor main class:
class Field(object):
def __init__(self, type_, name, value=None, required=False):
self.type = type_
self.name = "_" + name
self.required = required
self._value = value
def __get__(self, instance, owner):
return getattr(instance, self.name, self.value)
def __set__(self, instance, value):
raise NotImplementedError
def __delete__(self, instance):
raise AttributeError("Can't delete attribute")
#property
def value(self):
return self._value
#value.setter
def value(self, value):
self._value = value if value else self.type()
Descriptor list class:
class ListField(Field):
def __init__(self, name, value_type):
super(ListField, self).__init__(list, name, value=[])
self.value_type = value_type
def __set__(self, instance, value):
if not isinstance(value, list):
raise TypeError("{} must be a list".format(self.name))
setattr(instance, self.name, value)
def __iter__(self):
for item in self.value:
yield item
def __len__(self):
return len(self.value)
def __getitem__(self, item):
return self.value[item]
def append(self, value):
if not isinstance(value, self.value_type):
raise TypeError("Value is list {} must be of type {}".format(self.name, self.value_type))
self.value.append(value)
Unittests:
# Class I created solely for testing purposes
class ListTestClass(object):
l = ListField("l", int)
class TestListFieldClass(unittest.TestCase):
def setUp(self):
self.listobject = ListTestClass()
def test_add(self):
# The first number is added to the list
self.listobject.l.append(2)
def test_multiple_instances(self):
# This test works just fine
l1 = ListField("l1", int)
l2 = ListField("l2", int)
l1.append(1)
l2.append(2)
self.assertEqual(l1[0], 1)
self.assertEqual(l2[0], 2)
def test_add_multiple(self):
# This test works just fine
l1 = ListField("l1", int)
l1.append(1)
l1.append(2)
self.assertEqual(l1[0], 1)
self.assertEqual(l1[1], 2)
def test_add_error(self):
# This test works just fine
with self.assertRaises(TypeError):
l1 = ListField("l1", int)
l1.append("1")
def test_overwrite_list(self):
# This test works just fine
l1 = ListField("l1", int)
l1 = []
l1.append(1)
def test_overwrite_error(self):
# This test works just fine
l1 = ListTestClass()
l1.l.append(1)
with self.assertRaises(TypeError):
l1.l = "foo"
def test_multiple_model_instances(self):
# I create 2 more instances of ListTestClass
l1 = ListTestClass()
l2 = ListTestClass()
l1.l.append(1)
l2.l.append(2)
self.assertEqual(l1.l[0], 1)
self.assertEqual(l2.l[0], 2)
The last test fails
Failure
Traceback (most recent call last):
File "/home/user/project/tests/test_fields.py", line 211, in test_multiple_model_instances
self.assertEqual(l1.l[0], 1)
AssertionError: 2 != 1
When I look at the values for l1.1 and l2.l, they both have a list containing [2, 1, 2]
What am I missing here?
I looked to the memory addresses and it seems that the lists all point to the same object.
class ListFieldTest(object):
lf1 = ListField("lf1", int)
class TestClass(object):
def __init__(self):
l1 = ListFieldTest()
l2 = ListFieldTest()
l1.lf1.append(1)
l2.lf1.append(2)
print(l1.lf1)
print(l2.lf1)
print(hex(id(l1)))
print(hex(id(l2)))
print(hex(id(l1.lf1)))
print(hex(id(l2.lf1)))
This prints
[1, 2]
[1, 2]
0x7f987da018d0 --> Address for l1
0x7f987da01910 --> Address for l2
0x7f987d9c4bd8 --> Address for l1.lf1
0x7f987d9c4bd8 --> Address for l2.lf1
ListTestClass.l is a class attribute, so it is shared by all instances of the class. Instead, you should create an instance attribute, eg in the __init__ method:
class ListTestClass(object):
def __init__(self):
self.l = ListField("l", int)
Similar remarks apply to ListFieldTest. There may be other similar problems elsewhere in your code, I haven't examined it closely.
According to this source, the proper form is
class ListTestClass(object):
l_attrib = ListField("l", int)
def __init__(self)
self.l = l_attrib
Thanks to both #PM 2Ring and volcano I found the answer.
In the end this works great for value types:
class IntTestClass(object):
i = IntegerField("i")
However for a reference type (like a list) that won't work and you have to add a new list
class ListTestClass(object):
l = ListField("l", int)
def __init__(self):
self.l = []

Can decorator wrap setter and getter in python?

I want to build various setter and getter. Fot not copy and paste the code, I thought something to solve it. Can decorator do it?
#property
def !!variable_name!!(self):
return self.__!!variable_name!!
#!!variable_name!!.setter
def !!variable_name!!(self, input):
self.__!!variable_name!! = input
Is it possible like macro in C?
It's unclear why you would want to do something like this—create a property with setter that ignores its value argument—but the answer is "Yes", you can do it by creating a function that returns a custom property object:
However you can't use # syntax to apply it. Instead you have to utilize it as shown:
def attribute_property(name, input_value):
STORAGE_NAME = '_' + name
#property
def prop(self):
return getattr(self, STORAGE_NAME)
#prop.setter
def prop(self, ignored):
setattr(self, STORAGE_NAME, input_value)
return prop
# EXAMPLE USAGE
class Person(object):
name = attribute_property('name', 'Monty')
def __init__(self, name, age):
self.name = name # ignores value of passed "name" argument!
self.age = age
user = Person('Rodrigo', 42)
print('user.name: {!r}'.format(user.name))
print('user.age: {!r}'.format(user.age))
Output:
user.name: 'Monty'
user.age: 42
Simple answer: Yes, that's possible using the descriptor protocol. For example you want to save variables with a leading underscore and access them without the leading underscore such a descriptor would work:
from six import string_types
class DescriptorSingleLeadingUnderscore(object):
def __init__(self, attr, doc=""):
if not isinstance(attr, string_types):
# Not a string so take the documentation (if avaiable) and name
# from the method.
if attr.__doc__:
doc = attr.__doc__
attr = attr.__name__
self.__doc__ = doc # Set the documentation of the instance.
self.attr = '_' + attr # Add leading underscore to the attribute name
def __get__(self, instance, owner=None):
if instance is None:
return self
return getattr(instance, self.attr, None)
def __set__(self, instance, value):
setattr(instance, self.attr, value)
def __delete__(self, instance):
delattr(instance, self.attr)
class X(object):
someproperty = DescriptorSingleLeadingUnderscore('someproperty')
someproperty1 = DescriptorSingleLeadingUnderscore('someproperty1')
someproperty2 = DescriptorSingleLeadingUnderscore('someproperty2')
someproperty3 = DescriptorSingleLeadingUnderscore('someproperty3')
#DescriptorSingleLeadingUnderscore
def it_also_works_as_decorator(self):
pass # this code is never executed!
And a test case:
>>> x = X()
>>> x.someproperty = 100
>>> x.someproperty
100
>>> x._someproperty
100
>>> x.it_also_works_as_decorator = 100
>>> x.it_also_works_as_decorator
100
>>> x._it_also_works_as_decorator
100

Is there a comparison key for set objects?

Is there a way to give a comparator to set() so when adding items it checks an attribute of that item for likeness rather than if the item is the same? For example, I want to use objects in a set that can contain the same value for one attribute.
class TestObj(object):
def __init__(self, value, *args, **kwargs):
self.value = value
super().__init__(*args, **kwargs)
values = set()
a = TestObj('a')
b = TestObj('b')
a2 = TestObj('a')
values.add(a) # Ok
values.add(b) # Ok
values.add(a2) # Not ok but still gets added
# Hypothetical code
values = set(lambda x, y: x.value != y.value)
values.add(a) # Ok
values.add(b) # Ok
values.add(a2) # Not added
I have implemented my own sorta thing that does similar functionality but wanted to know if there was a builtin way.
from Queue import Queue
class UniqueByAttrQueue(Queue):
def __init__(self, attr, *args, **kwargs):
Queue.__init__(self, *args, **kwargs)
self.attr = attr
def _init(self, maxsize):
self.queue = set()
def _put(self, item):
# Potential race condition, worst case message gets put in twice
if hasattr(item, self.attr) and item not in self:
self.queue.add(item)
def __contains__(self, item):
item_attr = getattr(item, self.attr)
for x in self.queue:
x_attr = getattr(x, self.attr)
if x_attr == item_attr:
return True
return False
def _get(self):
return self.queue.pop()
Just define __hash__ and __eq__ on the object in terms of the attribute in question and it will work with sets. For example:
class TestObj(object):
def __init__(self, value, *args, **kwargs):
self.value = value
super().__init__(*args, **kwargs)
def __eq__(self, other):
if not instance(other, TestObj):
return NotImplemented
return self.value == other.value
def __hash__(self):
return hash(self.value)
If you can't change the object (or don't want to, say, because other things are important to equality), then use a dict instead. You can either do:
mydict[obj.value] = obj
so new objects replace old, or
mydict.setdefault(obj.value, obj)
so old objects are maintained if the value in question is already in the keys. Just make sure to iterate using .viewvalues() (Python 2) or .values() (Python 3) instead of iterating directly (which would get the keys, not the values). You could actually use this approach to make a custom set-like object with a key as you describe (though you'd need to implement many more methods than I show to make it efficient, the default methods are usually fairly slow):
from collections.abc import MutableSet # On Py2, collections without .abc
class keyedset(MutableSet):
def __init__(self, it=(), key=lambda x: x):
self.key = key
self.contents = {}
for x in it:
self.add(x)
def __contains__(self, x):
# Use anonymous object() as default so all arguments handled properly
sentinel = object()
getval = self.contents.get(self.key(x), sentinel)
return getval is not sentinel and getval == x
def __iter__(self):
return iter(self.contents.values()) # itervalues or viewvalues on Py2
def __len__(self):
return len(self.contents)
def add(self, x):
self.contents.setdefault(self.key(x), x)
def discard(self, x):
self.contents.pop(self.key(x), None)

How to create a class instance without calling initializer?

Is there any way to avoid calling __init__ on a class while initializing it, such as from a class method?
I am trying to create a case and punctuation insensitive string class in Python used for efficient comparison purposes but am having trouble creating a new instance without calling __init__.
>>> class String:
def __init__(self, string):
self.__string = tuple(string.split())
self.__simple = tuple(self.__simple())
def __simple(self):
letter = lambda s: ''.join(filter(lambda s: 'a' <= s <= 'z', s))
return filter(bool, map(letter, map(str.lower, self.__string)))
def __eq__(self, other):
assert isinstance(other, String)
return self.__simple == other.__simple
def __getitem__(self, key):
assert isinstance(key, slice)
string = String()
string.__string = self.__string[key]
string.__simple = self.__simple[key]
return string
def __iter__(self):
return iter(self.__string)
>>> String('Hello, world!')[1:]
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
String('Hello, world!')[1:]
File "<pyshell#1>", line 17, in __getitem__
string = String()
TypeError: __init__() takes exactly 2 positional arguments (1 given)
>>>
What should I replace string = String(); string.__string = self.__string[key]; string.__simple = self.__simple[key] with to initialize the new object with the slices?
EDIT:
As inspired by the answer written below, the initializer has been edited to quickly check for no arguments.
def __init__(self, string=None):
if string is None:
self.__string = self.__simple = ()
else:
self.__string = tuple(string.split())
self.__simple = tuple(self.__simple())
When feasible, letting __init__ get called (and make the call innocuous by suitable arguments) is preferable. However, should that require too much of a contortion, you do have an alternative, as long as you avoid the disastrous choice of using old-style classes (there is no good reason to use old-style classes in new code, and several good reasons not to)...:
class String(object):
...
bare_s = String.__new__(String)
This idiom is generally used in classmethods which are meant to work as "alternative constructors", so you'll usually see it used in ways such as...:
#classmethod
def makeit(cls):
self = cls.__new__(cls)
# etc etc, then
return self
(this way the classmethod will properly be inherited and generate subclass instances when called on a subclass rather than on the base class).
A trick the standard pickle and copy modules use is to create an empty class, instantiate the object using that, and then assign that instance's __class__ to the "real" class. e.g.
>>> class MyClass(object):
... init = False
... def __init__(self):
... print 'init called!'
... self.init = True
... def hello(self):
... print 'hello world!'
...
>>> class Empty(object):
... pass
...
>>> a = MyClass()
init called!
>>> a.hello()
hello world!
>>> print a.init
True
>>> b = Empty()
>>> b.__class__ = MyClass
>>> b.hello()
hello world!
>>> print b.init
False
But note, this approach is very rarely necessary. Bypassing the __init__ can have some unexpected side effects, especially if you're not familiar with the original class, so make sure you know what you're doing.
Using a metaclass provides a nice solution in this example. The metaclass has limited use but works fine.
>>> class MetaInit(type):
def __call__(cls, *args, **kwargs):
if args or kwargs:
return super().__call__(*args, **kwargs)
return cls.__new__(cls)
>>> class String(metaclass=MetaInit):
def __init__(self, string):
self.__string = tuple(string.split())
self.__simple = tuple(self.__simple())
def __simple(self):
letter = lambda s: ''.join(filter(lambda s: 'a' <= s <= 'z', s))
return filter(bool, map(letter, map(str.lower, self.__string)))
def __eq__(self, other):
assert isinstance(other, String)
return self.__simple == other.__simple
def __getitem__(self, key):
assert isinstance(key, slice)
string = String()
string.__string = self.__string[key]
string.__simple = self.__simple[key]
return string
def __iter__(self):
return iter(self.__string)
>>> String('Hello, world!')[1:]
<__main__.String object at 0x02E78830>
>>> _._String__string, _._String__simple
(('world!',), ('world',))
>>>
Addendum:
After six years, my opinion favors Alex Martelli's answer more than my own approach. With meta-classes still on the mind, the following answer shows how the problem can be solved both with and without them:
#! /usr/bin/env python3
METHOD = 'metaclass'
class NoInitMeta(type):
def new(cls):
return cls.__new__(cls)
class String(metaclass=NoInitMeta if METHOD == 'metaclass' else type):
def __init__(self, value):
self.__value = tuple(value.split())
self.__alpha = tuple(filter(None, (
''.join(c for c in word.casefold() if 'a' <= c <= 'z') for word in
self.__value)))
def __str__(self):
return ' '.join(self.__value)
def __eq__(self, other):
if not isinstance(other, type(self)):
return NotImplemented
return self.__alpha == other.__alpha
if METHOD == 'metaclass':
def __getitem__(self, key):
if not isinstance(key, slice):
raise NotImplementedError
instance = type(self).new()
instance.__value = self.__value[key]
instance.__alpha = self.__alpha[key]
return instance
elif METHOD == 'classmethod':
def __getitem__(self, key):
if not isinstance(key, slice):
raise NotImplementedError
instance = self.new()
instance.__value = self.__value[key]
instance.__alpha = self.__alpha[key]
return instance
#classmethod
def new(cls):
return cls.__new__(cls)
elif METHOD == 'inline':
def __getitem__(self, key):
if not isinstance(key, slice):
raise NotImplementedError
cls = type(self)
instance = cls.__new__(cls)
instance.__value = self.__value[key]
instance.__alpha = self.__alpha[key]
return instance
else:
raise ValueError('METHOD did not have an appropriate value')
def __iter__(self):
return iter(self.__value)
def main():
x = String('Hello, world!')
y = x[1:]
print(y)
if __name__ == '__main__':
main()
Pass another argument to the constructor, like so:
def __init__(self, string, simple = None):
if simple is None:
self.__string = tuple(string.split())
self.__simple = tuple(self.__simple())
else:
self.__string = string
self.__simple = simple
You can then call it like this:
def __getitem__(self, key):
assert isinstance(key, slice)
return String(self.__string[key], self.__simple[key])
Also, I'm not sure it's allowed to name both the field and the method __simple. If only for readability, you should change that.

Categories