I had namedtuple variable which represents version of application (its number and type). But i want and some restriction to values:
Version = namedtuple("Version", ["app_type", "number"])
version = Version("desktop") # i want only "desktop" and "web" are valid app types
version = Version("deskpop") # i want to protect from such mistakes
My solution for now is primitive class with no methods:
class Version:
def __init__(self, app_type, number):
assert app_type in ('desktop', 'web')
self.app_type = app_type
self.number = number
Is it pythonic? Is it overkill?
You could use enum.Enum, and typing.NamedTuple instead of collections.namedtuple:
Maybe something like this:
from typing import NamedTuple
import enum
class AppType(enum.Enum):
desktop = 0
web = 1
class Version(NamedTuple):
app: AppType
v0 = Version(app=AppType.desktop)
v1 = Version(app=AppType.web)
print(v0, v1)
output:
Version(app=<AppType.desktop: 0>) Version(app=<AppType.web: 1>)
A undefined AppType raises an AttributeError:
v2 = Version(app=AppType.deskpoop)
output:
AttributeError: deskpoop
Related
There is probably an stupidly obvious solution to this but I'm new to python and can't find it. I'm working out a few of the systems for a practice project I'm working on and I can't seem to get this to work:
class Item:
def __init__(self, name, description, type, mindamage, maxdamage):
self.name = name
self.desc = description
self.type = type
self.mindmg = mindamage
self.maxdmg = maxdamage
woodsman = Item("'Woodsman'", "An automatic chambered in .22lr", "gun", 4, 10)
inspect = input("inspect:").lower()
print(inspect.name)
print(inspect.desc)
print(inspect.type)
I can't find a solution to this for some reason.
Use dataclasses and items dict:
from dataclasses import dataclass
#dataclass
class Item:
name: str
description: str
item_type: str # don't use 'type' for variables name, it's reserved name
min_damage: int
max_damage: int
woodsman = Item(
name="'Woodsman'",
description="An automatic chambered in .22lr",
item_type="gun",
min_damage=4,
max_damage=10
)
# other items...
items = {
"woodsman": woodsman,
# other items...
}
inspect = items.get(input("inspect:").lower())
print(inspect.name)
print(inspect.description)
print(inspect.item_type)
This might be closer to what you're trying to do:
inventory = {
"woodsman": Item("'Woodsman'","An automatic chambered in .22lr","gun",4,10)
}
inspect = inventory[input("inspect:").lower()]
print(inspect.name)
print(inspect.desc)
print(inspect.type)
Note that you will probably want to have some kind of error handling in case the user enters an item that doesn't exist in the inventory.
I was fiddling around and found another solution that works for me:
inspect = input("inspect:").lower()
exec("print(" + inspect + ".name)")
I'm new to logging in python and I would like to save, other than the outcome of a long pipeline in the log file, also the parameters/class attributes of some of the instance created in the pipeline.
Ideally this should not pollute too much the code where the class is implemented.
Even better if the solution takes into account only the instance of the class and writes its attribute in the log file without touching at all the class implementation.
Any suggestion, or god practice advice?
--- Edit:
An unpolished and simplified version initial attempt (as asked in the comment) is the most obvious I could think of, and consist in adding a method that queries the attribute of the class in a string to be returned when the method is called:
In a python package with 2 modules main.py and a_class.py written as follows:
>> cat main.py
import logging
from a_class import MyClass
logging.basicConfig(filename='example.log',level=logging.DEBUG)
logging.warning('Print this to the console and save it to the log')
logging.info('Print this to the console')
o = MyClass()
o.attribute_1 = 1
o.attribute_2 = 3
o.attribute_3 = 'Spam'
logging.info(o.print_attributes())
and
>> cat a_class.py
class MyClass():
def __init__(self):
self.attribute_1 = 0
self.attribute_2 = 0
self.attribute_3 = 0
def print_attributes(self):
msg = '\nclass.attribute_1 {}\n'.format(self.attribute_1)
msg += 'class.attribute_2 {}\n'.format(self.attribute_2)
msg += 'class.attribute_3 {}\n'.format(self.attribute_3)
return msg
The example.log contains what I wanted, which is:
WARNING:root:Print this to the console and save it to the log
INFO:root:Print this to the console
INFO:root:
class.attribute_1 1
class.attribute_2 3
class.attribute_3 Spam
In reformulating the question, is there a way of doing the same query to the attribute of the class and send it to the log without adding any kind of print_attributes method in the class itself?
Use the inbuilt __dict__
class MyClass():
def __init__(self):
self.attribute_1 = 0
self.attribute_2 = 0
self.attribute_3 = 0
o = MyClass()
print o.__dict__
Outputs:
{'attribute_2': 0, 'attribute_3': 0, 'attribute_1': 0}
Use it in logging as you want to.
I'd suggest to implement __str__ or __repr__ for your class so that it would nicely show all the salient attribute values.
Then you can log instances as simple values: log.info("Now foo is %s", foo_instance).
A complete example:
class Donut(object):
def __init__(self, filling, icing):
self.filling = filling
self.icing = icing
def __repr__(self):
return 'Donut(filling=%r, icing=%r)' % (self.filling, self.icing)
donut = Donut('jelly', 'glaze')
import logging
logging.basicConfig()
logging.getLogger().warn('Carbs overload: one %s too much', donut)
Output:
2017-10-25 10:59:05,302 9265 WARNING Carbs overload: one Donut(filling='jelly', icing='glaze') too much
I agree with #Iguananaut that there is no magical way of doing this. However, the following may do the trick. It is better than the print_attributes method you wrote, IMO.
import logging
logging.basicConfig()
logger = logging.getLogger('ddd')
logger.setLevel(logging.DEBUG)
class A(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def __str__(self):
return "\n".join(["{} is {}".format(k, v)
for k, v in self.__dict__.iteritems()])
a = A(1, 2, 3)
logger.debug(a)
The result looks like this -
{12:43}~ ➭ python logging_attrib.py
DEBUG:ddd:a is 1
c is 3
b is 2
Please let me know what you think
I am using the amazing attrs library to define a lot of object attributes in a very elegant way and it has been working like a charm so far.
The only problem that I am currently having is that I sometimes want to define default values by referencing other attr.ib() attributes. Here is some code that would run if the default for name were a static string:
import attr
from attr.validators import instance_of
import datetime
#attr.s
class Something:
some_date = attr.ib(validator=instance_of(datetime.date))
some_number = attr.ib(convert=float)
name = attr.ib(validator=instance_of(str),
default="Generic Name {0} - {1}%".format(
some_date.strftime("%d-%b-%Y"),
some_number * 100)
)
something_instance = Something(some_date=datetime.date.today(), some_number=0.375)
The problem is that name doesn't see a float and a date, but a _CountingAttr object, hence I get an AttributeError (and a TypeError for some_number * 100). Since I can't reference self either, how do I do this?
So this seems not possible with the default keyword at the moment. However, to achieve the same effect, it's possible to use the __attrs_post_init__ method, which can used to execute arbitrary calculations after instance initialization: http://attrs.readthedocs.io/en/stable/examples.html?highlight=attrs_post_init#other-goodies
In my example it would basically come down to adding
def __attrs_post_init__(self):
if self.name is None:
self.name = "Generic Name {0} - {1}%".format(
self.some_date.strftime("%d-%b-%Y"),
self.some_number * 100)
Credit goes to the attrs github issue tracker for pointing me in the right direction.
You can also do it without __attrs_post_init__.
Just use default = attr.Factory(lambda self: ..., takes_self=True)
import attr
from attr.validators import instance_of
import datetime
#attr.s
class Something:
some_date = attr.ib(validator=instance_of(datetime.date))
some_number = attr.ib(convert=float)
name = attr.ib(validator=instance_of(str),
default=attr.Factory(lambda self: "Generic Name {0} - {1}%".format(
self.some_date.strftime("%d-%b-%Y"),
self.some_number * 100)
), takes_self=True)
something_instance = Something(some_date=datetime.date.today(), some_number=0.375)
I will appreciate any effort to clarify the following: is there a way in Python to dynamically create one object per class, where several classes are declared? My silly guess can be described as following:
...
suppose we have some data from db
props = dict_cur.fetchall()
classes_names = []
data = []
for i in props:
classes_names.append(i['client_name'].title())
classes = []
data = []
for i in props:
data.append(dict(i))
for i, d in zip(classes_names, data):
classes.append(type(i, (object,), dict(**d)))
print classes
#printing list of classes
objects = []
for obj in classes:
objects.append(obj())
for obj in objects:
print obj.client_name, obj.client_id
This is very naive approach and it never lets inherit from created classes in a regular way, just like this:
class ClientProcess(Someclient): #Someclient is the name of the created class before
def __init__(self):
print "Someclient stuff"
The goal is pretty simple: create the objects of several classes, preferably with the properties that are stored in the tables, but at the same time have class declaration for every client which will have specific method implemented that will very from class to class. The initial script that works well and uses Python version of Factory method is not sufficient because it only can process one class(client) a time (based on command-line argument which is client id).
If I understand you correctly, you can use the following ways to subclass dynamically created classes:
In : classes = []
In : cls_name = 'BaseCls1'
In : classes.append(type(cls_name, (object, ), {'x': 1}))
In : classes[0].x
Out: 1
In : classes[0].__bases__
Out: (object,)
# two ways to create subclass out of BaseCls1
In : class SubCls1(classes[0]):
: x = 2
:
In : SubCls1.x
Out: 2
In : SubCls1.__bases__
Out: (__main__.BaseCls1,)
In : SubCls2 = type('SubCls2', (classes[0],), {'x': 2})
In : SubCls2.x
Out: 2
In : SubCls2.__bases__
Out: (__main__.BaseCls1,)
class GetConfig(object):
def __init__(self, client_id):
self.client_id = client_id
#construct the query here to get the clients data ...where client_id = self.client_id
d = {'logfile': 'some_long_path', 'contact_name': 'some_name'}
class FirstClient(object):
def __init__(self):
client_id = '111111111'
props = GetConfig(client_id)
#print props.d
def check_source(self):
print "Checking FirstClient source"
return "Something"
#print props.d
def check_downl(self):
print "Checking FirstClient downloaded"
class SecondClient(object):
def __init__(self):
client_id = "222222"
props = GetConfig(client_id)
def check_source(self):
print "Checking SecondClient source"
def check_downl(self):
print "Checking SecondClient downloaded"
myfactory = {
"firstclient" : FirstClient,
"secondclient" : SecondClient,
}
for i in myfactory.values():
i().check_source()
i().check_downl()
collections.namedtuple. done.
Edit: to elaborate,
from collections import namedtuple
rows = dict_cur.fetchall()
# creates the class Row which is a tuple, but each position argument
# corresponds to the column name in that position
# Row can be instantiated as a tuple and then its elements can be accessed
# by name class attributes
Row = namedtuple("Row", zip(*dict_cur.description)[0])
objects = [Row(row) for row in rows]
for o in objects:
print o.client_name, ' is ' , o
I have objects from various classes that work together to perform a certain task. The task requires a lot of parameters, provided by the user (through a configuration file). The parameters are used deep inside the system.
I have a choice of having the controller object read the configuration file, and then allocate the parameters as appropriate to the next layer of objects, and so on in each layer. But the only objects themselves know which parameters they need, so the controller object would need to learn a lot of detail about every other object.
The other choice is to bundle all the parameters into a collection, and pass the whole collection into every function call (equivalently, create a global object that stores them, and is accessible to everyone). This looks and feels ugly, and would cause a variety of minor technical issues (e.g., I can't allow two objects to use parameters with the same name; etc.)
What to do?
I have used the "global collection" alternative in the past.
If you are concerned with naming: how would you handle this in your config file? The way I see it, your global collection is a datastructure representing the same information you have in your config file, so if you have a way of resolving or avoiding name clashes in your cfg-file, you can do the same in your global collection.
I hope you don't feel like I'm thread-jacking you - what you're asking about is similar to what I was thinking about in terms of property aggregation to avoid the models you want to avoid.
I also nicked a bit of the declarative vibe that Elixir has turned me onto.
I'd be curious what the Python gurus of stack overflow think of it and what better alternatives there might be. I don't like big kwargs and if I can avoid big constructors I prefer to.
#!/usr/bin/python
import inspect
from itertools import chain, ifilter
from pprint import pprint
from abc import ABCMeta
class Property(object):
def __init__(self, value=None):
self._x = value
def __repr__(self):
return str(self._x)
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
value = property(getx, setx, delx, "I'm the property.")
class BaseClass(object):
unique_baseclass_thing = Property()
def get_prop_tree(self):
mro = self.__class__.__mro__
r = []
for i in xrange( 0, len(mro) - 1 ):
child_prop_names = set(dir(mro[i]))
parent_prop_names = set(dir(mro[i+1]))
l_k = list( chain( child_prop_names - parent_prop_names ) )
l_n = [ (x, getattr(mro[i],x,None)) for x in l_k ]
l_p = list( ifilter(lambda y: y[1].__class__ == Property, l_n))
r.append(
(mro[i],
(dict
( l_p )
)
)
)
return r
def get_prop_list(self):
return list( chain(* [ x[1].items() for x in reversed( self.get_prop_tree() ) ] ) )
class SubClass(BaseClass):
unique_subclass_thing = Property(1)
class SubSubClass(SubClass):
unique_subsubclass_thing_one = Property("blah")
unique_subsubclass_thing_two = Property("foo")
if __name__ == '__main__':
a = SubSubClass()
for b in a.get_prop_tree():
print '---------------'
print b[0].__name__
for prop in b[1].keys():
print "\t", prop, "=", b[1][prop].value
print
for prop in a.get_prop_list():
When you run it..
SubSubClass
unique_subsubclass_thing_one = blah
unique_subsubclass_thing_two = foo
---------------
SubClass
unique_subclass_thing = 1
---------------
BaseClass
unique_baseclass_thing = None
unique_baseclass_thing None
unique_subclass_thing 1
unique_subsubclass_thing_one blah
unique_subsubclass_thing_two foo