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
Related
I want to format an attribute-string of a class with another attribute of the same class like this:
class Test:
def __init__(self):
self.name = None
self.full_name = 'name, {}'.format(self.name)
def print_name(self):
print(self.full_name)
my_object = Test()
my_object.name = 'my_object'
my_object.print_name()
Now it should print 'name, my_object'
But it prints 'name, None'
What to do that the string formats with the assigned value of the object?
You need to add full_name as a property so that you can add some more logic to it:
class Test:
def __init__(self):
self.name = None
#property
def full_name(self):
return f'name, {self.name}'
def print_name(self):
print(self.full_name)
my_object = Test()
my_object.name = 'my_object'
my_object.print_name()
Resources:
property function (built-in)
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.
Is possible access to the parent methods/properties in a class that are inside of the other class?
class ClassA:
a = 'a'
class ClassB():
def method(self):
return self.a
instance = ClassA()
instance2 = instance.ClassB()
instance2.method()
No, nesting a class doesn't automatically produce a relationship between instances. All you did was create an attribute on ClassA that happens to be a class object. Calling that attribute on instances just finds the class attribute and a new instance of ClassB is created without any knowledge of or reference to the ClassA instance.
You'll need to make such relationships explicit by passing in a reference:
class ClassB():
def __init__(self, a):
self.a = a
def method(self):
return self.a
class ClassA:
a = 'a'
def class_b_factory(self):
return ClassB(self)
instance = ClassA()
instance2 = instance.class_b_factory()
instance2.method()
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.