A group of constants in Python - python-3.x

I want something like this:
class Fruits:
APPLE = 'APPLE'
ORANGE = 'ORANGE'
MANGO = 'MANGO'
# I want to access members easily
print(Fruits.APPLE)
# I want to list all members
print(list(Fruits))
# I want to check if a string belongs to the set
print('POTATO' in Fruits)
I want plain string constants, grouped into a class with:
member check
listing all values
Python enums do not seem to be suitable, because:
Enums are not plain strings, introduce a new type
Enums require using .value
Not directly serializable and are otherwise clumsy.
Is this implementable in Python? I suppose I might need some magic methods or metaclasses for this?

If you want to implement yourself you can do so with a metaclass and an __iter__ method.
class Meta(type):
def __new__(cls, name, bases, dct):
# this just iterates through the class dict and removes
# all the dunder methods
cls.members = [v for k, v in dct.items() if not k.startswith('__') and not callable(v)]
return super().__new__(cls, name, bases, dct)
# giving your class an __iter__ method gives you membership checking
# and the ability to easily convert to another iterable
def __iter__(cls):
yield from cls.members
class Fruits(metaclass=Meta):
APPLE = 'APPLE'
ORANGE = 'ORANGE'
MANGO = 'MANGO'
print(Fruits.APPLE)
print('APPLE' in Fruits)
print(list(Fruits))

You want Python "enums":
In [7]: from enum import Enum
In [8]: class Fruits(Enum):
...: APPLE = 'APPLE'
...: ORANGE = 'ORANGE'
...: MANGO = 'MANGO'
...:
In [9]: print (Fruits.APPLE)
Fruits.APPLE
In [10]: list(Fruits)
Out[10]: [<Fruits.APPLE: 'APPLE'>, <Fruits.ORANGE: 'ORANGE'>, <Fruits.MANGO: 'MANGO'>]
For containment checking, though, you can't use the string directly -
evaluating "APPLE" in Fruits directly would raise a TypeError, but this is possible:
In [18]: "APPLE" in Fruits.__members__
Out[18]: True
# or:
In [15]: Fruits("APPLE")
Out[15]: <Fruits.APPLE: 'APPLE'>
And, as for the part of your questions that goes:
Is this implementable in Python? I suppose I might need some magic
methods or metaclasses for this?
Yes, it is. And yes, it needs both - but it was all done back by Python 3.4

A very basic solution with a meta-class:
class EnumClass(type):
def __iter__(cls):
for key in cls.__dict__:
if not key.startswith('__'):
yield cls.__dict__[key]
def __contains__(cls, item):
return item in cls.__dict__ and not item.startswith('__')
class Fruits(metaclass=EnumClass):
APPLE = 'APPLE'
ORANGE = 'ORANGE'
MANGO = 'MANGO'
# I want to access members easily
print(Fruits.APPLE)
# I want to list all members
print(list(Fruits))
# I want to check if a string belongs to the set
print('POTATO' in Fruits)
print('APPLE' in Fruits)
It's very simplistic and has flaws (e.g., you cannot add methods in Fruits) but it's ok for the use cases you mention.

Related

Best way to model JSON data in python

This question may be opinion based, but I figured I'd give it shot.
I am attempting to create a variety of classes which gets its values from JSON data. The JSON data is not under my control so I have to parse the data and select the values I want. My current implementation subclasses UserDict from python3's collection module. However, I have had iterations where I have directly created attributes and set the values to the parsed data.
The reason I changed to using the UserDict is the ease of using the update function.
However, I feel odd calling the object and using MyClass['attribute'] rather than MyClass.attribute
Is there a more pythonic way to model this data?
I am not 100% convinced that this makes sense, but you could try this:
class MyClass (object):
def __init__(self, **kwargs):
for key in kwargs.keys():
setattr(self, key, kwargs[key])
my_json = {"a":1, "b":2, "c":3}
my_instance = MyClass(**my_json)
print (my_instance.a)
# 1
print (my_instance.b)
# 2
print (my_instance.c)
# 3
--- edit
in case you have nested data you could also try this:
class MyClass (object):
def __init__(self, **kwargs):
for key in kwargs.keys():
if isinstance(kwargs[key],dict):
setattr(self, key, MyClass(**kwargs[key]))
else:
setattr(self, key, kwargs[key])
my_json = {"a":1, "b":2, "c":{"d":3}}
my_instance = MyClass(**my_json)
print (my_instance.a)
# 1
print (my_instance.b)
# 2
print (my_instance.c.d)
# 3

Python 2.7 Is there an equivalent method to locals formatting when adding class attributes into a string?

I have a class that has a number of attributes and within that class I have a function that combines those attributes into a string.
The string is quite long so for visual purposes, I would like to see exactly which variable is inserted where. The ideal solution is to use "This is my %(self.var_name)s" %locals() however the solution only works if I redefine my variable first. For example see the example script:
class Shopping(object):
def __init__(self):
self.n_apples = 4
self.n_pears = 5
self.n_grapefruit =7
def generate_list_from_self(self):
self.shoppingList = """
My Shopping List
apples = %(self.n_apples)s
pears = %(self.n_pears)s
grapefruits = %(self.n_grapefruit)s
""" %locals()
def generate_list_redefine_variables(self):
n_apples = self.n_apples
n_pears = self.n_pears
n_grapefruit = self.n_grapefruit
self.shoppingList = """
My Shopping List
apples = %(n_apples)s
pears = %(n_pears)s
grapefruits = %(n_grapefruit)s
""" %locals()
shopping = Shopping()
# First method
shopping.generate_list_from_self()
# Second method
shopping.generate_list_redefine_variables()
The ideal solution would be to use the generate_from_self() method but the variables are not picked up by %locals(). Instead I am using the second approach and redefining the variables locally before inserting them into the string. This seems cumbersome and I am wondering if there is a better way of achieving this?
It is crucial that I am able to see where the variable is inserted into the string as the string I am working with gets very large.
First the simple approach will be changing the first method to:
def generate_list_from_self(self):
self.shoppingList = """
My Shopping List
apples = %(n_apples)s
pears = %(n_pears)s
grapefruits = %(n_grapefruit)s
""" %vars(self)
here i used the vars method
in general it's common to use __str__(self) for this approach ( converting your class to string) but since there is an init of self.shoppingList i am not sure this is the right approach for you. but i'll reference you anyway to an implementation of this:
class Shopping(object):
def __init__(self):
self.n_apples = 4
self.n_pears = 5
self.n_grapefruit =7
def __str__(self):
self.shoppingList ="""
My Shopping List
apples = %(n_apples)s
pears = %(n_pears)s
grapefruits = %(n_grapefruit)s
""" %vars(self)
return self.shoppingList
shopping = Shopping()
str(shopping) # calls your class's __str__(self) method
and lastly to generailse this class to contain all shopping needed you can use a dict and return (key, value) pairs so you don't have to define a variable for every product.

Class instance representation to something other than a string

I have not been able to find the answer to this question, but maybe I have been asking it incorrectly or dont know the correct keywords. So....
How can I call a custom class instance, and have it return something other than gibberish, and also something other than a string?
For instance, if I create a list mylist = [1,2,3,4,5] and then type 'mylist' into the command line, it returns the list I created
mylist
Out[16]: [1, 2, 3, 4, 5]
The same is true for other aspects of Python, like a dataframe
a = pd.DataFrame()
a
Out[18]:
Empty DataFrame
Columns: []
Index: []
How do I have something like this happen with a custom class? Something like, calling the class instance returns one of its defining attributes, or something similar (other than a string). Is this possible (or a typical practice?) instead of returning
<__main__.MyClass at stuff>
Thanks for the responses!
Use the special methods __str__ and __repr__:
class A:
def __str__(self):
# if __str__ isn't defined, it will default to __repr__
return 'A description for print'
def __repr__(self):
return 'This description will appear in the REPL'
Example:
>>> a = A()
>>> a
This description will appear in the REPL
>>> print(a)
A description for print
>>>

Create instances from list of classes

How do I create instances of classes from a list of classes? I've looked at other SO answers but did understand them.
I have a list of classes:
list_of_classes = [Class1, Class2]
Now I want to create instances of those classes, where the variable name storing the class is the name of the class. I have tried:
for cls in list_of_classes:
str(cls) = cls()
but get the error: "SyntaxError: can't assign to function call". Which is of course obvious, but I don't know what to do else.
I really want to be able to access the class by name later on. Let's say we store all the instance in a dict and that one of the classes are called ClassA, then I would like to be able to access the instance by dict['ClassA'] later on. Is that possible? Is there a better way?
You say that you want "the variable name storing the class [to be] the name of the class", but that's a very bad idea. Variable names are not data. The names are for programmers to use, so there's seldom a good reason to generate them using code.
Instead, you should probably populate a list of instances, or if you are sure that you want to index by class name, use a dictionary mapping names to instances.
I suggest something like:
list_of_instances = [cls() for cls in list_of_classes]
Or this:
class_name_to_instance_mapping = {cls.__name__: cls() for cls in list_of_classes}
One of the rare cases where it can sometimes make sense to automatically generate variables is when you're writing code to create or manipulate class objects themselves (e.g. producing methods automatically). This is somewhat easier and less fraught than creating global variables, since at least the programmatically produced names will be contained within the class namespace rather than polluting the global namespace.
The collections.NamedTuple class factory from the standard library, for example, creates tuple subclasses on demand, with special descriptors as attributes that allow the tuple's values to be accessed by name. Here's a very crude example of how you could do something vaguely similar yourself, using getattr and setattr to manipulate attributes on the fly:
def my_named_tuple(attribute_names):
class Tup:
def __init__(self, *args):
if len(args) != len(attribute_names):
raise ValueError("Wrong number of arguments")
for name, value in zip(attribute_names, args):
setattr(self, name, value) # this programmatically sets attributes by name!
def __iter__(self):
for name in attribute_names:
yield getattr(self, name) # you can look up attributes by name too
def __getitem__(self, index):
name = attribute_names[index]
if isinstance(index, slice):
return tuple(getattr(self, n) for n in name)
return getattr(self, name)
return Tup
It works like this:
>>> T = my_named_tuple(['foo', 'bar'])
>>> i = T(1, 2)
>>> i.foo
1
>>> i.bar
2
If i did understood your question correctly, i think you can do something like this using globals():
class A:
pass
class B:
pass
class C:
pass
def create_new_instances(classes):
for cls in classes:
name = '{}__'.format(cls.__name__)
obj = cls()
obj.__class__.__name__ = name
globals()[name] = obj
if __name__ == '__main__':
classes = [A, B, C]
create_new_instances(classes)
classes_new = [globals()[k] for k in globals() if k.endswith('__') and not k.startswith('__')]
for cls in classes_new:
print(cls.__class__.__name__, repr(cls))
Output (you'll get a similar ouput):
A__ <__main__.A object at 0x7f7fac6905c0>
C__ <__main__.C object at 0x7f7fac6906a0>
B__ <__main__.B object at 0x7f7fac690630>

Dynamically add methods to a class in Python 3.0

I'm trying to write a Database Abstraction Layer in Python which lets you construct SQL statments using chained function calls such as:
results = db.search("book")
.author("J. K. Rowling")
.price("<40.00")
.title("Harry")
.execute()
but I am running into problems when I try to dynamically add the required methods to the db class.
Here is the important parts of my code:
import inspect
def myName():
return inspect.stack()[1][3]
class Search():
def __init__(self, family):
self.family = family
self.options = ['price', 'name', 'author', 'genre']
#self.options is generated based on family, but this is an example
for opt in self.options:
self.__dict__[opt] = self.__Set__
self.conditions = {}
def __Set__(self, value):
self.conditions[myName()] = value
return self
def execute(self):
return self.conditions
However, when I run the example such as:
print(db.search("book").price(">4.00").execute())
outputs:
{'__Set__': 'harry'}
Am I going about this the wrong way? Is there a better way to get the name of the function being called or to somehow make a 'hard copy' of the function?
You can simply add the search functions (methods) after the class is created:
class Search: # The class does not include the search methods, at first
def __init__(self):
self.conditions = {}
def make_set_condition(option): # Factory function that generates a "condition setter" for "option"
def set_cond(self, value):
self.conditions[option] = value
return self
return set_cond
for option in ('price', 'name'): # The class is extended with additional condition setters
setattr(Search, option, make_set_condition(option))
Search().name("Nice name").price('$3').conditions # Example
{'price': '$3', 'name': 'Nice name'}
PS: This class has an __init__() method that does not have the family parameter (the condition setters are dynamically added at runtime, but are added to the class, not to each instance separately). If Search objects with different condition setters need to be created, then the following variation on the above method works (the __init__() method has a family parameter):
import types
class Search: # The class does not include the search methods, at first
def __init__(self, family):
self.conditions = {}
for option in family: # The class is extended with additional condition setters
# The new 'option' attributes must be methods, not regular functions:
setattr(self, option, types.MethodType(make_set_condition(option), self))
def make_set_condition(option): # Factory function that generates a "condition setter" for "option"
def set_cond(self, value):
self.conditions[option] = value
return self
return set_cond
>>> o0 = Search(('price', 'name')) # Example
>>> o0.name("Nice name").price('$3').conditions
{'price': '$3', 'name': 'Nice name'}
>>> dir(o0) # Each Search object has its own condition setters (here: name and price)
['__doc__', '__init__', '__module__', 'conditions', 'name', 'price']
>>> o1 = Search(('director', 'style'))
>>> o1.director("Louis L").conditions # New method name
{'director': 'Louis L'}
>>> dir(o1) # Each Search object has its own condition setters (here: director and style)
['__doc__', '__init__', '__module__', 'conditions', 'director', 'style']
Reference: http://docs.python.org/howto/descriptor.html#functions-and-methods
If you really need search methods that know about the name of the attribute they are stored in, you can simply set it in make_set_condition() with
set_cond.__name__ = option # Sets the function name
(just before the return set_cond). Before doing this, method Search.name has the following name:
>>> Search.price
<function set_cond at 0x107f832f8>
after setting its __name__ attribute, you get a different name:
>>> Search.price
<function price at 0x107f83490>
Setting the method name this way makes possible error messages involving the method easier to understand.
Firstly, you are not adding anything to the class, you are adding it to the instance.
Secondly, you don't need to access dict. The self.__dict__[opt] = self.__Set__ is better done with setattr(self, opt, self.__Set__).
Thirdly, don't use __xxx__ as attribute names. Those are reserved for Python-internal use.
Fourthly, as you noticed, Python is not easily fooled. The internal name of the method you call is still __Set__, even though you access it under a different name. :-) The name is set when you define the method as a part of the def statement.
You probably want to create and set the options methods with a metaclass. You also might want to actually create those methods instead of trying to use one method for all of them. If you really want to use only one __getattr__ is the way, but it can be a bit fiddly, I generally recommend against it. Lambdas or other dynamically generated methods are probably better.
Here is some working code to get you started (not the whole program you were trying to write, but something that shows how the parts can fit together):
class Assign:
def __init__(self, searchobj, key):
self.searchobj = searchobj
self.key = key
def __call__(self, value):
self.searchobj.conditions[self.key] = value
return self.searchobj
class Book():
def __init__(self, family):
self.family = family
self.options = ['price', 'name', 'author', 'genre']
self.conditions = {}
def __getattr__(self, key):
if key in self.options:
return Assign(self, key)
raise RuntimeError('There is no option for: %s' % key)
def execute(self):
# XXX do something with the conditions.
return self.conditions
b = Book('book')
print(b.price(">4.00").author('J. K. Rowling').execute())

Resources