Inserting additional items into an inherited list in Django/Python - python

I'm using some subclasses in my Django app, and I'm continuing that logic through to my admin implementation.
Currently, I have this admin defintion:
class StellarObjectAdmin(admin.ModelAdmin):
list_display = ('title','created_at','created_by','updated_at','updated_by)
Now, I have a Planet class, that is a subclass of StellarObject, with an additional field. I want to add this field to the list_display (not replace StellarObject's display entirely).
If I try something like this:
class PlanetAdmin(StellarObjectAdmin):
list_display.insert(1,'size')
I get the following error:
name 'list_display' is not defined
I will admit, I'm very new to python, and inheritance in general, so I'm sure that there is something simple I am missing.
Thank you

You'll need to use:
StellarObjectAdmin.list_display.insert(1, 'size')
Also, you'll need to change list_display from a tuple (which is immutable) to a list. Eg: list_display = [ ... ].
Finally, you'll probably be surprised by what happens: by inserting the item, you're going to be changing the list on StellarObjectAdmin. What you probably want to do is:
list_display = list(StellarObjectAdmin.list_display) # copy the list
list_display.insert(1, 'size')
Which will create a new copy of the list for your PlanetAdmin class.
This happens because of the way Python does inheritance. Basically, Python never injects names into a namespace (eg, some languages inject a magic this "variable" into methods, while Python forces you to explicitly define the equivalent — self — as the first argument of methods), and since a class is just another namespace, nothing (like, eg, values in its super classes) gets injected into it.
When you've got a class, B, which inherits from another class, A, and you try to look up a property on B — B.foo — it first checks to see if foo is in B's namespace, and if it isn't, it goes on to check A's namespace, and so on.
I hope that's clear… If not, I can clarify (or try to find relevant documentation).

David is spot on. Also, as a note, if you want to reference the variable within the class, you'll need to use 'self.'
Example:
Class A:
mylist = [1,2,3]
def display_list(self):
for i in self.mylist:
print i

Related

What is the difference between assign and declare a variable in python? [duplicate]

I want to clarify how variables are declared in Python.
I have seen variable declaration as
class writer:
path = ""
sometimes, there is no explicit declaration but just initialization using __init__:
def __init__(self, name):
self.name = name
I understand the purpose of __init__, but is it advisable to declare variable in any other functions?
How can I create a variable to hold a custom type?
class writer:
path = "" # string value
customObj = ??
Okay, first things first.
There is no such thing as "variable declaration" or "variable initialization" in Python.
There is simply what we call "assignment", but should probably just call "naming".
Assignment means "this name on the left-hand side now refers to the result of evaluating the right-hand side, regardless of what it referred to before (if anything)".
foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication
As such, Python's names (a better term than "variables", arguably) don't have associated types; the values do. You can re-apply the same name to anything regardless of its type, but the thing still has behaviour that's dependent upon its type. The name is simply a way to refer to the value (object). This answers your second question: You don't create variables to hold a custom type. You don't create variables to hold any particular type. You don't "create" variables at all. You give names to objects.
Second point: Python follows a very simple rule when it comes to classes, that is actually much more consistent than what languages like Java, C++ and C# do: everything declared inside the class block is part of the class. So, functions (def) written here are methods, i.e. part of the class object (not stored on a per-instance basis), just like in Java, C++ and C#; but other names here are also part of the class. Again, the names are just names, and they don't have associated types, and functions are objects too in Python. Thus:
class Example:
data = 42
def method(self): pass
Classes are objects too, in Python.
So now we have created an object named Example, which represents the class of all things that are Examples. This object has two user-supplied attributes (In C++, "members"; in C#, "fields or properties or methods"; in Java, "fields or methods"). One of them is named data, and it stores the integer value 42. The other is named method, and it stores a function object. (There are several more attributes that Python adds automatically.)
These attributes still aren't really part of the object, though. Fundamentally, an object is just a bundle of more names (the attribute names), until you get down to things that can't be divided up any more. Thus, values can be shared between different instances of a class, or even between objects of different classes, if you deliberately set that up.
Let's create an instance:
x = Example()
Now we have a separate object named x, which is an instance of Example. The data and method are not actually part of the object, but we can still look them up via x because of some magic that Python does behind the scenes. When we look up method, in particular, we will instead get a "bound method" (when we call it, x gets passed automatically as the self parameter, which cannot happen if we look up Example.method directly).
What happens when we try to use x.data?
When we examine it, it's looked up in the object first. If it's not found in the object, Python looks in the class.
However, when we assign to x.data, Python will create an attribute on the object. It will not replace the class' attribute.
This allows us to do object initialization. Python will automatically call the class' __init__ method on new instances when they are created, if present. In this method, we can simply assign to attributes to set initial values for that attribute on each object:
class Example:
name = "Ignored"
def __init__(self, name):
self.name = name
# rest as before
Now we must specify a name when we create an Example, and each instance has its own name. Python will ignore the class attribute Example.name whenever we look up the .name of an instance, because the instance's attribute will be found first.
One last caveat: modification (mutation) and assignment are different things!
In Python, strings are immutable. They cannot be modified. When you do:
a = 'hi '
b = a
a += 'mom'
You do not change the original 'hi ' string. That is impossible in Python. Instead, you create a new string 'hi mom', and cause a to stop being a name for 'hi ', and start being a name for 'hi mom' instead. We made b a name for 'hi ' as well, and after re-applying the a name, b is still a name for 'hi ', because 'hi ' still exists and has not been changed.
But lists can be changed:
a = [1, 2, 3]
b = a
a += [4]
Now b is [1, 2, 3, 4] as well, because we made b a name for the same thing that a named, and then we changed that thing. We did not create a new list for a to name, because Python simply treats += differently for lists.
This matters for objects because if you had a list as a class attribute, and used an instance to modify the list, then the change would be "seen" in all other instances. This is because (a) the data is actually part of the class object, and not any instance object; (b) because you were modifying the list and not doing a simple assignment, you did not create a new instance attribute hiding the class attribute.
This might be 6 years late, but in Python 3.5 and above, you can give a hint about a variable type like this:
variable_name: type_name
or this:
variable_name # type: shinyType
This hint has no effect in the core Python interpreter, but many tools will use it to aid the programmer in writing correct code.
So in your case(if you have a CustomObject class defined), you can do:
customObj: CustomObject
See this or that for more info.
There's no need to declare new variables in Python. If we're talking about variables in functions or modules, no declaration is needed. Just assign a value to a name where you need it: mymagic = "Magic". Variables in Python can hold values of any type, and you can't restrict that.
Your question specifically asks about classes, objects and instance variables though. The idiomatic way to create instance variables is in the __init__ method and nowhere else — while you could create new instance variables in other methods, or even in unrelated code, it's just a bad idea. It'll make your code hard to reason about or to maintain.
So for example:
class Thing(object):
def __init__(self, magic):
self.magic = magic
Easy. Now instances of this class have a magic attribute:
thingo = Thing("More magic")
# thingo.magic is now "More magic"
Creating variables in the namespace of the class itself leads to different behaviour altogether. It is functionally different, and you should only do it if you have a specific reason to. For example:
class Thing(object):
magic = "Magic"
def __init__(self):
pass
Now try:
thingo = Thing()
Thing.magic = 1
# thingo.magic is now 1
Or:
class Thing(object):
magic = ["More", "magic"]
def __init__(self):
pass
thing1 = Thing()
thing2 = Thing()
thing1.magic.append("here")
# thing1.magic AND thing2.magic is now ["More", "magic", "here"]
This is because the namespace of the class itself is different to the namespace of the objects created from it. I'll leave it to you to research that a bit more.
The take-home message is that idiomatic Python is to (a) initialise object attributes in your __init__ method, and (b) document the behaviour of your class as needed. You don't need to go to the trouble of full-blown Sphinx-level documentation for everything you ever write, but at least some comments about whatever details you or someone else might need to pick it up.
For scoping purpose, I use:
custom_object = None
Variables have scope, so yes it is appropriate to have variables that are specific to your function. You don't always have to be explicit about their definition; usually you can just use them. Only if you want to do something specific to the type of the variable, like append for a list, do you need to define them before you start using them. Typical example of this.
list = []
for i in stuff:
list.append(i)
By the way, this is not really a good way to setup the list. It would be better to say:
list = [i for i in stuff] # list comprehension
...but I digress.
Your other question.
The custom object should be a class itself.
class CustomObject(): # always capitalize the class name...this is not syntax, just style.
pass
customObj = CustomObject()
As of Python 3, you can explicitly declare variables by type.
For instance, to declare an integer one can do it as follows:
x: int = 3
or:
def f(x: int):
return x
see this question for more detailed info about it:
Explicitly declaring a variable type in Python

Can I declare a variable firmly typed as an integer in Python, like I do in Java? [duplicate]

I want to clarify how variables are declared in Python.
I have seen variable declaration as
class writer:
path = ""
sometimes, there is no explicit declaration but just initialization using __init__:
def __init__(self, name):
self.name = name
I understand the purpose of __init__, but is it advisable to declare variable in any other functions?
How can I create a variable to hold a custom type?
class writer:
path = "" # string value
customObj = ??
Okay, first things first.
There is no such thing as "variable declaration" or "variable initialization" in Python.
There is simply what we call "assignment", but should probably just call "naming".
Assignment means "this name on the left-hand side now refers to the result of evaluating the right-hand side, regardless of what it referred to before (if anything)".
foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication
As such, Python's names (a better term than "variables", arguably) don't have associated types; the values do. You can re-apply the same name to anything regardless of its type, but the thing still has behaviour that's dependent upon its type. The name is simply a way to refer to the value (object). This answers your second question: You don't create variables to hold a custom type. You don't create variables to hold any particular type. You don't "create" variables at all. You give names to objects.
Second point: Python follows a very simple rule when it comes to classes, that is actually much more consistent than what languages like Java, C++ and C# do: everything declared inside the class block is part of the class. So, functions (def) written here are methods, i.e. part of the class object (not stored on a per-instance basis), just like in Java, C++ and C#; but other names here are also part of the class. Again, the names are just names, and they don't have associated types, and functions are objects too in Python. Thus:
class Example:
data = 42
def method(self): pass
Classes are objects too, in Python.
So now we have created an object named Example, which represents the class of all things that are Examples. This object has two user-supplied attributes (In C++, "members"; in C#, "fields or properties or methods"; in Java, "fields or methods"). One of them is named data, and it stores the integer value 42. The other is named method, and it stores a function object. (There are several more attributes that Python adds automatically.)
These attributes still aren't really part of the object, though. Fundamentally, an object is just a bundle of more names (the attribute names), until you get down to things that can't be divided up any more. Thus, values can be shared between different instances of a class, or even between objects of different classes, if you deliberately set that up.
Let's create an instance:
x = Example()
Now we have a separate object named x, which is an instance of Example. The data and method are not actually part of the object, but we can still look them up via x because of some magic that Python does behind the scenes. When we look up method, in particular, we will instead get a "bound method" (when we call it, x gets passed automatically as the self parameter, which cannot happen if we look up Example.method directly).
What happens when we try to use x.data?
When we examine it, it's looked up in the object first. If it's not found in the object, Python looks in the class.
However, when we assign to x.data, Python will create an attribute on the object. It will not replace the class' attribute.
This allows us to do object initialization. Python will automatically call the class' __init__ method on new instances when they are created, if present. In this method, we can simply assign to attributes to set initial values for that attribute on each object:
class Example:
name = "Ignored"
def __init__(self, name):
self.name = name
# rest as before
Now we must specify a name when we create an Example, and each instance has its own name. Python will ignore the class attribute Example.name whenever we look up the .name of an instance, because the instance's attribute will be found first.
One last caveat: modification (mutation) and assignment are different things!
In Python, strings are immutable. They cannot be modified. When you do:
a = 'hi '
b = a
a += 'mom'
You do not change the original 'hi ' string. That is impossible in Python. Instead, you create a new string 'hi mom', and cause a to stop being a name for 'hi ', and start being a name for 'hi mom' instead. We made b a name for 'hi ' as well, and after re-applying the a name, b is still a name for 'hi ', because 'hi ' still exists and has not been changed.
But lists can be changed:
a = [1, 2, 3]
b = a
a += [4]
Now b is [1, 2, 3, 4] as well, because we made b a name for the same thing that a named, and then we changed that thing. We did not create a new list for a to name, because Python simply treats += differently for lists.
This matters for objects because if you had a list as a class attribute, and used an instance to modify the list, then the change would be "seen" in all other instances. This is because (a) the data is actually part of the class object, and not any instance object; (b) because you were modifying the list and not doing a simple assignment, you did not create a new instance attribute hiding the class attribute.
This might be 6 years late, but in Python 3.5 and above, you can give a hint about a variable type like this:
variable_name: type_name
or this:
variable_name # type: shinyType
This hint has no effect in the core Python interpreter, but many tools will use it to aid the programmer in writing correct code.
So in your case(if you have a CustomObject class defined), you can do:
customObj: CustomObject
See this or that for more info.
There's no need to declare new variables in Python. If we're talking about variables in functions or modules, no declaration is needed. Just assign a value to a name where you need it: mymagic = "Magic". Variables in Python can hold values of any type, and you can't restrict that.
Your question specifically asks about classes, objects and instance variables though. The idiomatic way to create instance variables is in the __init__ method and nowhere else — while you could create new instance variables in other methods, or even in unrelated code, it's just a bad idea. It'll make your code hard to reason about or to maintain.
So for example:
class Thing(object):
def __init__(self, magic):
self.magic = magic
Easy. Now instances of this class have a magic attribute:
thingo = Thing("More magic")
# thingo.magic is now "More magic"
Creating variables in the namespace of the class itself leads to different behaviour altogether. It is functionally different, and you should only do it if you have a specific reason to. For example:
class Thing(object):
magic = "Magic"
def __init__(self):
pass
Now try:
thingo = Thing()
Thing.magic = 1
# thingo.magic is now 1
Or:
class Thing(object):
magic = ["More", "magic"]
def __init__(self):
pass
thing1 = Thing()
thing2 = Thing()
thing1.magic.append("here")
# thing1.magic AND thing2.magic is now ["More", "magic", "here"]
This is because the namespace of the class itself is different to the namespace of the objects created from it. I'll leave it to you to research that a bit more.
The take-home message is that idiomatic Python is to (a) initialise object attributes in your __init__ method, and (b) document the behaviour of your class as needed. You don't need to go to the trouble of full-blown Sphinx-level documentation for everything you ever write, but at least some comments about whatever details you or someone else might need to pick it up.
For scoping purpose, I use:
custom_object = None
Variables have scope, so yes it is appropriate to have variables that are specific to your function. You don't always have to be explicit about their definition; usually you can just use them. Only if you want to do something specific to the type of the variable, like append for a list, do you need to define them before you start using them. Typical example of this.
list = []
for i in stuff:
list.append(i)
By the way, this is not really a good way to setup the list. It would be better to say:
list = [i for i in stuff] # list comprehension
...but I digress.
Your other question.
The custom object should be a class itself.
class CustomObject(): # always capitalize the class name...this is not syntax, just style.
pass
customObj = CustomObject()
As of Python 3, you can explicitly declare variables by type.
For instance, to declare an integer one can do it as follows:
x: int = 3
or:
def f(x: int):
return x
see this question for more detailed info about it:
Explicitly declaring a variable type in Python

Access local classvariable from inherited instance

I have my pseudo Interface, which I implement several times. Each implementation is supposed to store a variable that basically defines a path to a file (a template). Because these classes are produced by a factory, I don't know which subclass is going to come up, therefore, I want to make it possible to access a class variable via an instance method.
This does not really pose a problem, however, when I inherit from my Interface, I don't want to implement the getHidden() method (in the following) several times. But calling it, the way it is written down there, will always yield hidden.
class MySuperInterface(object):
# class Variable
__much = "hidden"
# instance method
def getHidden(self):
print self.__class__.__much
class MySub(MySuperInterface):
__much = "this is different per subclass!"
def soTroublesome(self):
print self.__class__.__much
Execution
>>> sub = MySub() # I don't know this class!
>>> sub.getHidden()
hidden
>>> sub.soTroublesome()
this is different per subclass!
So, how can I implement getHidden() to access the instance's class' classvariable. I know, that the information is available, as I checked with dir(), but I have no idea how to access it.
Again, I don't want to end up with a class/static method, because I don't know the class that gets out of my factory!
Thanks!
Just don't use the "__" in the class variable name and you are set.
Some Python write ups and "documentation" say that the "__" prefix is the Python way to get
"private" members in a class. They are wrong.
The "__" prefix does exactly what is happening to you: ensure that the variable accessed in a method inside a class access the variable defined in that exact class (and not any of the classes that inherit from it).
The way it works is simple: at compile time, the names prefixed with "__" are "mangled", i.e. changed like this: __much -> _classname__much:
>>> class Hidden(object):
... __hidden = False
...
>>> dir(Hidden)
['_Hidden__hidden', '__class__', ...]
Therefore your getHidden method will always look for the __much variable thathas had its name actually changed to _MySuperInterface__much, while the variable you want has had its name changed to _MySub__much.
If you as much as use a single underscore "_" to mean by convention the variable should not be used outside of the class, your code would work as you expect.
You should definitely learn and try how python member access works. Use interactive Python shell (python in the command line), import your modules and experiment.
print self.__class__.__much
You don't typically need to access class members via __class__ when reading. Access them as normal members instead:
print self.__much
Python supports private members by name mangling, changing __much member of MySuperInterface class to _MySuperInterface__much. This is to avoid accessing the private member from child classes which is exactly what you are trying to do.
When you, for any reason, need to access it, you can simply use the mangled name:
print self._MySuperInterface__much
print self._MySub__much
You should typically avoid it and rethink your code instead. The easiest way to do that is to use a single underscore that still denotes internal implementation member but doesn't trigger the name mangling.

Difference between Class Members and Instance Members in Django and "Ordinary" Python?

Beginner question here! Some time ago, I asked this question:
Parse CSV records into a list of Classes, which was also answered more technically here: How do I avoid having class data shared among instances?
I learned that, in Python classes, variables that will be defined on a per-object basis need to be declared in the __init__(self) function.
So for:
class ClassOne:
def __init__(self, datetime):
self.datetime = datetime
v = []
the variable v will hold the same data for all instances of ClassOne, whereas for:
class ClassTwo:
def __init__(self, datetime):
self.datetime = datetime
self.v = []
variable v holds individual data for each instance of ClassTwo.
However, in Django (which I'm learning now), I see the "normal" (more C++ like) behavior again for the variables:
class Post(models.Model):
title = models.CharField(max_length = 255)
Here, the variable title holds individual data for each instance of Post, despite not being defined in the __init__ function.
My basic question is Why or How does title pertain to individual class objects instead of being common to every class object, as v in ClassOne is above?
If I'm understanding this right, this means that Django classes are interpreted differently than normal Python classes? However, that conclusion doesn't make sense...
I hope that someone can help me understand this. It was my assumption previously that python code (say, a data analysis or a scientific model) could be built into a web-based service by using it's classes and routines in a Django app. If the implementation of the two different classes is different, then this would be quite difficult!
This may have been answered elsewhere. I'm not well versed in Django jango, so don't know what to search for.
The title attribute is not data. It holds a model description only; an object describing what type of information the title field should hold.
As such it is part of the class definition; individual instances of the Post class will have a title attribute that conforms to the constraints set in the models.CharField() instance on the class.
You need to build such a model to describe to Django how to build form fields and how to build a SQL table for the Post instances; both are concepts that need to have more type information than what Python normally itself needs.
Individual instances of Post are given a title attribute as well. That attribute then masks the class attribute:
p = Post(title='Some title')
print p.title # prints 'Some title'
Python looks at the instance directly first; if it does not have a title attribute, lookup would then move to the class object. But that's not needed here, the Post.title attribute is not found as the instance has a title attribute itself.
In Python itself, there is no absolute distinction between 'data' and methods, by the way. Everything in Python is an object, including classes and methods. As such, looking up an attribute on an instance can find an object there too, including methods. If an attribute lookup there fails, then Python will look for the attribute on the class and base classes, and if that fails, lookup falls back to the metaclass even.
This is where mutable attributes come in; looking up ClassOne().v fails on the instance, but succeeds on the class. Manipulating that list then alters ClassOne.v the class attribute, and looking up v on other instances once again will find the class attribute. This is how class attributes are shared, just like the methods on the class.
Django does not change the rules of the language. It does however use the language creatively. Just like class ClassTwo(...): v = [] creates one list and stores it in the class, class Post(...): title = something creates one something and stores it in the class. In this case, said something is not a char field value like "foo", it's an object which represents the concept of a char field with a max_length of 255.
Django gathers these objects representing database types, and creates (among many other things) an __init__ method that gives Post instances an attribute of the same name (which does contain an actual string value). The implementation of this is quite advanced, but firmly within the rules of the Python language - you and I can create our own Python libraries doing something similar. Anyway, since instance attributes shadow class attributes, you never notice that Post.title exists only once and isn't actually a title string. a_post_object.title always gives you the instance attribute.
As a slightly more general explanation of the relationship between class and instance variables, consider the following example that is unrelated to django models:
>>> class A(object):
... x = 2
... y = 1
...
... def __init__(self):
... self.x = 3
...
>>> A.x
2
>>> instance = A()
>>> instance.x
3
>>> instance.y
1
>>> instance.y = 4
>>> instance.y
4
>>> A.y
1
There are 2 things that I think are worth noting here. Firstly, a separate class and instance variable of the same name can exist. The class variable is only accessible directly from an instance if there is no instance variable of the same name. This is how the django models work, the class variables are fields (which are descriptions of the instance variables), the instance variables are the values for the specific instances. Using the same name for class and instance variables can be confusing, and isn't something to be done lightly. In the case of django models I think it works really well, but still can cause some headaches (I had similar questions when I first used django).
The second thing to note is that you can assign variables to an instance anywhere, it doesn't have to be in the __init__ function or even in a method of the instance's class, it can be anywhere. That is not to say that making a point of defining all instance variables in the __init__ function is a bad idea. In many cases it is a good idea.
This is a really old thread. I happen to get the same question while I'm just new to Django.
Class of 'title' is models.CharField, which seems a python descriptor. According to the Descriptor definition, 'title' is a class variable. p.title = 'xxx', there is no instance 'title'. The above statement calls the class variable title to create a hidden title for the instance. print(p.title) will just call the class variable title to return the invisible title of instance.
https://docs.python.org/3.7/howto/descriptor.html
Python cookbook chapter 8.6 also talks about the Descriptor.
Hope I'm correct and could help.

how to override class, or undeclare class or redeclare a Class in python?

is there any possible to override class, or undeclare class or redeclare a Class in python?
Yes, just declare it again:
class Foo(object): x = 1
class Foo(object): x = 2
The above code will not raise any error, and the name Foo will refer to the second class declared. Note however, that the class declared by the first declaration will still exist if anything refers to it, e.g. an instance, or a derived class.
This means that existing instances will not change class when you declare a new class with the same name, and existing subclasses will not magically inherit from the new class.
Probably the simplest method to deal with subclasses is to also re-declare them, so they inherit from the "renewed" base class. An alternative would be to mess with their __bases__ property, although I can't tell you if that would have unexpected results (there will almost certainly be some corner cases where this would not work).
As to existing instances, it is possible to re-assign their __class__ property with a new class. This does present two issues - first you have to find them (see this question: Printing all instances of a class), and second of all, items stored in instance __dict__ or __slots__ properties will still be there in those instances. If that is not something that should happen with your new class definition, you will have to write appropriate code to handle that as part of the transformation.
IN summary, it's unlikely to be worth it except in quite simple cases. If you need complete uptime for a running system, you might be better using a replication-based approach to achieve code changes.
Update: If this is the kind of thing you know you're going to do, another solution would be to use the strategy pattern.
Undeclare a class using del className as usual.

Categories

Resources