I'm trying to subclass the IntEnum to start members' value at a certain value and then automatically set the value for subsequent members. This is my class:
class Abc(IntEnum):
def __init__(self, n=100):
super().__init__()
self._value_ = n + len(self.__class__.__members__)
A = () # 100
B = () # 101
Abc.A == Abc.B # expects False, but gets True
As shown above the comparison between the members is not correct. When printing out Abc.dict, I noticed that it _value2member_map_ does not look correct either.
mappingproxy({'A': <Abc.A: 100>,
'B': <Abc.B: 101>,
'__doc__': 'An enumeration.',
'__init__': <function __main__.Abc.__init__>,
'__module__': '__main__',
'__new__': <function enum.Enum.__new__>,
'_generate_next_value_': <function enum.Enum._generate_next_value_>,
'_member_map_': OrderedDict([('A', <Abc.A: 100>),
('B', <Abc.B: 101>)]),
'_member_names_': ['A', 'B'],
'_member_type_': int,
'_value2member_map_': {0: <Abc.B: 101>}})
Notice how '_value2member_map_' has key 0 instead of the expected values 100 and 101. I must be missing something in the init function, but I could not figure out how to properly do what I intended. Any help is appreciated.
Thank you.
First, there's a more idiomatic—and dead simple—way to do what you seem to be trying to do:
class Abc(IntEnum):
A = 100
B = auto()
Or, given that you're putting 100 and 101 in as comments anyway, live code is always better than comments:
class Abc(IntEnum):
A = 100
B = 101
The fact that you're not doing either of those is a signal to the reader that you're probably doing to do something more complicated. Except that, as far as I can tell, you aren't, so this is misleading.
Plus, you're combining two patterns that have directly opposite connotations: as the docs say, using the () idiom "signifies to the user that these values are not important", but using IntEnum obviously means that the numeric values of these enumeration constants are not just important but the whole point of them.
Not only that, but the user has to read through your method code to figure out what those important numeric values are, instead of just immediately reading them off.
Anyway, if you want to get this to work, the problem is that replacing _value_ after initialization isn't documented to do any good, and in fact it doesn't.
What you want to override is __new__, not __init__, as in the auto-numbering example in the docs.
But there are two differences here (both related to the fact that you're using IntEnum instead of Enum):
You cannot call object.__new__, because an IntEnum is an int, and object.__new__ can't be used on instances of builtin types like int. You can figure out the right base class dynamically from looking through cls's mro, or you can just hardcode int here.
You don't need an intermediate base class here to do the work. (You might still want one if you were going to create multiple auto-numbered IntEnums, of course.)
So:
class Abc(IntEnum):
def __new__(cls, n=100):
value = len(cls.__members__) + n
obj = int.__new__(cls, value)
obj._value_ = value
return obj
A = ()
B = ()
Related
This question already has answers here:
How to access (get or set) object attribute given string corresponding to name of that attribute
(3 answers)
Closed 3 years ago.
I have a Python class that have attributes named: date1, date2, date3, etc.
During runtime, I have a variable i, which is an integer.
What I want to do is to access the appropriate date attribute in run time based on the value of i.
For example,
if i == 1, I want to access myobject.date1
if i == 2, I want to access myobject.date2
And I want to do something similar for class instead of attribute.
For example, I have a bunch of classes: MyClass1, MyClass2, MyClass3, etc. And I have a variable k.
if k == 1, I want to instantiate a new instance of MyClass1
if k == 2, I want to instantiate a new instance of MyClass2
How can i do that?
EDIT
I'm hoping to avoid using a giant if-then-else statement to select the appropriate attribute/class.
Is there a way in Python to compose the class name on the fly using the value of a variable?
You can use getattr() to access a property when you don't know its name until runtime:
obj = myobject()
i = 7
date7 = getattr(obj, 'date%d' % i) # same as obj.date7
If you keep your numbered classes in a module called foo, you can use getattr() again to access them by number.
foo.py:
class Class1: pass
class Class2: pass
[ etc ]
bar.py:
import foo
i = 3
someClass = getattr(foo, "Class%d" % i) # Same as someClass = foo.Class3
obj = someClass() # someClass is a pointer to foo.Class3
# short version:
obj = getattr(foo, "Class%d" % i)()
Having said all that, you really should avoid this sort of thing because you will never be able to find out where these numbered properties and classes are being used except by reading through your entire codebase. You are better off putting everything in a dictionary.
For the first case, you should be able to do:
getattr(myobject, 'date%s' % i)
For the second case, you can do:
myobject = locals()['MyClass%s' % k]()
However, the fact that you need to do this in the first place can be a sign that you're approaching the problem in a very non-Pythonic way.
OK, well... It seems like this needs a bit of work. Firstly, for your date* things, they should be perhaps stored as a dict of attributes. eg, myobj.dates[1], so on.
For the classes, it sounds like you want polymorphism. All of your MyClass* classes should have a common ancestor. The ancestor's __new__ method should figure out which of its children to instantiate.
One way for the parent to know what to make is to keep a dict of the children. There are ways that the parent class doesn't need to enumerate its children by searching for all of its subclasses but it's a bit more complex to implement. See here for more info on how you might take that approach. Read the comments especially, they expand on it.
class Parent(object):
_children = {
1: MyClass1,
2: MyClass2,
}
def __new__(k):
return object.__new__(Parent._children[k])
class MyClass1(Parent):
def __init__(self):
self.foo = 1
class MyClass2(Parent):
def __init__(self):
self.foo = 2
bar = Parent(1)
print bar.foo # 1
baz = Parent(2)
print bar.foo # 2
Thirdly, you really should rethink your variable naming. Don't use numbers to enumerate your variables, instead give them meaningful names. i and k are bad to use as they are by convention reserved for loop indexes.
A sample of your existing code would be very helpful in improving it.
to get a list of all the attributes, try:
dir(<class instance>)
I agree with Daenyth, but if you're feeling sassy you can use the dict method that comes with all classes:
>>> class nullclass(object):
def nullmethod():
pass
>>> nullclass.__dict__.keys()
['__dict__', '__module__', '__weakref__', 'nullmethod', '__doc__']
>>> nullclass.__dict__["nullmethod"]
<function nullmethod at 0x013366A8>
While learning about how classes work in Python I came across a class definition example which behaved kind of strangely in my eyes.
The purpose of the example was to demonstrate how the behaviour of a static variable can be achieved in Python. The example was written as follows:
class MemberCounter:
members = 0
def init(self):
MemberCounter.members += 1
m1 = MemberCounter()
m1.init()
m2 = MemberCounter()
m2.init()
after setting up the class and creating the objects, I printed the values of the 'members' attribute. These were the results:
MemberCounter.members = 2
m1.members = 2
m2.members = 2
And that's when I got confused. While I was expecting for 'MemberCounter.members = 2' the two other results made no sense to me - why would both of 'm1' and 'm2' objects' 'members' value be equal to 2? I thought that both of the values should have been 0 - if the only attribute that was chaged is the 'members' attribute which was attached to the MemberCounter class why would it cause any change to the own unique 'members' value of each of the class' objects. It looks like the fact that the 'members' attribute is addresed like 'MemberCounter.members += 1' in the init() function of each object, completely overrides the unique values which m1.members and m2.members refer to and redirects their pointers to the MemberCounter.members value making all the three pointers point at the same value
==> m1.members = m2.members = MemberCounter.members.
Moreover, I have tried defining the class in an opossite way (Increasing self.members instead of MemberCounter.members):
class MemberCounter:
members = 0
def init(self):
self.members += 1
m1 = MemberCounter()
m1.init()
m2 = MemberCounter()
m2.init()
This definition yielded logical results (which got me curious about the above mentioned strange behaviour even more):
MemberCounter.members = 0
m1.members = 1
m2.members = 1
In short, I was curious about why the first class definition behaves in such a strange way? Why the mere 'MemberCounter.members += 1' statement completely erased 'm1.members' and 'm2.members' own unique value and made it equal to the MemberCounter.members value.
I hope I was able to clearly present my problem and I will be extremly happy to get an insight about this strange behaviour :)
That you can read a static attribute with instance.attribute notation as alternative to the more natural class.attribute notation, is an intended feature in Python.
From the documentation:
Both static data and static methods (in the sense of C++ or Java) are supported in Python.
For static data, simply define a class attribute. To assign a new
value to the attribute, you have to explicitly use the class name in
the assignment:
class C:
count = 0 # number of times C.__init__ called
def __init__(self):
C.count = C.count + 1
def getcount(self):
return C.count # or return self.count
c.count also refers to C.count for any c such that
isinstance(c, C) holds, unless overridden by c itself or by some
class on the base-class search path from c.__class__ back to C.
Caution: within a method of C, an assignment like self.count = 42
creates a new and unrelated instance named “count” in self’s own dict.
Rebinding of a class-static data name must always specify the class
whether inside a method or not:
C.count = 314
The paragraph just below the first code block explains your doubts. The "Caution" paragraph explains what you found logical.
What is the difference between the two class definitions below,
class my_dict1(dict):
def __init__(self, data):
self = data.copy()
self.N = sum(self.values)
The above code results in AttributeError: 'dict' object has no attribute 'N', while the below code compiles
class my_dict2(dict):
def __init__(self, data):
for k, v in data.items():
self[k] = v
self.N = sum(self.values)
For example,
d = {'a': 3, 'b': 5}
a = my_dict1(d) # results in attribute error
b = my_dict2(d) # works fine
By assigning self itself to anything you assign self to a completely different instance than you were originally dealing with, making it no longer the "self". This instance will be of the broader type dict (because data is a dict), not of the narrower type my_dict1. You would need to do self["N"] in the first example for it to be interpreted without error, but note that even with this, in something like:
abc = mydict_1({})
abc will still not have the key "N" because a completely difference instance in __init__ was given a value for the key "N". This shows you that there's no reasonable scenario where you want to assign self itself to something else.
In regards to my_dict2, prefer composition over inheritance if you want to use a particular dict as a representation of your domain. This means having data as an instance field. See the related C# question Why not inherit from List?, the core answer is still the same. It comes down to whether you want to extend the dict mechanism vs. having a business object based on it.
I have a class with several named attributes. I would like to be able to pass one of the classes attributes to itself and be able to determine specifically which attribute was passed.
Below is a trivial example of how I was doing it (using the "is" operator), until I discovered that special cached variable IDs are used for integer values between -5 and 256.
class AClass:
def __init__(self, one, two, three):
self.one = one
self.two = two
self.three = three
def getIndex(self, attribute):
if attribute is self.one:
return 1
elif attribute is self.two:
return 2
elif attribute is self.three:
return 3
def setByIndex(self, i, value):
if i == 1:
self.one = value
elif i == 2:
self.two = value
elif i == 3:
self.three = value
def setByAttrib(self, attribute, value):
i = self.getIndex(attribute)
self.setByIndex(i, value)
object = AClass(0, 0, 0)
object.setByAttrib(object.three, 10)
In the above example, the intention is to set object.three to 10. However, since all attributes are pointing to the cached location of integer 0, the getIndex function would evaluate true on any of them, and object.one (which appears first) will get set to 10. If the object was initialized with values 257, 257, 257, functionality would presumably be as intended.
So the question is, is there a way to either:
a) force the system to assign non-cached, unique memory locations for these attributes (even if they are set between -5 and 256), or
b) use some other method to check if an attribute passed as an argument is uniquely itself?
EDIT:
Since it was asked a couple times, one of the reasons I'm using this paradigm is due to the the lack of pointers in python. In the example above, the setByIndex function could be doing some complicated work on the attribute. Rather than write multiple identical functions for each variable (eg setOne, setTwo, setThree), I can write out a single generic function that is retrieving and setting by index (index is basically acting like a pointer). Yes, I could pass the attribute value as an argument and return the new set value and do the assignment in the scope where the specific attribute is known, but I am already returning a value. Yes, I could return a list, but it adds more complexity.
I do realize that there are better ways to implement what I need (eg key-value pairs for the attributes and index numbers) but it would be a lot of work to implement (thousands of changes). If there was a way to use the varaible ID as my unique identifier and continue to use the "is" operator (or similar), I wouldn't need to change too much. Not looking possible though. Appreciate the comments/responses.
I wouldn't worry about the memory locations, they are simply an implementation detail here. It's really about function design, so if you want to set object.three, then do exactly that, otherwise, you can create a mapping to an index if you wanted to:
class MyClass:
def __init__(self, *args):
self.one, self.two, self.three, *_ = args
# get an object by it's index
def get_by_index(self, index):
# here's how you could create such a mapping
opts = dict(zip((1, 2, 3), ('one', 'two', 'three')))
try:
return getattr(self, opts[index])
except KeyError as e:
raise ValueError(f"Improper alias for attribute, select one of {', '.join(opts)}") from e
# if you want to set by an index, then do that this way
def set_by_index(self, index, val):
opts = dict(zip((1, 2, 3), ('one', 'two', 'three')))
try:
setattr(self, opts[index], val)
except KeyError as e:
raise ValueError(f"Improper alias for attribute, select one of {', '.join(opts)}") from e
# otherwise, just set the attribute by the name
a = MyClass(0, 0, 0)
a.three = 55
The thing is, you're right, is will look at the three 0's the same way, because it never copied that data in the first place. one, two, three point to the same data because they were assigned the same data. Once you assign the attribute again, you've effectively re-binded that attribute to a new value, rather than updating an existing one.
Point being, don't worry about where the memory is for this implementation, just set explicitly against the attribute
I know they practically do the same thing, but if you were to lets say do something like...
curpop = this_other_ndarray
i = 0;
while i<20:
curpop[:] = select(curpop, parameter, parameter1)
stuff
more stuff
curpop[:] = some_stuff_I_did
i += 1;
So the above code is just saying, before I enter a generational loop I am going to take an initial generation of populations from 'this other ndarray'.
Then I am planning on changing that array over and over and everytime I restart the loop I will only select some from itself but I will declare that as what it is equal to now. Is this okay to do in Python3?
Is the declaration of
'array[:] = some of it self'
versus
'array = some of itself'
different at all?
These are two totally different things.
The first is simple assignment.
foo = bar
This assignment statement merely says that the name on the left-hand side now refers to the same object as the name on the right-hand side. These statements do not modify either object.
Objects are neither created nor necessarily destroyed. If you lose the last name of an object, however, you will have lost the object. The CPython runtime uses reference counting as a memory management strategy, and will automatically reclaim objects that have a zero reference count.
In Python, variables act simply like object names that you can create, destroy, and change what they reference. Think of them like name-tags.
Now, a statement like:
foo[:] = bar
Is actually a method call. It can be translated to:
foo.__setitem__(slice(None, None, None), bar)
Observe:
>>> class Foo:
... def __setitem__(self, key, value):
... print("Key:", key, "Value:", value)
...
>>> class Bar: pass
...
>>> foo = Foo()
>>> bar = Bar()
>>> foo[:] = bar
Key: slice(None, None, None) Value: <__main__.Bar object at 0x104aa5c50>
So, really, the type of the objects control the ultimate effects of this statement. In the case of numpy.ndarray objects, slice-based assignment works similarly to list slice based assignment in that it mutates the array object in-place, with a few more caveats like broadcasting to throw into the mix. See the relevant docs:
https://docs.scipy.org/doc/numpy-1.13.0/user/basics.indexing.html#assigning-values-to-indexed-arrays
In many cases
curpop[:]= iterable_value_as_tuple_string_dictionary_and_list_etc
do the same thing as
curpop=iterable_value_as_tuple_string_dictionary_and_list_etc
of course assign a string first or at any step will remove the ability in the next steps to use [:] to assign something again
note that
curpop[:]= notiterable_value != curpop=notiterable_value
as the first assign notiterable_value to each element of curpop and the second assign the value notiterable_value to curpop itself