See the update below
I even don't know how to make a short title for my problem.
In a class I have some class attributes of StringField class:
class Authors(Table):
# id field is already present
first_name = StringField(maxLength=100)
last_name = StringField(maxLength=100)
StringField constructor may receive an argument called name. If it's not given, i want it to be equal to class attribute's name (first_name, last_name in the example above).
Is it possible to extract the name of the variable the created instance is going to be assigned to?
I guess i have to use inspect module?
I see Django does this:
Each field type, except for ForeignKey, ManyToManyField and
OneToOneField, takes an optional first positional argument -- a
verbose name. If the verbose name isn't given, Django will
automatically create it using the field's attribute name, converting
underscores to spaces.
In this example, the verbose name is "person's first name":
first_name = models.CharField("person's first name", max_length=30)
In this example, the verbose name is "first name":
first_name = models.CharField(max_length=30)
But i don't find in Django 1.3.1 source code the part which is doing what i need.
UPDATE:
To simplify:
class Field():
def __init__(self, field_name=None):
if not field_name:
field_name = ??? # some magic here to determine the name
print(field_name)
class Table():
first_name = Field()
last_name = Field()
Running this should print first_name and last_name
SOLUTION:
class Field():
def __init__(self, name=None):
self._name = name
class Table():
first_name = Field()
last_name = Field()
for attrName, attr in Table.__dict__.items():
if isinstance(attr, Field):
if attr._name is None:
attr._name = attrName
print(Table.first_name._name)
print(Table.last_name._name)
I don't know how Django does it. But you could do it this way:
class WantFixup(object):
def new_instance(self, name, derived_name):
cls = type(self)
if name is None:
name = derived_name.replace('_', ' ')
return cls(name)
class Container(WantFixup):
def __init__(self, name=None):
self.name = name
def __repr__(self):
return "Container('%s')" % str(self.name)
class WillFixup(object):
def __init__(self):
cls = type(self)
for name in cls.__dict__:
o = cls.__dict__[name] # look up object from name
if not isinstance(o, WantFixup):
continue
print("calling %s.new_instance('%s', '%s')" % (o, o.name, name))
self.__dict__[name] = o.new_instance(o.name, name)
class Name(WillFixup):
first_name = Container("given name")
last_name = Container()
Here is an example of the above code in action:
>>> import auto_name
>>> n = auto_name.Name()
calling Container('None').new_instance('None', 'last_name')
calling Container('given name').new_instance('given name', 'first_name')
>>> print(n.__dict__)
{'first_name': Container('given name'), 'last_name': Container('last name')}
>>> print(auto_name.Name.__dict__)
{'__module__': 'auto_name', 'last_name': Container('None'), 'first_name': Container('given name'), '__doc__': None}
>>>
The class WantFixup serves two purposes. First, all classes that inherit from it can be detected using isinstance(); if our object instance is named o, we can test it like isinstance(o, WantFixup). Second, it provided the .new_instance() method function to any class that inherits from it.
The class Container is an example of a container that might need fixup. Note that it inherits from WantFixup.
The class WillFixup contains a .__init__() method that performs fixup on all classes that inherit from it. This simply loops over everything in the class dictionary, and calls the .new_instance() method function for each one, passing in the name.
Finally, class Name inherits from WillFixup and contains two instances of Container. Because it inherits from WillFixup, the method WillFixup.__init__() is called. As you can see from the example, first_name has a .name attribute set to 'given name' but last_name wasn't set, so it is patched to have its .name attribute set to 'last name'.
The .__init__() function is supposed to set up the new class instance. As long as all the special WantFixup class instances are in the parent class, the .__init__() method will automatically loop over them and set them up.
The confusing part here is that the instance has first_name set to an instance of Container that has the name patched, and will actually be used to store stuff. But the class Name contains an instance of Container that is just used to store the name of the class, and as a marker for the .__init__() method to find.
The good part is that the magic is hidden away in the base classes. The Container and Name classes just need to inherit from them, but are not themselves cluttered with stuff.
There might be a slicker way to solve the problem using metaprogramming.
http://www.ibm.com/developerworks/linux/library/l-pymeta/index.html
This solution isn't metaclass programming, but it is tested, working code.
EDIT: This is a changed version of the code. The original code was intended to show the general idea, but didn't actually init the Name object. It's not hard to actually do the init, so I changed it.
In order for the magic to happen as in the sample, Python would need to be a context-sensitive language (which is isn't, as far as I know, which isn't that far). Django uses the ModelBase meta-class to (among other tasks) set verbose names for the fields. Basically, the metaclass's __new__ loops over the class attributes to get the attribute names, adding them to the options. You can be a little more direct and alter the fields directly. Here's a Python 2 example:
class Field(object):
def __init__(self, name=None):
self.name = name
def __str__(self):
if self.name:
return self.name
return type(self).__name__
def __repr__(self):
return '%s(%s)' % (type(self).__name__, repr(self.name))
class MetaContainer(type):
#classmethod
def dub(metacls, name):
return name.replace('_', ' ').capitalize()
def __new__(cls, name, bases, attrs):
for attr in attrs:
if issubclass(type(attrs[attr]), Field) and attrs[attr].name is None:
attrs[attr].name = MetaContainer.dub(attr)
return super(MetaContainer, cls).__new__(cls, name, bases, attrs)
class Container(object):
__metaclass__ = MetaContainer
first_name = Field()
foo = Field('Foobar')
cntr = Container()
cntr.first_name
Python 3 is almost the same, but you use the metaclass class argument* rather than the __metaclass__ property:
class Container(object, metaclass=MetaContainer):
first_name = Field()
foo = Field('Foobar')
You can write a version that works with metaclasses in in Python 2 and 3 by creating an intermediate base class for the container using the metaclass directly, rather than the metaclass argument or __metaclass__ property:
ContainerBase = MetaContainer('ContainerBase', (object,), {})
class Container(ContainerBase):
first_name = Field()
foo = Field('Foobar')
* For the reason for the change, see PEP 3115: Metaclasses in Python 3000.
Related
from sqlalchemy import create_engine
from sqlalchemy import Sequence
Base = declarative_base()
Column(Integer, Sequence('user_id_seq'), primary_key=True)
engine = create_engine('sqlite:///:memory:', echo=True)
class User(Base):
__tablename__ = 'users'
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
name = Column(String(50))
fullname = Column(String(50))
nickname = Column(String(50))
def __repr__(self):
return "<User(name='%s', fullname='%s', nickname='%s')>" % (
self.name, self.fullname, self.nickname)
class User1(Base):
__tablename__ = 'users1'
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
name = Column(String(50))
fullname = Column(String(50))
nickname = Column(String(50))
def __init__(self, name, fullname, nickname):
self.name = name
self.fullname = fullname
self.nickname = nickname
def __repr__(self):
return "<User(name='%s', fullname='%s', nickname='%s')>" % (
self.name, self.fullname, self.nickname)
ed_user = User(name='ed', fullname='Ed Jones', nickname='edsnickname')
ed_user = User1(name='edd', fullname='Edd Jones', nickname='edsnick')
i picked up this piece of code from the sqlalchemy documentation website, I think everything is okay, but i have a problem understanding the last line, the class user inherits from the base class, buy the user class is not having an init methods in other to accept any argument. can some please explain this to me.. thanks. this two-class achieves the same result they create a table, but in the second instance, the User1 has an init method declared, so obviously the creation of the table happens in the base class, but in the second instance the class and instance variable were declared I want to know how will the base class be able to create the table if it is not receiving any data from the child class.
Python is a very dynamic language. There are several ways to achieve this. One is inheriting from its superclass, as #vrevolverr says. But unfortunately here is not this case. You can confirm that by running print(Base.__init__ is User.__init__), which will give you a False. That means User.__init__ is not inherited from Base.
Another evidence is that print('__init__' in User.__dict__) gives you True, which means that User class has its own __init__ method. And this method can only be given by its metaclass. So the answer comes out. By the way, in your case, this metaclass is DeclarativeMeta in sqlalchemy.ext.declarative.
Just FYI. Simply put, metaclass can do something during the creating process of a class. For example, add a method to this class. This is where your __init__ comes from.
Update:
My original answer also solves your second question. But I still want to add some comments.
First, does User1.__init__ take effect? The answer is NO. Try this simple test:
def init(self, name, fullname, nickname):
self.name = name
self.fullname = fullname
self.nickname = nickname
class User(Base):
...
__init__ = init
print(User.__init__ is init) # False
You can see that the __init__ method defined by you is already replaced.
Then, how to perform this "magic"? See below:
def init1(self):
pass
def init2(self):
pass
class MyMeta(type):
# You can also do this in __new__
def __init__(cls, *args, **kwargs):
cls.__init__ = init2
type.__init__(cls, *args, **kwargs)
class MyClass(metaclass=MyMeta):
__init__ = init1
print(MyClass.__init__ is init1) # False
print(MyClass.__init__ is init2) # True
If the child class (the class which inherits) does not have a class constructor (init method), the child class will call the constructor of the parent class. However, if the child class has a constructor, it will call its own constructor.
Consider the following examples:
Child class without constructor
class ParentClass:
def __init__(self, parent_arg):
self.parent_arg = parent_arg
class ChildClass(ParentClass):
def child_method(self):
print(self.parent_arg)
c = ChildClass(parent_arg="Test")
c.child_method() # Output: Test
Child class with constructor
class ChildClass(ParentClass):
def __init__(self, child_arg):
self.child_arg = child_arg
def child_method(self):
print(self.child_arg) # Output: Child Test
# This will throw an error since this attribute is created by the parent constructor
print(self.parent_arg)
c = ChildClass(child_arg="Child Test")
c.child_method()
To call the parent constructor, pass the arguments for parent class through the constructor of child class and use super() to call the constructor of parent class
def __init__(self, child_arg, parent_arg):
self.child_arg = child_arg
super().__init__(parent_arg)
print(self.parent_arg) # This will then work
if I understand your question well, you want to understand why the User class contains no __init__ method yet it was able to receive arguments, just as #snakecharmerb answered, the User class was able to receive arguments even though it has no init method of it own, this is possible because the class from which User inherited called base have all ready implemented the init method, so you can use the init method from the base class without declaring anyone explicitly. for instance if you inherit a car from your dad, you will be able to use that car even though you don't have a car you bought for yourself.
in the second class User1 the constructor or the init method is used to create a new instance or new row inside the table, every instance of the User1 class you create will be equivalent to a new row in the table
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), unique=True, index=True)
username = db.Column(db.String(20), unique=True, index=True)
hash_passwrd = db.Column(db.String(200))
def __init__(self, email, username, password):
self.email = email
self.username = username
self.hash_passwrd = generate_password_hash(password)
adams = user('adams#email.com', 'adams', 'adams#1')
ben= user('ben#email.com', 'ben', 'ben#1')
poolo= user('poolo#email.com', 'poolo', 'poolo#1')
somewhere in your in your code you will have your database object
db.session.add_all([adams, ben, poolo])
db.session.commit()
now these three class object are now rows inside your table.
when you instaciate a class like this in flask it means you are creating a new row inside your user table, I hope this helps.
Perhaps the below little snippet helps to explain what is going on:
class A:
def __init__(self, a):
self.a = a
class B(A):
def printme(self):
print(self.a)
b = B(10)
b.printme()
result
10
class B inherits class A which has an __init__ method that defines self.a, which is called when the instance B is created which is then used in class B method printme.
so obviously the creation of the table happens in the base class
This is a misconception. The model class defines the structure of a table, and that table is created when Base.metadata.create_all or similar is called. This is independent of the creation of any instances of the class.
Creating an instance of the model class - user = User(...) is the equivalent of creating a row on the table, not the table itself. If an __init__ method assigns values to the class' attributes, these values become the row values. If no __init__ function is defined, the declarative machinery calls a default constructor (or a function passed as declarative_base's constructor argument) to assign the values passed to the Model's constructor.
I have an abstract Django model that I use to create two other models. How can I avoid duplicating code when dealing with the different examples below (for example, when creating a Boxed cereal and a Bowled cereal I would like to avoid duplicating the function twice.
class Cereal(models.Model):
name = models.CharField()
class Meta:
abstract = True
class Boxed(Cereal):
pass
class Bowled(Cereal):
pass
func some_func_boxed(name):
boxed = Boxed.objects.get(id=1)
boxed.name = name
boxed.save()
func some_func_bowled(name):
bowled = Bowled.objects.get(id=1)
bowled.name = name
bowled.save()
def some_func(name, Instance):
i = Instance.objects.get(id=1)
i.name = "some name"
i.save()
The good idea is using strategy pattern, article for example: https://medium.com/#sheikhsajid/design-patterns-in-python-part-1-the-strategy-pattern-54b24897233e
You can add this as a #classmethod on the Cereal model:
class Cereal(models.Model):
name = models.CharField()
#classmethod
def some_func_cereal(cls, name):
bowled = cls.objects.get(id=1)
bowled.name = name
bowled.save()
class Meta:
abstract = True
You can then call this method with:
Boxed.some_func_cereal('Captain Crunch')
Bowled.some_func_cereal('Lucky Charms')
The class with which you call the class method, is passed as the cls parameter in the some_func_cereal function.
You could add an update method to your Cereal absract class such as:
class Cereal:
def update(self, **kwargs):
for key, val in kwargs.items():
setattr(self, key, val)
self.save(update_fields=kwargs.keys())
return self
and use it as follows to update any column you like
BoxedInstance.update(name="new name")
or
BoxedInstance.update(name="new name", taste="cardboardy")
I have no idea how to even look for this, here is a simplified example
I have a class:
class MyField():
def __init__(self, model=None, source=None, id=None):
self.source = source
self.model = model
self.id = id
def somemethod(self):
...
That is used on this other class
class MyClass(db.Model):
id = db.Column(db.Integer, primary_key=True)
somefield = db.Column(db.String(255))
#property
def someproperty(self):
specs = MyField(
source=self.somefield,
model=self.__class__.__name__,
id=self.id
)
return specs.somemethod()
By that is no ideal to me, I want to have something simpler to code for the second class, so making it look like this:
class MyClass(db.Model):
somefield = db.Column(db.String(255))
someproperty = MyField(source='somefield')
and have on the first class all the logic that handles that data. Here I have no idea on how to read the contents of 'somefield' and id, 'somefield' may vary and have another name, thats why I use it as an argument, and 'id' is always the same for every class
All that #property does is return a custom descriptor whose __get__ method calls your function. So, you can just do that directly.
I can't test this, because I don't have sqlalchemy installed here, but something like this:
class FieldProperty(object):
def __init__(self, field, source):
self.field, self.source = field, source
def __get__(self, obj, typ=None):
if typ is None:
typ = obj.__class__
specs = self.field(
source = getattr(obj, self.source),
model = typ.__name__,
id = obj.id)
return specs.somemethod()
Now:
class MyClass(db.Model):
somefield = db.Column(db.String(255))
someproperty = FieldProperty(MyField, source='somefield')
Or, if you prefer, you can create a base class or mixin for all your fields that adds a class method that does this for you:
class BaseField(object):
#classmethod
def make_property(cls, source):
return FieldProperty(cls, source)
And now:
class MyClass(db.Model):
somefield = db.Column(db.String(255))
someproperty = MyField.make_property('somefield')
Note the FieldProperty(object) above. Descriptors have to be new-style classes, and they only work in new-style classes. In Python 3.x, new-style classes is all there is, but if you're using 2.x, every time you define a class with no base class, you get a old-style class. This is just one of the many reasons you don't want an old-style class; they also handle some special methods wrong, break multiple inheritance, make you look like a retro hipster, and sneak into your room and steal money out of your wallet while you sleep.
I'm trying to make a list of objects with different content but when I create the instance, it edits all other instances.
class Example(object):
name = ''
#classmethod
def __init__(cls, name):
cls.name = name
col = []
col.append(Example('text1'))
col.append(Example('text2'))
for item in col:
print item.name
And it prints
'text2'
'text2'
When I expect it to print
'text1'
'text2'
I've also tried with
var = Example('text1')
col.append(var)
And I can't set different variable names because I want it to create instances in a loop.
Don't make __init__ a class method; it a instance initializer:
class Example(object):
name = ''
def __init__(self, name):
self.name = name
By making it a class method, you made it alter the class, not the new instance created.
Without the #classmethod decorator, the class-level name attribute is entirely optional, you can remove it for most uses.
You want this:
class Example(object):
def __init__(self, name):
self.name = name
With SQLAlchemy objects inheriting from the Base class I can pass arguments to a class for variables which aren't defined in a constructor:
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
name = Column(String(50))
fullname = Column(String(50))
password = Column(String(12))
def __repr__(self):
return "<User(name='%s', fullname='%s', password='%s')>" % (
self.name, self.fullname, self.password)
ed_user = User(name='ed', fullname='Ed Jones', password='edspassword')
of course, if I tried passing arguments like that to another class, to set class variables in the same way I'd get an error:
In [1]: class MyClass(object):
...: i = 2
...:
In [2]: instance = MyClass(i=9)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-2-6d3ec8445b00> in <module>()
----> 1 instance = MyClass(i=9)
TypeError: object.__new__() takes no parameters
What sort of trickery is SQLalchemy doing? Why don't they just use a constructor (i.e an __init__ method)?
You actually asked two questions here.
First, you asked "What sort of trickery is SQLAlchemy doing". There is a bit more going on behind the scenes using a concept called Metaclasses to dynamically create the Base class.
But in reality all you need to know is that SQLAlchemy is defining a constructor (albeit in a roundabout way) in the Base class that dynamically sets the elements. Here is actually the implementation of that method (at least as it exists at the time of this answer):
def _declarative_constructor(self, **kwargs):
"""A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and
values in ``kwargs``.
Only keys that are present as
attributes of the instance's class are allowed. These could be,
for example, any mapped columns or relationships.
"""
cls_ = type(self)
for k in kwargs:
if not hasattr(cls_, k):
raise TypeError(
"%r is an invalid keyword argument for %s" %
(k, cls_.__name__))
setattr(self, k, kwargs[k])
Basically, this is dynamically determining the keyword arguments, and setting the attributes on the new object automatically. You can imagine theBase class as looking like the following, although keep in mind it is actually a bit more complex (you can read the code to find out more):
class Base(object):
def __init__(self, **kwargs):
cls_ = type(self)
for k in kwargs:
if not hasattr(cls_, k):
raise TypeError(
"%r is an invalid keyword argument for %s" %
(k, cls_.__name__))
setattr(self, k, kwargs[k])
If you created the above code, any class that you create that inherits from Base would automatically get the ability to have the attributes of the property auto-filled as long as the attribute was already defined on the class. This is because of the typical Python Object-Oriented inheritance structure: if you don't define a method on your User object, Python looks for the method being defined on a base class (in this case the Base method) and will use that instead. This goes for the __init__ method, just like any other method.
Your second question is "Why don't they just use a constructor (i.e an __init__ method)?" Well, as we've described above, they do! They set the _declarative_constructor method to the __init__ attribute the Base class, effectively setting the default logic for object construction. Of course, this only defines the default; you can always override this if you want to...
class User(Base):
__tablename__ = 'users'
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
name = Column(String(50))
fullname = Column(String(50))
password = Column(String(12))
def __init__(self, name):
self.name = name
self.fullname = name
self.password = generate_new_password()
# The following will now work...
ed_user = User('ed')
mark_user = User(name='mark')
# ...but this will not...
problem_user = User(name='Error', fullname='Error M. McErrorson', password='w00t')