What is the proper way to bundle variables in python - 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.

Related

Is it safe to compare enum objects?

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:

Can Keys of Dictionary be instances of a class?

Lets assume I have a class awhich has the function __eq__(self,other). Now I want to have a dictionary where the keys are instances of the class (and the values numbers, but that should not make a difference). Then I get the error:
unhashable type: 'a'
In the documenation it says that I should define __eq__ and __cmp__ in order to define __hash__, but that is not possible since my class is not comparable!!
How to solve this, folks!
edit: Ok I made it works with only a _eq_ and _hash_ method, but I am still not sure if python uses the hash method in the in operation or the _eq_ method (which should be the case I hope)
The documentation says that beside the __hash__() it needs an __eq__() or (not "and" as you suggest) __cmp__() method.
So in your case it is enough to define the __hash__() method.
A class can be a key for a dict, so long as the hashCode for the class is constant. If at any point in time that the key, hashCode, for the class can change, then you would not be able to use it as a key.
This is precisely why a list cannot be used as a key. An alternative for the list would be to use a tuple since tuples are immutable. Again, if you can guarantee that the hashCode won't change, you're good.
It works for me..
>>> class A:
... def __init__(self):
... self.a = 5
...
>>> a = A()
>>> d = { a:"hello"}
>>> d[a]
'hello'
You can use class instances as keys for a dict
This is not a direct answer, but may be it can help you.
You can override __cmp__ and raise NotImplementedError to avoid usage of it.
class SomeClass():
def __init__(self):
pass # your init here
def __cmp__(self, orher):
raise NotImplementedError('You can not compare this')
def __eq__(self, other):
pass # Your eq here
def __hash__(self):
pass # your hash function here
Demo:
>> s = SomeClass()
>> s == '12'
>> NotImplementedError: You can not compare this

Need help on creating object with class

I need help on creating an object (a sequence of numbers) in respect to some parameters of a class. Lets say I typed in to the Python IDLE shell:
SuperLotto = make_lottery_set_type('SuperLotto', 6, (1,50))
#means user can create a 'SuperLotto' with 6 numbers in range of 1 to 50
It would make 'SuperLotto' as a new class instance of a class called 'LotteryGameType'.
This is using the code so far:
class LotterySetError(Exception):
pass
def make_lottery_set_type(name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
name = LotteryGameType(name, size, minmax[0], minmax[1])
return name
class LotteryGameType:
def __init__(self, name, set_size, min_set_number, max_set_number):
self.name = name
self.set_size = set_size
self.min_set_number = min_set_number
self.max_set_number = max_set_number
I want to be able to create a sequence of numbers and storing it for later use so I can use it with things like overload operators (e.g. eq and ne).
I want to be able to type into the Python IDLE shell:
SuperLotto([3, 4, 19, 23, 46, 27])
This would create an object under the parameters of SuperLotto, if not under parameters of 'SuperLotto' (say more than 6 numbers), it would raise an error. Any approach would be fine. Does anyone have any ideas on how to approach this?
It sounds like what you want is for make_lottery_set_type to return a new class, presumably one that's a subclass of LotteryGameType, rather than returning an instance of that type.
This is actually pretty easy to do in Python. Class definitions are just normal code, that you can run anywhere, even in the middle of a function. And they have access to the local environment while they're running. And classes themselves are "first-class values", meaning you can pass them around and return them from functions. So:
def make_lottery_set_type(name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
def __init__(self, numbers):
super().__init__(name, size, minmax[0], minmax[1])
self.numbers = numbers
return NewLotteryGameType
If you want to add other methods, that's the same as adding methods to any other class. For example:
def make_lottery_set_type(name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
def __init__(self, numbers):
super().__init__(name, size, minmax[0], minmax[1])
self.numbers = numbers
def __eq__(self, rhs):
return set(self.numbers) == set(rhs.numbers)
return NewLotteryGameType
So:
>>> SuperLotto = make_lottery_set_type('SuperLotto', 6, (1,50))
>>> super1 = SuperLotto([1,2,3,4,5,6])
>>> super2 = SuperLotto([6,5,4,3,2,1])
>>> super3 = SuperLotto([7,8,9,10,11,12])
>>> super1 == super2
True
>>> super1 == super3
False
(Obviously you can define __eq__ however you want, if set-equality isn't the right rule for your use.)
If you try to inspect the values you're generating, they don't look quite as pretty as you might like. For example, you'd probably rather see SuperLotto rather than NewLotteryGameType in places like this:
>>> super1
<__main__.NewLotteryGameType at 0x10259e490>
>>> SuperLotto.__name__
'NewLotteryGameType'
For that, just add NewLotteryGameType.__name__ = name. You might also want to copy over the docstring from the parent class, or various other things.
More generally, look at functools.update_wrapper (which is designed for wrapping up functions, not classes, but many of the details are the same) for inspiration, and the inspect module docs from your Python version for all of the attributes that classes can have.
In a comment, you ask:
The only problem is that I want NewLotteryGameType to inherit the parameters such as name, set_size, min_set_number, max_set_number from LotteryGameType. So lets say I wanted to type in NewLotteryGameType.set_size in to the Python Shell. I want it to return back to me 6.
That's contradictory. If you want to inherit the instance attributes of LotteryGameType… well, you already do. For example:
>>> super1.set_size
6
If you want them to be accessible off the class, then they can't be instance attributes, they have to be class attributes. And just changing set_size to a class attribute of LotteryGameType and inheriting it won't work, because the whole point of a class attribute is that the same value shared by all instances of the class or any of its subclasses, and the subclasses all need different values.
But you could do something like this:
class LotteryGameType:
def __init__(self, min_set_number, max_set_number):
self.min_set_number = min_set_number
self.max_set_number = max_set_number
def make_lottery_set_type(lottery_name:str, size:int, minmax:tuple):
if minmax[0] > minmax[1]:
raise LotterySetError('Illegal range for tuple')
else:
class NewLotteryGameType(LotteryGameType):
name = lottery_name
set_size = size
def __init__(self, numbers):
super().__init__(minmax[0], minmax[1])
self.numbers = numbers
def __eq__(self, rhs):
return set(self.numbers) == set(rhs.numbers)
return NewLotteryGameType
(Notice that I had to rename the first make_ parameter to lottery_name so it was different from the class attribute name, because of the way scopes work.) Now, name and set_size are not instance attributes, nor are they class attributes of LotteryGameType—but they're class attributes of each NewLotteryGameType. So:
>>> SuperLotto = make_lottery_set_type('SuperLotto', 6, (1,50))
>>> SuperDuperLotto = make_lottery_set_type('SuperDuperLotto', 8, (1,100))
>>> SuperLotto.set_size
6
>>> SuperDuperLotto.set_size
8
What if you create instances of those types? Well, Python looks for attributes in the instance, then in the most-derived class, and then the base classes. So as long as you don't create instance attributes with the same name (notice that I removed the extra params, and the code that set instance attributes, from the LotteryGameType.__init__ method), it does just what you'd want:
>>> super1 = SuperLotto([1,2,3,4,5,6])
>>> super1.set_size
6
>>> duper1 = SuperDuperLotto([1,2,3,4,5,6,7,8])
>>> duper1.set_size
8
Of course this means that LotteryGameType is no longer a usable type on its own; only its subclasses are usable. But that's probably what you wanted anyway, right? You could even consider making it explicitly an abstract base class to make sure nobody accidentally tries to use a direct LotteryGameType instance.
If you're feeling brave, you might want to read up on metaclasses and see how you could adapt this whole design into use a LotteryGameMetaclass, so each new class is an instance of that metaclass instead of a subclass of the (abstract) base class. The source for the new enum module in 3.4, or the near-equivalent external flufl.enum package, might make good sample code. Then you can play with both and see how similar and how different they are.

are user defined classes mutable

Say I want to create a class for car, tractor and boat. All these classes have an instance of engine and I want to keep track of all the engines in a single list. If I understand correctly if the motor object is mutable i can store it as an attribute of car and also the same instance in a list.
I cant track down any solid info on whether user defined classes are mutable and if there is a choice to choose when you define them, can anybody shed some light?
User classes are considered mutable. Python doesn't have (absolutely) private attributes, so you can always change a class by reaching into the internals.
For using your class as a key in a dict or storing them in a set, you can define a .__hash__() method and a .__eq__() method, making a promise that your class is immutable. You generally design your class API to not mutate the internal state after creation in such cases.
For example, if your engines are uniquely defined by their id, you can use that as the basis of your hash:
class Engine(object):
def __init__(self, id):
self.id = id
def __hash__(self):
return hash(self.id)
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.id == other.id
return NotImplemented
Now you can use instances of class Engine in sets:
>>> eng1 = Engine(1)
>>> eng2 = Engine(2)
>>> eng1 == eng2
False
>>> eng1 == eng1
True
>>> eng1 == Engine(1)
True
>>> engines = set([eng1, eng2])
>>> engines
set([<__main__.Engine object at 0x105ebef10>, <__main__.Engine object at 0x105ebef90>])
>>> engines.add(Engine(1))
>>> engines
set([<__main__.Engine object at 0x105ebef10>, <__main__.Engine object at 0x105ebef90>])
In the above sample I add another Engine(1) instance to the set, but it is recognized as already present and the set didn't change.
Note that as far as lists are concerned, the .__eq__() implementation is the important one; lists don't care if an object is mutable or not, but with the .__eq__() method in place you can test if a given engine is already in a list:
>>> Engine(1) in [eng1, eng2]
True
All objects (with the exception of a few in the standard library, some that implement special access mechanisms using things like descriptors and decorators, or some implemented in C) are mutable. This includes instances of user defined classes, classes themselves, and even the type objects that define the classes. You can even mutate a class object at runtime and have the modifications manifest in instances of the class created before the modification. By and large, things are only immutable by convention in Python if you dig deep enough.
I think you're confusing mutability with how python keeps references -- Consider:
class Foo(object):
pass
t = (1,2,Foo()) # t is a tuple, :. t is immutable
b = a[2] # b is an instance of Foo
b.foo = "Hello" # b is mutable. (I just changed it)
print (hash(b)) # b is hashable -- although the default hash isn't very useful
d = {b : 3} # since b is hashable, it can be used as a key in a dictionary (or set).
c = t # even though t is immutable, we can create multiple references to it.
a = [t] # here we add another reference to t in a list.
Now to your question about getting/storing a list of engines globally -- There are a few different ways to do this, here's one:
class Engine(object):
def __init__(self, make, model):
self.make = make
self.model = model
class EngineFactory(object):
def __init__(self,**kwargs):
self._engines = kwargs
def all_engines(self):
return self._engines.values()
def __call__(self,make, model):
""" Return the same object every for each make,model combination requested """
if (make,model) in _engines:
return self._engines[(make,model)]
else:
a = self._engines[(make,model)] = Engine(make,model)
return a
engine_factory = EngineFactory()
engine1 = engine_factory('cool_engine',1.0)
engine2 = engine_factory('cool_engine',1.0)
engine1 is engine2 #True !!! They're the same engine. Changing engine1 changes engine2
The example above could be improved a little bit by having the EngineFactory._engines dict store weakref.ref objects instead of actually storing real references to the objects. In that case, you'd check to make sure the reference is still alive (hasn't been garbage collected) before you return a new reference to the object.
EDIT: This is conceptually wrong, The immutable object in python can shed some light as to why.
class Engine():
def __init__(self, sn):
self.sn = sn
a = Engine(42)
b = a
print (a is b)
prints True.

Use a Descriptor (EDIT: Not a single decorator) for multiple attributes?

Python 2.5.4. Fairly new to Python, brand new to decorators as of last night. If I have a class with multiple boolean attributes:
class Foo(object):
_bool1 = True
_bool2 = True
_bool3 = True
#et cetera
def __init__():
self._bool1 = True
self._bool2 = False
self._bool3 = True
#et cetera
Is there a way to use a single decorator to check that any setting of any of the boolean attributes must be a boolean, and to return the boolean value for any requested one of these variables?
In other words, as opposed to something like this for each attribute?
def bool1():
def get_boo1():
return self._bool1
def set_bool1(self,value):
if value <> True and value <> False:
print "bool1 not a boolean value. exiting"
exit()
self._bool1=value
return locals()
bool1 = property(**bool1())
#same thing for bool2, bool3, etc...
I have tried to write it as something like this:
def stuff(obj):
def boolx():
def fget(self):
return obj
def fset(self, value):
if value <> True and value <> False:
print "Non-bool value" #name of object???
exit()
obj = value
return locals()
return property(**boolx())
bool1 = stuff(_bool1)
bool2 = stuff(_bool2)
bool3 = stuff(_bool3)
which gives me:
File "C:/PQL/PythonCode_TestCode/Tutorials/Decorators.py", line 28, in stuff
return property(**boolx())
TypeError: 'obj' is an invalid keyword argument for this function
Any pointers on how to do this correctly?
Thanks,
Paul
You can try using a descriptor:
class BooleanDescriptor(object):
def __init__(self, attr):
self.attr = attr
def __get__(self, instance, owner):
return getattr(instance, self.attr)
def __set__(self, instance, value):
if value in (True, False):
return setattr(instance, self.attr, value)
else:
raise TypeError
class Foo(object):
_bar = False
bar = BooleanDescriptor('_bar')
EDIT:
As S.Lott mentioned, python favors Duck Typing over type checking.
Two important things.
First, "class-level" attributes are shared by all instances of the class. Like static in Java. It's not clear from your question if you're really talking about class-level attributes.
Generally, most OO programming is done with instance variables, like this.
class Foo(object):
def __init__():
self._bool1 = True
self._bool2 = False
self._bool3 = True
#et cetera
Second point. We don't waste a lot of time validating the types of arguments.
If a mysterious "someone" provides wrong type data, our class will crash and that's pretty much the best possible outcome.
Fussing around with type and domain validation is a lot of work to make your class crash in a different place. Ultimately, the exception (TypeError) is the same, so the extra checking turns out to have little practical value.
Indeed, extra domain checking can (and often does) backfire when someone creates an alternate implementation of bool and your class rejects this perfectly valid class that has all the same features as built-in bool.
Do not conflate human-input range checking with Python type checking. Human input (or stuff you read from files or URI's) must be range checked, but not not type checked. The piece of the application that does the reading of the external data defines the type. No need to check the type. There won't be any mysteries.
The "what if I use the wrong type and my program appears to work but didn't" scenario doesn't actually make any sense. First, find two types that have the same behavior right down the line but produce slightly different results. The only example is int vs. float, and the only time is really matters is around division, and that's taken care of by the two division operators.
If you "accidentally" use a string where a number was required, your program will die. Reliably. Consistently.

Categories