How to print out the foods list? - python-2.7

How can I print out the list of "foods"?
All I can print was something like memory location.
class Fridge:
isOpened = False
foods = []
def open(self):
self.isOpened = True
print "Fridge open"
def put(self, thing):
if self.isOpened:
self.foods.append(thing)
print 'Food in'
else:
print 'Cannot do that'
def close(self):
self.isOpened = False
print 'Fridge closed.'
def __repr__(self):
return "%s" % (self.foods[0])
class Food:
pass

The way you defined repr(), it will only produce the first item in the list foods (as indicated by foods[0]). Furthermore, if the list foods is empty, calling repr() will result in an IndexError.
One way to print the list would be:
def __repr__(self):
return str([food for food in self.foods])
If you are not familiar with the syntax, please check out List Comprehensions.
Here's an example use case of your class:
>>> f = Fridge()
>>> f.open()
Fridge open
>>> f.put("Fruit")
Food in
>>> f.put("Vegetables")
Food in
>>> f.put("Beer")
Food in
>>> print f
['Fruit', 'Vegetables', 'Beer']

Related

Manipulating instances of a class change the whole class

So I'm struggling. I've seen quite a few posts on this topic, but after a couple hours struggling with the problem, I can't figure this out. Here are a few snippets of code I have. I'd like to be able to change one instance of the class without the other being changed as well, and I'm coming up short
class voter:
def __init__(self, iPositon, jPosition, affiliation):
self.affiliation = affiliation
self.iPositon = iPositon
self.jPosition = jPosition
class district:
def __init__(self, *listOfVotersPassed):
# super(district, self).__init__()
self.listOfVoters = []
for x in listOfVotersPassed:
self.listOfVoters.append(x)
class city:
def __init__(self, *listOfDistrictsPassed):
self.listOfDistricts = []
for x in listOfDistrictsPassed:
self.listOfDistricts.append(x)
def main():
# I have a list of class district that I pass to city()
startCity = city(*startCityList)
solutionCity = city(*solutionCityList)
print solutionCity.listOfDistricts[0].listOfVoters[0].affiliation # Democrat
print startCity.listOfDistricts[0].listOfVoters[0].affiliation # Democrat
solutionCity.listOfDistricts[0].listOfVoters[0].affiliation = "Republican"
print solutionCity.listOfDistricts[0].listOfVoters[0].affiliation # Republican
print startCity.listOfDistricts[0].listOfVoters[0].affiliation # Republican
if __name__ == "__main__":
main()
edit.
So I was asked about how I created the instance(s) of city. I have a file I'm reading in, each has either R or D in each line.
file = open(fileName)
# import contents
startVoterList = []
solutionVoterList = []
for line in file:
for house in line:
if " " in house:
pass
elif "\n" in house:
pass
else:
startVoterList.append(house)
solutionVoterList.append(house)
I also updated the classes, now each is in the following format. No changes besides the "(object)" after each class className.
class voter(object):
def __init__(self, iPositon, jPosition, affiliation):
self.affiliation = affiliation
self.iPositon = iPositon
self.jPosition = jPosition

Why doesn't my find function compare the nodes correctly?

I'm working on a concordance dictionary that reads a data file and records every unique word and the word's line number in a AVL tree. The problem is that my find method is not finding the Entry's within the tree so it adds every word instead of every unique word.
I'm also having trouble making my program keep a list of the line numbers within each entry. I'm using an entry class to keep the key(word) and the list of line numbers. Thank you for any help.
I'm writing in Python 2.7 and have included all my program so far.
My Main Program:
import string #NEW
from time import clock
import sys #for BST recursion limit
from dictionary import Entry
sys.setrecursionlimit(3000)#for BST
from avl import AVL
def main():
"""Calls on necessary functions to fill the dictionary, and process the keys"""
start = clock() #times runtime
stopWordDict = AVL()#Empty Dictionary
stopWordDict = fillStopWordDict(stopWordDict)
keyList = []
wordConcordanceDict = AVL()#Empty Dictionary
wordConcordanceDict = fillWordDict(stopWordDict,wordConcordanceDict, keyList)
print str(wordConcordanceDict) #wordconcorddict made here.
keyList.sort()
print keyList
writeWordConDict(wordConcordanceDict, keyList)
end = clock() #gets runtime
runTime = end - start
print("Done. Runtime was:",runTime,"seconds.")
def fillStopWordDict(stopWordDict):
"""fills chain dict with all of the stop words"""
fileNew=open('stop_words.txt', "r")
for word in fileNew:
word=word.lower().strip() #strip will strip \n from word
if stopWordDict.find(word) == None:
stopWordDict.add(word)
fileNew.close()
return stopWordDict
def fillWordDict(stopWordDict,wordConcordanceDict, keyList):
"""opens hw5data.txt and calls on processLine function"""
lineCounter = 1
fileNew=open('hw5data.txt', "r")
for line in fileNew:
processLine(lineCounter, line, stopWordDict,wordConcordanceDict, keyList)
lineCounter+=1 #changes to next line of file
fileNew.close()
return wordConcordanceDict
def processLine(lineCounter, line, stopWordDict,wordConcordanceDict, keyList):
"""process each line into the wordConcordanceDict"""
line=line.split() #splits line into list of words
for word in line:
word=word.lower().strip(string.punctuation)#strips punctuation
if stopWordDict.find(word) == None:
wordEntry = Entry(word, None)
if wordConcordanceDict.find(wordEntry) == None:
lineList = wordEntry.value
lineList.append(lineCounter)
wordEntry.value = lineList
wordConcordanceDict.add(wordEntry)
keyList.append(word)
else:
wordEntry = wordConcordance.find(wordEntry)
lineList = wordEntry.value
lineList.append(lineCounter)
wordEntry.value = lineList
wordConcordanceDict.add(wordEntry)
return wordConcordanceDict
def writeWordConDict(wordConcordanceDict, keyList):
"""takes in wordConcordanceDict and list of its keys. Then prints the key value pairs to the screen"""
fileNew=open("ProgProj5Concordance.txt", 'w')
# listOfWords = wordConcordanceDict.inorder()
for key in keyList:
wordEntry = wordConcordanceDict.find(key) #makes the values into a string
lineList = wordEntry.value
line=str(key + ":" + lineList + "\n")
fileNew.write(line)
fileNew.close()
main()
MY ENTRY CLASS:
"""
File: bst.py
BST class for binary search trees.
"""
from queue import LinkedQueue
from binarytree import BinaryTree
class BST(object):
def __init__(self):
self._tree = BinaryTree.THE_EMPTY_TREE
self._size = 0
def isEmpty(self):
return len(self) == 0
def __len__(self):
return self._size
def __str__(self):
return str(self._tree)
def __iter__(self):
return iter(self.inorder())
def find(self, target):
"""Returns data if target is found or None otherwise."""
def findHelper(tree):
if tree.isEmpty():
return None
elif target == tree.getRoot():
return tree.getRoot()
elif target < tree.getRoot():
return findHelper(tree.getLeft())
else:
return findHelper(tree.getRight())
return findHelper(self._tree)
def add(self, newItem):
"""Adds newItem to the tree."""
# Helper function to search for item's position
def addHelper(tree):
currentItem = tree.getRoot()
left = tree.getLeft()
right = tree.getRight()
# New item is less, go left until spot is found
if newItem < currentItem:
if left.isEmpty():
tree.setLeft(BinaryTree(newItem))
else:
addHelper(left)
# New item is greater or equal,
# go right until spot is found
elif right.isEmpty():
tree.setRight(BinaryTree(newItem))
else:
addHelper(right)
# End of addHelper
# Tree is empty, so new item goes at the root
if self.isEmpty():
self._tree = BinaryTree(newItem)
# Otherwise, search for the item's spot
else:
addHelper(self._tree)
self._size += 1
def inorder(self):
"""Returns a list containing the results of
an inorder traversal."""
lyst = []
self._tree.inorder(lyst)
return lyst
def preorder(self):
"""Returns a list containing the results of
a preorder traversal."""
# Exercise
pass
def postorder(self):
"""Returns a list containing the results of
a postorder traversal."""
# Exercise
pass
def levelorder(self):
"""Returns a list containing the results of
a levelorder traversal."""
# Exercise
pass
def remove(self, item):
# Exercise
pass
def main():
tree = BST()
print "Adding D B A C F E G"
tree.add("D")
tree.add("B")
tree.add("A")
tree.add("C")
tree.add("F")
tree.add("E")
tree.add("G")
print tree.find("A")
print tree.find("Z")
print "\nString:\n" + str(tree)
print "Iterator (inorder traversal): "
iterator = iter(tree)
while True:
try:
print iterator.next(),
except Exception, e:
print e
break
# Use a for loop instead
print "\nfor loop (inorder traversal): "
for item in tree:
print item,
if __name__ == "__main__":
main()
AND FINALLY THE BINARY TREE AVL CLASS:
from binarytree import *
class BinaryTreeAVL(BinaryTree):
def __init__(self, item, balance = 'EQ'):
BinaryTree.__init__(self, item)
self._balance = balance
def getBalance(self):
return self._balance
def setBalance(self, newBalance):
self._balance = newBalance
def __str__(self):
"""Returns a string representation of the tree
rotated 90 degrees to the left."""
def strHelper(tree, level):
result = ""
if not tree.isEmpty():
result += strHelper(tree.getRight(), level + 1)
result += "| " * level
result += str(tree.getRoot())+ " : " + tree.getBalance() + "\n"
result += strHelper(tree.getLeft(), level + 1)
return result
return strHelper(self, 0)

Python cannot iterate a list completely

So I posted this before but I didn't follow the community guidelines so I decided to post it again this time following the community guidelines. (I tried to delete my other question but it wouldn't let me)
Here is the minimal amount of code I could do to create the same problem:
class Object:
def __init__(self, *args, **kwargs):
for k, v in kwargs.iteritems():
setattr(self, k, v)
self.inventory = []
try: self.itemComponent.owner = self
except: self.itemComponent = None
class Item:
def drop(self):
for obj in objects:
if self.owner in obj.inventory:
objects.append(self.owner)
obj.inventory.remove(self.owner)
def monster_death(monster):
monster.name = 'Goblin Corpse'
for element in monster.inventory:
if element.itemComponent:
element.itemComponent.drop()
objects = []
#Create Goblin
monster = Object(name = 'Goblin')
#Populate Goblin's Equipment
monster.inventory = [
Object(name='Dagger', itemComponent=Item() ),
Object(name='Light Healing Potion', itemComponent=Item() ),
Object(name='Scroll of Chain Lightning', itemComponent=Item())
]
objects.append(monster)
print '=~In Monster Inventory~='
for item in monster.inventory:
print item.name
print
print '=~In World~='
for obj in objects:
print obj.name
print
print '***MONSTER DIES***'
print
monster_death(monster)
print '=~In Monster Inventory~='
print
for item in monster.inventory:
print item.name
print
print '=~In World~='
print
for obj in objects:
print obj.name
What happens is one of the items always stays in the monsters inventory...it seems almost random which item stays in but it is always the same item every time unless I remove or add more items to his inventory.
You're removing from the list that you are currently iterating through, that will affect the iteration.
If you need to process each item, then do that in the loop, and then clear the list afterwards
my_list = ['a', 'b', 'c']
my_list[:] = [] # clear the list without replacing it

returning a replaced field in a list of namedtuples in a namedtuple

I have a Restaurant and Dish type namedtuple defined below:
Restaurant = namedtuple('Restaurant', 'name cuisine phone menu')
Dish = namedtuple('Dish', 'name price calories')
r1 = Restaurant('Thai Dishes', 'Thai', '334-4433', [Dish('Mee Krob', 12.50, 500),
Dish('Larb Gai', 11.00, 450)])
I need to change the price of the dish by 2.50. I have the following code:
def Restaurant_raise_prices(rest):
result = []
for item in rest:
for dish in item.menu:
dish = dish._replace(price = dish.price + 2.50)
result.append(item)
return result
It replaces the price field and returns the Dish namedtuple:
[Dish(name='Mee Krob', price=15.0, calories=500), Dish(name='Larb Gai', price=13.5, calories=450)]
How can I change my code to add the restaurant as well?
but it only returns the Dish. What if I wanted the entire Restaurant too? How can I make the change so that the output is:
Restaurant('Thai Dishes', 'Thai', '334-4433', [Dish(name='Mee Krob', price=15.0, calories=500), Dish(name='Larb Gai', price=13.5, calories=450)])
Named tuples are first and foremost tuples, and as such immutable. That means that you cannot modify the existing objects. If you wanted to change them, you would have to create new tuples containing the new values and replace all references to the old tuple with that new tuple.
The code you are using does not work for that, since dish = dish._replace(…) will replace the value of dish with a new tuple, but changing what dish references will not update the reference that exists within the restaurant tuple. Also, with the line result.append(item) being part of the inner loop where you iterate over the dishes, you end up with multiple (unchanged!) copies of the same restaurant tuple in the result.
You could change it like this to make it work (btw. assuming you only pass a single restaurant to the function—so you only need one loop for the dishes):
def restaurant_raise_prices (rest):
dishes = []
for dish in rest.menu:
dishes.append(dish._replace(price=dish.price + 2.50))
rest = rest._replace(menu=dishes)
return rest
This will return a new restaurant with the changed prices for each dish (note that r1 won’t reflect this change):
>>> r1
Restaurant(name='Thai Dishes', cuisine='Thai', phone='334-4433', menu=[Dish(name='Mee Krob', price=12.5, calories=500), Dish(name='Larb Gai', price=11.0, calories=450)])
>>> restaurant_raise_prices(r1)
Restaurant(name='Thai Dishes', cuisine='Thai', phone='334-4433', menu=[Dish(name='Mee Krob', price=15.0, calories=500), Dish(name='Larb Gai', price=13.5, calories=450)])
A cleaner way however would be to introduce proper types that are mutable, so you can make this a bit better. After all, restaurants are objects that can change: They can modify their menu all the time, without becoming a new restaurant. So it makes sense to have the restaurants—as well as the dishes—be mutable objects instead:
class Restaurant:
def __init__ (self, name, cuisine, phone):
self.name = name
self.cuisine = cuisine
self.phone = phone
self.menu = []
def __str__ (self):
return '{} ({}) - {} ({} dishes)'.format(self.name, self.cuisine, self.phone, len(self.menu))
class Dish:
def __init__ (self, name, price, calories):
self.name = name
self.price = price
self.calories = calories
def raise_price (self, amount):
self.price += amount
def __str__ (self):
return '{} (price: {}, calories: {})'.format(self.name, self.price, self.calories)
>>> r1 = Restaurant('Thai Dishes', 'Thai', '334-4433')
>>> r1.menu.append(Dish('Mee Krob', 12.50, 500))
>>> r1.menu.append(Dish('Larb Gai', 11.00, 450))
>>> print(r1)
Thai Dishes (Thai) - 334-4433 (2 dishes)
>>> for dish in r1.menu:
print(dish)
Mee Krob (price: 12.5, calories: 500)
Larb Gai (price: 11.0, calories: 450)
>>> for dish in r1.menu:
dish.raise_price(2.50)
print(dish)
Mee Krob (price: 15.0, calories: 500)
Larb Gai (price: 13.5, calories: 450)

How do I put docstrings on Enums?

Python 3.4 has a new enum module and Enum data type. If you are unable to switch to 3.4 yet, Enum has been backported.
Since Enum members support docstrings, as pretty much all python objects do, I would like to set them. Is there an easy way to do that?
Yes there is, and it's my favorite recipe so far. As a bonus, one does not have to specify the integer value either. Here's an example:
class AddressSegment(AutoEnum):
misc = "not currently tracked"
ordinal = "N S E W NE NW SE SW"
secondary = "apt bldg floor etc"
street = "st ave blvd etc"
You might ask why I don't just have "N S E W NE NW SE SW" be the value of ordinal? Because when I get its repr seeing <AddressSegment.ordinal: 'N S E W NE NW SE SW'> gets a bit clunky, but having that information readily available in the docstring is a good compromise.
Here's the recipe for the Enum:
class AutoEnum(enum.Enum):
"""
Automatically numbers enum members starting from 1.
Includes support for a custom docstring per member.
"""
#
def __new__(cls, *args):
"""Ignores arguments (will be handled in __init__."""
value = len(cls) + 1
obj = object.__new__(cls)
obj._value_ = value
return obj
#
def __init__(self, *args):
"""Can handle 0 or 1 argument; more requires a custom __init__.
0 = auto-number w/o docstring
1 = auto-number w/ docstring
2+ = needs custom __init__
"""
if len(args) == 1 and isinstance(args[0], (str, unicode)):
self.__doc__ = args[0]
elif args:
raise TypeError('%s not dealt with -- need custom __init__' % (args,))
And in use:
>>> list(AddressSegment)
[<AddressSegment.ordinal: 1>, <AddressSegment.secondary: 2>, <AddressSegment.misc: 3>, <AddressSegment.street: 4>]
>>> AddressSegment.secondary
<AddressSegment.secondary: 2>
>>> AddressSegment.secondary.__doc__
'apt bldg floor etc'
The reason I handle the arguments in __init__ instead of in __new__ is to make subclassing AutoEnum easier should I want to extend it further.
Anyone arriving here as a google search:
For many IDE's now in 2022, the following will populate intellisense:
class MyEnum(Enum):
"""
MyEnum purpose and general doc string
"""
VALUE = "Value"
"""
This is the Value selection. Use this for Values
"""
BUILD = "Build"
"""
This is the Build selection. Use this for Buildings
"""
Example in VSCode:
This does not directly answer the question, but I wanted to add a more robust version of #Ethan Furman's AutoEnum class which uses the auto enum function.
The implementation below works with Pydantic and does fuzzy-matching of values to the corresponding enum type.
Usage:
In [2]: class Weekday(AutoEnum): ## Assume AutoEnum class has been defined.
...: Monday = auto()
...: Tuesday = auto()
...: Wednesday = auto()
...: Thursday = auto()
...: Friday = auto()
...: Saturday = auto()
...: Sunday = auto()
...:
In [3]: Weekday('MONDAY') ## Fuzzy matching: case-insensitive
Out[3]: Monday
In [4]: Weekday(' MO NDAY') ## Fuzzy matching: ignores extra spaces
Out[4]: Monday
In [5]: Weekday('_M_onDa y') ## Fuzzy matching: ignores underscores
Out[5]: Monday
In [6]: %timeit Weekday('_M_onDay') ## Fuzzy matching takes ~1 microsecond.
1.15 µs ± 10.9 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
In [7]: %timeit Weekday.from_str('_M_onDay') ## You can further speedup matching using from_str (this is because _missing_ is not called)
736 ns ± 8.89 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
In [8]: list(Weekday) ## Get all the enums
Out[8]: [Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday]
In [9]: Weekday.Monday.matches('Tuesday') ## Check if a string matches a particular enum value
Out[9]: False
In [10]: Weekday.matches_any('__TUESDAY__') ## Check if a string matches any enum
Out[10]: True
In [11]: Weekday.Tuesday is Weekday(' Tuesday') and Weekday.Tuesday == Weekday('_Tuesday_') ## `is` and `==` work as expected
Out[11]: True
In [12]: Weekday.Tuesday == 'Tuesday' ## Strings don't match enum values, because strings aren't enums!
Out[12]: False
In [13]: Weekday.convert_keys({ ## Convert matching dict keys to an enum. Similar: .convert_list, .convert_set
'monday': 'alice',
'tuesday': 'bob',
'not_wednesday': 'charles',
'THURSDAY ': 'denise',
})
Out[13]:
{Monday: 'alice',
Tuesday: 'bob',
'not_wednesday': 'charles',
Thursday: 'denise'}
The code for AutoEnum can be found below.
If you want to change the fuzzy-matching logic, then override the classmethod _normalize (e.g. returning the input unchanged in _normalize, will perform exact matching).
from typing import *
from enum import Enum, auto
class AutoEnum(str, Enum):
"""
Utility class which can be subclassed to create enums using auto().
Also provides utility methods for common enum operations.
"""
#classmethod
def _missing_(cls, enum_value: Any):
## Ref: https://stackoverflow.com/a/60174274/4900327
## This is needed to allow Pydantic to perform case-insensitive conversion to AutoEnum.
return cls.from_str(enum_value=enum_value, raise_error=True)
def _generate_next_value_(name, start, count, last_values):
return name
#property
def str(self) -> str:
return self.__str__()
def __repr__(self):
return self.__str__()
def __str__(self):
return self.name
def __hash__(self):
return hash(self.__class__.__name__ + '.' + self.name)
def __eq__(self, other):
return self is other
def __ne__(self, other):
return self is not other
def matches(self, enum_value: str) -> bool:
return self is self.from_str(enum_value, raise_error=False)
#classmethod
def matches_any(cls, enum_value: str) -> bool:
return cls.from_str(enum_value, raise_error=False) is not None
#classmethod
def does_not_match_any(cls, enum_value: str) -> bool:
return not cls.matches_any(enum_value)
#classmethod
def _initialize_lookup(cls):
if '_value2member_map_normalized_' not in cls.__dict__: ## Caching values for fast retrieval.
cls._value2member_map_normalized_ = {}
for e in list(cls):
normalized_e_name: str = cls._normalize(e.value)
if normalized_e_name in cls._value2member_map_normalized_:
raise ValueError(
f'Cannot register enum "{e.value}"; '
f'another enum with the same normalized name "{normalized_e_name}" already exists.'
)
cls._value2member_map_normalized_[normalized_e_name] = e
#classmethod
def from_str(cls, enum_value: str, raise_error: bool = True) -> Optional:
"""
Performs a case-insensitive lookup of the enum value string among the members of the current AutoEnum subclass.
:param enum_value: enum value string
:param raise_error: whether to raise an error if the string is not found in the enum
:return: an enum value which matches the string
:raises: ValueError if raise_error is True and no enum value matches the string
"""
if isinstance(enum_value, cls):
return enum_value
if enum_value is None and raise_error is False:
return None
if not isinstance(enum_value, str) and raise_error is True:
raise ValueError(f'Input should be a string; found type {type(enum_value)}')
cls._initialize_lookup()
enum_obj: Optional[AutoEnum] = cls._value2member_map_normalized_.get(cls._normalize(enum_value))
if enum_obj is None and raise_error is True:
raise ValueError(f'Could not find enum with value {enum_value}; available values are: {list(cls)}.')
return enum_obj
#classmethod
def _normalize(cls, x: str) -> str:
## Found to be faster than .translate() and re.sub() on Python 3.10.6
return str(x).replace(' ', '').replace('-', '').replace('_', '').lower()
#classmethod
def convert_keys(cls, d: Dict) -> Dict:
"""
Converts string dict keys to the matching members of the current AutoEnum subclass.
Leaves non-string keys untouched.
:param d: dict to transform
:return: dict with matching string keys transformed to enum values
"""
out_dict = {}
for k, v in d.items():
if isinstance(k, str) and cls.from_str(k, raise_error=False) is not None:
out_dict[cls.from_str(k, raise_error=False)] = v
else:
out_dict[k] = v
return out_dict
#classmethod
def convert_keys_to_str(cls, d: Dict) -> Dict:
"""
Converts dict keys of the current AutoEnum subclass to the matching string key.
Leaves other keys untouched.
:param d: dict to transform
:return: dict with matching keys of the current AutoEnum transformed to strings.
"""
out_dict = {}
for k, v in d.items():
if isinstance(k, cls):
out_dict[str(k)] = v
else:
out_dict[k] = v
return out_dict
#classmethod
def convert_values(
cls,
d: Union[Dict, Set, List, Tuple],
raise_error: bool = False
) -> Union[Dict, Set, List, Tuple]:
"""
Converts string values to the matching members of the current AutoEnum subclass.
Leaves non-string values untouched.
:param d: dict, set, list or tuple to transform.
:param raise_error: raise an error if unsupported type.
:return: data structure with matching string values transformed to enum values.
"""
if isinstance(d, dict):
return cls.convert_dict_values(d)
if isinstance(d, list):
return cls.convert_list(d)
if isinstance(d, tuple):
return tuple(cls.convert_list(d))
if isinstance(d, set):
return cls.convert_set(d)
if raise_error:
raise ValueError(f'Unrecognized data structure of type {type(d)}')
return d
#classmethod
def convert_dict_values(cls, d: Dict) -> Dict:
"""
Converts string dict values to the matching members of the current AutoEnum subclass.
Leaves non-string values untouched.
:param d: dict to transform
:return: dict with matching string values transformed to enum values
"""
out_dict = {}
for k, v in d.items():
if isinstance(v, str) and cls.from_str(v, raise_error=False) is not None:
out_dict[k] = cls.from_str(v, raise_error=False)
else:
out_dict[k] = v
return out_dict
#classmethod
def convert_list(cls, l: List) -> List:
"""
Converts string list itmes to the matching members of the current AutoEnum subclass.
Leaves non-string items untouched.
:param l: list to transform
:return: list with matching string items transformed to enum values
"""
out_list = []
for item in l:
if isinstance(item, str) and cls.matches_any(item):
out_list.append(cls.from_str(item))
else:
out_list.append(item)
return out_list
#classmethod
def convert_set(cls, s: Set) -> Set:
"""
Converts string list itmes to the matching members of the current AutoEnum subclass.
Leaves non-string items untouched.
:param s: set to transform
:return: set with matching string items transformed to enum values
"""
out_set = set()
for item in s:
if isinstance(item, str) and cls.matches_any(item):
out_set.add(cls.from_str(item))
else:
out_set.add(item)
return out_set
#classmethod
def convert_values_to_str(cls, d: Dict) -> Dict:
"""
Converts dict values of the current AutoEnum subclass to the matching string value.
Leaves other values untouched.
:param d: dict to transform
:return: dict with matching values of the current AutoEnum transformed to strings.
"""
out_dict = {}
for k, v in d.items():
if isinstance(v, cls):
out_dict[k] = str(v)
else:
out_dict[k] = v
return out_dict
Functions and classes have docstrings, but most objects don't and do not even need them at all. There is no native docstring syntax for instance attributes, as they can be described exhaustively in the classes' docstring, which is also what I recommend you to do. Instances of classes normally also don't have their own docstrings, and enum members are nothing more than that.
Sure enough you could add a docstring to almost anything. Actually you can, indeed, add anything to almost anything, as this is the way python was designed. But it is neither useful nor clean, and even what #Ethan Furman posted seems like way to much overhead just for adding a docstring to a static property.
Long story short, even though you might not like it at first:
Just don't do it and go with your enum's docstring. It is more than enough to explain the meaning of its members.