Is it safe to compare enum objects? - python

I have a module that defines an enum this way:
import enum
class MyEnum(enum.IntEnum):
FIRST = 1
SECOND = 2
and a function that returns:
def return_a_value():
my_enum = MyEnum(2)
return my_enum
When comparing the return value, is it safe to write code like this:
if return_a_value() == MyEnum.SECOND:
or am I supposed to access the value field instead for comparison?

It is safe-enough, although, someone can always implement an object's __eq__ method to return whatever they want.
But given that enum's are singletons, you can actually use is safely:
if return_a_value() is MyEnum.SECOND:

Related

How to make object from dictionary readable

I created a class Demo in which I added a constructor with an empty dictionary in it. With the method addSomething inside the class I add key value pairs to this dictionary. The key which gets added is of type str and the value of type int. In another method useKeys in the same class I wanna access the key which I added to the dictionary. With the keys() method I only get the key like dict_keys([<__main__.Demo object at 0x7f7cd00c75b0>]). How can I make the str who was added visible?
Code
class Demo:
def __init__(self, someString):
self.something = dict()
def addSomething(self, something):
if something not in self.something:
self.something[something] = 0
self.something[something] += 1
def useKeys(self):
#prints dict_keys([<__main__.Demo object at 0x7f7cd00c75b0>])
print(self.something.keys())
something1 = Demo("ABC")
something2 = Demo("DEF")
something1.addSomething(something2)
print(something1.useKeys())
Edit
One suggestion in the comments is to use __str__. I understand that this method gets called always if an object from this class gets printed. But how can I make the key from the dictionary readable? My current implementation does not make the key readable:
def __str__(self):
return "{self.something}".format(self=self)
With the method addSomething inside the class I add key value pairs to this dictionary. The key which gets added is of type str and the value of type int.
No, it is not. The key which gets added is of type Demo and the value is of type int. This is why printing the dictionary keys is printing the __repr__ of a Demo object.
How can I make the str who was added visible?
You did not add any str. The strings passed as arguments in your code are never used.
You can either write the __repr__ function (which will override the object object function of the same name, from which every python3 class inherits), or you can use the argument someString you're already providing and that it's not being used at all, it's only forcing you to provide a string when creating a new instance of a Demo object:
Solution 1
Actually using the attribute someString from the constructor in the addSomething function.
With this solution, the key is indeed of the type str.
class Demo:
def __init__(self, someString):
self.something = dict()
self.someString = someString # Actually using the string provided at instance time
def addSomething(self, something):
## This method will use the attribute someString from object something instead
if something.someString not in self.something:
self.something[something.someString] = 0
self.something[something.someString] += 1
def useKeys(self):
## keys are now strings
print(self.something.keys())
something1 = Demo("ABC")
something2 = Demo("DEF")
something1.addSomething(something2)
print(something1.useKeys())
Solution 2
Overriding __repr__, but you require a string anyway so using someString from the constructor too.
With this solution, the key is of type Demo, but when you print that key, it'll display a string.
class Demo:
def __init__(self, someString):
self.something = dict()
self.someString = someString # Actually using the string provided at instance time
def addSomething(self, something):
## This method will use the something object as in the original code
if something not in self.something:
self.something[something] = 0
self.something[something] += 1
def __repr__(self):
## When something1.__repr__ is called, it'll display the someString provided at instance time
return self.someString
def useKeys(self):
## keys are objects, but will appear as strings because of the __repr__ method from that object
print(self.something.keys())
something1 = Demo("ABC")
something2 = Demo("DEF")
something1.addSomething(something2)
print(something1.useKeys())
The __str__ function of an object is used in another circumstance, it's not needed in your requirement.
You can just convert it into a list for easy representation:
print(list(something1.useKeys()))
By the way, it does seem like the class you're implementing already exists as collections.Counter.

Pythonic Enumerated list with attribute lookup, and list of values

A common idiom I have is something like this: (the iterator doesnt work btw):
SUMMARY = 'summary'
REPORT = 'report'
class PDF_TYPES:
summary = SUMMARY
report = REPORT
class __metaclass__(type):
def __iter__(self):
return iter(list(self.summary, self.report))
Firstly thats a lot of boilerplate for 2 values.
I would like to define some constants in a list and be able to:
Refer to them individiually, e.g. REPORT as above
Import the whole list from another module, and refer to them as PDF_TYPES.report etc. A dictionary would be import PDF_TYPES, REPORT; PDF_TYPES[REPORT], i.e. 2 imports to access one value is not nice.
As a list, e.g. if x not in PDF_TYPES: raise ValueError(....).
I looked at dataclasses but they seem to be for instances of things, these are constants. A dictionary would be perfect except for the clunkiness in scneario 2, it doesnt have the attribute look up. What is the most pythonic way of achieving above 3 requirements?
Seems like an enum is what you're describing
from enum import Enum
class PDF_TYPES(Enum):
summary = 'summary'
report = 'report'
then for example
>>> PDF_TYPES.summary
<PDF_TYPES.summary: 'summary'>
>>> for pdf_type in PDF_TYPES:
print(pdf_type)
PDF_TYPES.summary
PDF_TYPES.report
Every enum entry has a .name and .value so if you want to check for containment you could use any
>>> any('report' == pdf_type.value for pdf_type in PDF_TYPES)
True
>>> any('foobar' == pdf_type.value for pdf_type in PDF_TYPES)
False

What is the proper way to bundle variables in python

I have three variables that are closely tied together and I do not want to pass separately every time I call a function. What is the proper way to bundle them.
Context: The purpose of the variables is to keep track of some properties of a document while I am reading it word by word.
My current approach is to bundle them in a class:
class MarkdownIsOpen(object):
def __init__(self):
self.ChapterOpen = False
self.SectionOpen = False
self.ArticleOpen = False
But this seems a bit wrong to me, as I do not intend to add any methods or other functionalities.
A namedtuple would be perfect if it were mutable.
What would be the proper (most pythonic) way to bundle the three variables?
Use a dataclass:
#dataclass
class MarkdownIsOpen:
ChapterOpen: bool = False
SectionOpen: bool = False
ArticleOpen: bool = False
Or:
MarkdownIsOpen = make_dataclass('MarkdownIsOpen', ['ChapterOpen', 'SectionOpen', 'ArticleOpen'])
Note that this requires Python 3.7.
If you're using Python <= 3.6, then an ordinary class will do as well. Classes are not expensive, and they provide a hint to the user that your function does not expect any old dict-like, but a special container with the following attributes.
Compare this to, for example, C's struct or Scala's case class, which serve largely the same purpose.
Also, you can even override __slots__ and/or __getitem__ to allow dict-like access, and prevent the addition of new attributes:
class MarkdownIsOpen:
__slots__ = ('ChapterOpen', 'SectionOpen', 'ArticleOpen')
def __init__(self):
self.ChapterOpen = False
self.SectionOpen = False
self.ArticleOpen = False
def __getattr__(self, key):
return getattr(self, key)
def __setattr__(self, key, value):
setattr(self, key, value)
Example:
m = MarkdownIsOpen()
m['ChapterOpen'] = True
print(m['SectionOpen'])
m['Nonexistent'] = False
Output:
False
AttributeError: 'MarkdownIsOpen' object has no attribute 'Nonexistent'
You can use dataclasses.
#dataclass
class MarkdownIsOpen:
ChapterOpen: bool = False
SectionOpen: bool = False
ArticleOpen: bool = False
May take a look at this question: Existence of mutable named tuple in Python?
With two nice answers: recordclass
and namedlist of mutable alternatives to named tuples
You could use a simple named tuple or a simple dictionary for that purpose, if you really never need to define any methods on the class.

Is an instance of object (but not a subclass) guaranteed to compare unequal to any other object?

Apologies if this is a dupe. (I couldn't find it but I'm not very good with google.)
I just stumbled over some code where they use
x = object()
in a place where they probably want x to compare not equal to anyhing that's already there. Is that guaranteed by the language?
If you compare it by using x == other_object, then this might return True. Since a custom class can override the __eq__ function, and make it for instance equal to every other object.
But we can use is to check whether the two operands refer to the same object. So we can for instance use it like:
dummy = object()
lookup = somedict.get(somekey, dummy):
if lookup is dummy:
# we did *not* find the key in the dictionary
pass
else:
pass
Since we just created the dummy object, there is no way that object can be in the somedict (unless it is of course something like locals()), so as a result we know for sure that if we find the key in the dictionary, then it will not return dummy. So we can use is safely to determine that.
Nothing is guaranteed. You can make anything equals to anything else by implementing __eq__.
Unless you know what x is, nothing is guaranteed and nothing can be assumed.
For example:
class A:
def __eq__(self, other):
return True
print(A() == object())
# True
And the contrary:
class A:
def __eq__(self, other):
return False
print(A() == object())
# False

Can I overload the {} operators for creating dictionaries?

I am making a derived variant of the dict class such that a dictionary value can be accessed through attribute access syntax (so instead of doing dictionary['foo'] you could do dictionary.foo.) This is what I have so far:
class dict(dict):
__getattr__ = dict.__getitem__
However, this snippet of my code gives it problems:
eventD = {'rrule_end':None}
. . .
. . .
#(some time later)
print event.rrule_end
This is because the { } operators for dictionary creation have not been overloaded. Is it possible to make the dictName = { } syntax create an instance of my derived class instead of an ordinary dictionary?
No. You cannot override dict literal syntax. (You also can't override list literal syntax, or string literal syntax, or number literal syntax, or any literal syntax.)
You have to create the instance of your class explicitly. Give your class a name like MyDict and then do
eventD = MyDict({'rrule_end':None})
no, you can't overload that syntax, but their are alternative things you can do.
convert a normal dictionary into your dictionary
my_dict( {'foo':bar, 'foo2':bar2} )
make your function accept key-args
my_dict( foo='bar', foo2='bar2' )
make up your own syntax for this dictionary.
this is abusing python's overloadable operators and is a little complex to do.
its a chain reaction, starting with my_dict<'foo'.
overload the operator so it outputs another my_dict object and repeat the process,
each time keeping a record of each value until if finally reaches the end object.
then it calculates and spits out you own object object.
my_dict<'foo'|bar,'foo2'|'bar2'>end
EDIT:
I'm not sure the reason you want to do this, but this could be an alternative answer to your problem. you may also want to have a look at the vars built in function. this lets you get a dictionary of every attribute an object has. if the object changes, the dictionary changes automatically.
class dict_obj(object):
def __init__(self, obj):
self.obj = obj
self.dict = vars(obj)
def __getattr__(self, value):
return self.dict[value]
__getitem__ = __getattr__
you can use it like this
>>> class test:
def __init__(self):
self.value = 5
>>> obj = dict_obj(test())
>>> obj.value
5
>>> obj['value']
5

Categories