I don't know how many class instances I will have from the get-go, so I need to create them dynamically, but I would also like to keep the code tidy and readable.
I was thinking of doing something like this:
names = ['Jon','Bob','Mary']
class Person():
def __init__(self, name):
self.name = name
people = {}
for name in names:
people[name] = Person(name)
It works, but I can't seem to find any examples of people doing this online (though I didn't look much). Is there any reason I should avoid doing this? If so, why and what is a better alternative?
If you want to create class instances dynamically, which is exactly what you are doing in your code, then I think your solution looks perfectly fine and is a pythonic way to do so (although I have to say there are of course other ways). Just to give you some food for thought: you could register/store each new instance with the class like that:
class Person():
people={}
#classmethod
def create(cls,name):
person=Person(name)
cls.people[name]=person
return person
def __init__(self, name):
self.name = name
And if you are getting adventerous, you can try the same with metaclass, but I will leave that for your research :-)
Use type(name, bases, dict)
From documentation:
Return a new type object. This is essentially a dynamic form of the
class statement. The name string is the class name and becomes the
name attribute; the bases tuple itemizes the base classes and becomes the bases attribute; and the dict dictionary is the
namespace containing definitions for class body and becomes the
dict attribute. For example, the following two statements create identical type objects:
>>> class X(object):
... a = 1
...
>>> X = type('X', (object,), dict(a=1))
For your example:
>>> JonClass = type('JonClass', (object,), {'name': 'Jon'})
>>> jon_instance = JonClass()
>>> jon_instance.name
'Jon'
>>> type(jon_instance)
<class '__main__.JonClass'>
How about using a generator expression to create the dictionary?
people = dict((name, Person(name)) for name in names)
But besides this your solution is perfectly valid.
Related
I have a class derived from dict which looks like this
class Instance(dict):
def __init__(self, space, vector, value):
dict.__init__(self, space=space, vector=vector, value=value)
I will occasionally be creating dicts matching the 'schema' for this class, and I would like to just construct Instances out of those dicts for typing purposes. What is an elegant way to do this, without changing the existing constructor?
What I want to be able to do is something along the lines of
reconstructed = Instance(json.loads(data))
I don't really know about elegance, but I needed to do that and I just created a function on the class like so:
def as_simple_dict(self):
simple_dict = {}
simple_dict['id'] = str(self.id)
simple_dict['name'] = self.name
simple_dict['attribute'] = self.attribute
simple_dict['foo'] = self.foo
simple_dict['bar'] = self.bar
And call it whenever I need it.
Hope it helps.
I have the following problem and I need advice on how to solve it the best technically in Python. As I am new to programming I would like to have some advice.
So I will have the following object and they should store something. Here is an example:
object 1: cash dividends (they will have the following properties)
exdate (will store a list of dates)
recorddate (will store a list of dates)
paydate (will store a list of dates)
ISIN (will store a list of text)
object 2: stocksplits (they will have the following prpoerties)
stockplitratio (will be some ration)
exdate(list of dates)
...
I have tried to solve it like this:
class cashDividends(object):
def __init__(self, _gross,_net,_ISIN, _paydate, _exdate, _recorddate, _frequency, _type, _announceddate, _currency):
self.gross = _gross
self.net = _net
self.ISIN = _ISIN
self.paydate = _paydate
self.exdate = _exdate
self.recorddate = _recorddate
self.frequency = _frequency
self.type = _type
self.announceddate = _announceddate
self.currency = _currency
So if I have this I would have to create another class named stockplits and then define an __init__ function again.
However is there a way where I can have one class like "Corporate Actions" and then have stock splits and cashdividends in there ?
Sure you can! In python you can pass classes to other classes.
Here a simple example:
class A():
def __init__(self):
self.x = 0
class B():
def __init__(self):
self.x = 1
class Container():
def __init__(self, objects):
self.x = [obj.x for obj in objects]
a = A()
b = B()
c = Container([a,b])
c.x
[0,1]
If I understood correctly what you want is an object that has other objects from a class you created as property?
class CorporateActions(object):
def __init__(self, aCashDividend, aStockSplit):
self.cashDividend = aCashDividend
self.stockSplit = aStockSplit
myCashDividends = CashDividends(...) #corresponding parameters here
myStockSplit = StockSplit(...)
myCorporateActions = CorporateActions(myCashDividends, myStockSplit)
Strictly speaking this answer isn't an answer for the final question. However, it is a way to make your life slightly easier.
Consider creating a sort-of template class (I'm using this term loosely; there's no such thing in Python) that does the __init__ work for you. Like this:
class KwargAttrs():
def __init__(self, **kwargs):
for k,v in kwargs.items():
setattr(self, k, v)
def _update(self, **kwargs):
args_dict = {k:(kwargs[k] if k in kwargs else self.__dict__[k]) for k in self.__dict__}
self.__dict__.update(args_dict)
This class uses every supplied keyword argument as an object attribute. Use it this way:
class CashDividends(KwargAttrs):
def __init__(self, gross, net, ISIN, paydate, exdate, recorddate, frequency, type, announceddate, currency):
# save the namespace before it gets polluted
super().__init__(**locals())
# work that might pollute local namespace goes here
# OPTIONAL: update the argument values in case they were modified:
super()._update(**locals())
Using a method like this, you don't have to go through the argument list and assign every single object attribute; it happens automatically.
We bookend everything you need to accomplish in the __init__ method with method calls to the parent-class via super(). We do this because locals() returns a dict every variable in the function's current namespace, so you need to 1.) capture that namespace before any other work pollutes it and 2.) update the namespace in case any work changes the argument values.
The call to update is optional, but the values of the supplied arguments will not be updated if something is done to them after the call to super().__init__() (that is, unless you change the values using setattr(self, 'argname, value)`, which is not a bad idea).
You can continue using this class like so:
class StockSplits(KwargAttrs):
def __init__(self, stocksplitratio, gross, net, ISIN, paydate, exdate, recorddate, frequency, type, announceddate, currency):
super().__init__(**locals())
As mentioned in the other answers you can create a container for our other classes, but you can even do that using this same template class:
class CorporateActions(KwargAttrs):
def __init__(self, stock_splits , cash_dividends):
super().__init__(**locals())
ca = CorporateActions(stock_splits = StockSplits(<arguments>), cash_dividends = CashDividends(<arguments>) )
I am trying to automatically create some SQL tables from the definition of some Python classes, I tried using dir() but since it returns a Python Dictionary, it's not ordered so the definition order of the class members is lost.
Reading on the internet I found the following here
class OrderedClass(type):
#classmethod
def __prepare__(metacls, name, bases, **kwds):
return collections.OrderedDict()
def __new__(cls, name, bases, namespace, **kwds):
result = type.__new__(cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
class A(metaclass=OrderedClass):
def one(self): pass
def two(self): pass
def three(self): pass
def four(self): pass
>>> A.members
('__module__', 'one', 'two', 'three', 'four')
I successfuly implemented a copy of it, and it appears to be doing what it should except that it's only saving the methods in the members variable, and I need to have also the class member variables.
Question:
How could I get a list of the member variables preserving their definition order?, I don't care about class methods, and I am actually ignoring them.
Note: The reason why the order is important is because the tables will have constraints that reference some of the table columns, and they must go after defining the column, but they are appearing before.
Edit: This is a sample class in my real program
class SQLTable(type):
#classmethod
def __prepare__(metacls, name, bases, **kwds):
return OrderedDict()
def __new__(cls, name, bases, namespace, **kwds):
result = type.__new__(cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
class AreaFisicoAmbiental(metaclass = SQLTable):
def __init__(self, persona, datos):
# edificacion
self.persona = persona
self.tipoEdificacion = datos[0]
self.tipoDeParedes = datos[1]
self.detallesTipoDeParedes = datos[2]
self.tipoDeTecho = datos[3]
self.detallesTipoDeTecho = datos[4]
self.tipoDePiso = datos[5]
self.detallesTipoDePiso = datos[6]
# ambientes
self.problemaDeInfraestructura = datos[7]
self.detallesProblemaDeInfraestructura = datos[9]
self.condicionDeTenencia = datos[10]
self.detallesCondicionDeTenencia = datos[11]
self.sala = toBool(datos[12])
self.comedor = toBool(datos[13])
self.baño = toBool(datos[14])
self.porche = toBool(datos[15])
self.patio = toBool(datos[16])
self.lavandero = toBool(datos[17])
self.habitaciones = toInt(datos[19])
# servicios básicos
self.aguasServidas = toBool(datos[21])
self.aguaPotable = toBool(datos[22])
self.luz = toBool(datos[23])
self.gas = datos[24]
self.internet = toBool(datos[25])
Doing
print(AreaFisicoAmbiental.members)
Outputs:
('__module__', '__qualname__', '__init__')
Variable names are in spanish because their names will be used as the table column names, and also as the labels for a web application that will be generated from the database structure.
I know that Django does something like this, but I already have my database inspector which does the opposite thing, so know I need a Django like functionality to use my generator.
Updated
As I commented, I think you're probably confusing instance attributes with class attributes and really want to keep track of the latter. Instance attributes are dynamic and can be added, changed, or removed at any time, so trying to do this with a metaclass like shown in your question won't work (and different instances may have a different group of them defined).
You may be able to keep track of their creation and deletion by overloading a couple of the class's special methods, namely __setattr__() and __delattr__() and storing their effects in a private data member which is an OrderedSet. Do so will keep track of what they are and preserve the order in which they were created.
Both of these methods will need to be careful not to operate upon the private data member itself.
That said, here's something illustrating such an implementation:
# -*- coding: iso-8859-1 -*-
# from http://code.activestate.com/recipes/576694
from orderedset import OrderedSet
class AreaFisicoAmbiental(object):
def __init__(self, persona, datos):
self._members = OrderedSet()
self.persona = persona
self.tipoEdificacion = datos[0]
self.tipoDeParedes = datos[1]
def __setattr__(self, name, value):
object.__setattr__(self, name, value)
if name != '_members':
self._members.add(name)
def __delattr__(self, name):
if name != '_members':
object.__delattr__(self, name)
self._members.discard(name)
def methodA(self, value1, value2): # add some members
self.attribute1 = value1
self.attribute2 = value2
def methodB(self):
del self.attribute1 # remove a member
if __name__ == '__main__':
a = AreaFisicoAmbiental('Martineau', ['de albañilería', 'vinilo'])
a.methodA('attribute1 will be deleted', 'but this one will be retained')
a.methodB() # deletes a.attribute1
a.attribute3 = 42 # add an attribute outside the class
print('current members of "a":')
for name in a._members:
print(' {}'.format(name))
Output:
current members of "a":
persona
tipoEdificacion
tipoDeParedes
attribute2
attribute3
A final note: It would be possible to create a metaclass that added these two methods automatically to client classes, which would make it easier to modify existing classes.
Maybe, python enum would be enough for the task. Indeed it supports stable order.
The basic implementation of DDL would look like this:
from enum import Enum
class Table1(Enum):
nombre = ''
edad = 0
sexo = True
...
then later you could do:
for prop in Table1:
print(prop)
this gives you
Table1.nombre
Table1.edad
Table1.sexo
if you need to construct a proper table definition you could use Table1.<field>.value:
>>> print(type(Table1.nombre.value))
<class 'str'>
>>> print(type(Table1.edad.value))
<class 'int'>
and so on. Using this technique you could even link some tables to others thus constructing a complete definition of a whole set of tables and their relationships.
As for data objects (e.g. a row in a table, or a row of a query results), here I think you don't any own ordering, you just need to maintain a link to a corresponding table class (from which the order can be restored, however I don't think it's such a requested option). So these classes could look like this:
class Table1Row(object):
_table = Table1
__slots__ = tuple(k.name for k Table1)
...
or simply
class ASpecificQueryResults(object):
__slots__ = (Table1.nombre.name, Table2.empresa.name,...)
probably you need a factory which would build row classes based on the query results and/or table definitions.
Edit probably the idea with __slots__ in *Row classes requires some more polish but this heavily depends on your actual needs.
P.S. Perhaps 'Table1.sexo' also should be an enum in our complicated times ;)
I have an object that holds lots of ids that are accessed statically. I want to split that up into another object which holds only those ids without the need of making modifications to the already existen code base. Take for example:
class _CarType(object):
DIESEL_CAR_ENGINE = 0
GAS_CAR_ENGINE = 1 # lots of these ids
class Car(object):
types = _CarType
I want to be able to access _CarType.DIESEL_CAR_ENGINE either by calling Car.types.DIESEL_CAR_ENGINE, either by Car.DIESEL_CAR_ENGINE for backwards compatibility with the existent code. It's clear that I cannot use __getattr__ so I am trying to find a way of making this work (maybe metaclasses ? )
Although this is not exactly what subclassing is made for, it accomplishes what you describe:
class _CarType(object):
DIESEL_CAR_ENGINE = 0
GAS_CAR_ENGINE = 1 # lots of these ids
class Car(_CarType):
types = _CarType
Something like:
class Car(object):
for attr, value in _CarType.__dict__.items():
it not attr.startswith('_'):
locals()[attr] = value
del attr, value
Or you can do it out of the class declaration:
class Car(object):
# snip
for attr, value in _CarType.__dict__.items():
it not attr.startswith('_'):
setattr(Car, attr, value)
del attr, value
This is how you could do this with a metaclass:
class _CarType(type):
DIESEL_CAR_ENGINE = 0
GAS_CAR_ENGINE = 1 # lots of these ids
def __init__(self,name,bases,dct):
for key in dir(_CarType):
if key.isupper():
setattr(self,key,getattr(_CarType,key))
class Car(object):
__metaclass__=_CarType
print(Car.DIESEL_CAR_ENGINE)
print(Car.GAS_CAR_ENGINE)
Your options fall into two substantial categories: you either copy the attributes from _CarType into Car, or set Car's metaclass to a custom one with a __getattr__ method that delegates to _CarType (so it isn't exactly true that you can't use __getattr__: you can, you just need to put in in Car's metaclass rather than in Car itself;-).
The second choice has implications that you might find peculiar (unless they are specifically desired): the attributes don't show up on dir(Car), and they can't be accessed on an instance of Car, only on Car itself. I.e.:
>>> class MetaGetattr(type):
... def __getattr__(cls, nm):
... return getattr(cls.types, nm)
...
>>> class Car:
... __metaclass__ = MetaGetattr
... types = _CarType
...
>>> Car.GAS_CAR_ENGINE
1
>>> Car().GAS_CAR_ENGINE
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Car' object has no attribute 'GAS_CAR_ENGINE'
You could fix the "not from an instance" issue by also adding a __getattr__ to Car:
>>> class Car:
... __metaclass__ = MetaGetattr
... types = _CarType
... def __getattr__(self, nm):
... return getattr(self.types, nm)
...
to make both kinds of lookup work, as is probably expected:
>>> Car.GAS_CAR_ENGINE
1
>>> Car().GAS_CAR_ENGINE
1
However, defining two, essentially-equal __getattr__s, doesn't seem elegant.
So I suspect that the simpler approach, "copy all attributes", is preferable. In Python 2.6 or better, this is an obvious candidate for a class decorator:
def typesfrom(typesclass):
def decorate(cls):
cls.types = typesclass
for n in dir(typesclass):
if n[0] == '_': continue
v = getattr(typesclass, n)
setattr(cls, n, v)
return cls
return decorate
#typesfrom(_CarType)
class Car(object):
pass
In general, it's worth defining a decorator if you're using it more than once; if you only need to perform this task for one class ever, then expanding the code inline instead (after the class statement) may be better.
If you're stuck with Python 2.5 (or even 2.4), you can still define typesfrom the same way, you just apply it in a slightly less elegant matter, i.e., the Car definition becomes:
class Car(object):
pass
Car = typesfrom(_CarType)(Car)
Do remember decorator syntax (introduced in 2.2 for functions, in 2.6 for classes) is just a handy way to wrap these important and frequently recurring semantics.
class _CarType(object):
DIESEL_CAR_ENGINE = 0
GAS_CAR_ENGINE = 1 # lots of these ids
class Car:
types = _CarType
def __getattr__(self, name):
return getattr(self.types, name)
If an attribute of an object is not found, and it defines that magic method __getattr__, that gets called to try to find it.
Only works on a Car instance, not on the class.
I want to know how to use variables for objects and function names in Python. In PHP, you can do this:
$className = "MyClass";
$newObject = new $className();
How do you do this sort of thing in Python? Or, am I totally not appreciating some fundamental difference with Python, and if so, what is it?
Assuming that some_module has a class named "class_name":
import some_module
klass = getattr(some_module, "class_name")
some_object = klass()
I should note that you should be careful here: turning strings into code can be dangerous if the string came from the user, so you should keep security in mind in this situation. :)
One other method (assuming that we still are using "class_name"):
class_lookup = { 'class_name' : class_name }
some_object = class_lookup['class_name']() #call the object once we've pulled it out of the dict
The latter method is probably the most secure way of doing this, so it's probably what you should use if at all possible.
In Python,
className = MyClass
newObject = className()
The first line makes the variable className refer to the same thing as MyClass. Then the next line calls the MyClass constructor through the className variable.
As a concrete example:
>>> className = list
>>> newObject = className()
>>> newObject
[]
(In Python, list is the constructor for the list class.)
The difference is that in PHP, you represent the name of the class you want to refer to as a string, while in Python you can reference the same class directly. If you must use a string (for example if the name of the class is created dynamically), then you will need to use other techniques.
If you need to create a dynamic class in Python (i.e. one whose name is a variable) you can use type() which takes 3 params:
name, bases, attrs
>>> class_name = 'MyClass'
>>> klass = type(class_name, (object,), {'msg': 'foobarbaz'})
<class '__main__.MyClass'>
>>> inst = klass()
>>> inst.msg
foobarbaz
Note however, that this does not 'instantiate' the object (i.e. does not call constructors etc. It creates a new(!) class with the same name.
If you have this:
class MyClass:
def __init__(self):
print "MyClass"
Then you usually do this:
>>> x = MyClass()
MyClass
But you could also do this, which is what I think you're asking:
>>> a = "MyClass"
>>> y = eval(a)()
MyClass
But, be very careful about where you get the string that you use "eval()" on -- if it's come from the user, you're essentially creating an enormous security hole.
Update: Using type() as shown in coleifer's answer is far superior to this solution.
I use:
newObject = globals()[className]()
I prefer using dictionary to store the class to string mapping.
>>> class AB:
... def __init__(self, tt):
... print(tt, "from class AB")
...
>>> class BC:
... def __init__(self, tt):
... print(tt, "from class BC")
...
>>> x = { "ab": AB, "bc": BC}
>>> x
{'ab': <class '__main__.AB'>, 'bc': <class '__main__.BC'>}
>>>
>>> x['ab']('hello')
hello from class AB
<__main__.AB object at 0x10dd14b20>
>>> x['bc']('hello')
hello from class BC
<__main__.BC object at 0x10eb33dc0>