Dynamically create a class inherited from neomodel.StructuredNode - python

Python's library neomodel provides the ability to define a relationship with a class that hasn't been defined yet, by using its name as string, which works fine as follows:
from neomodel import StructuredNode, RelationshipTo
# if Foo is already defined
class Bar (structuredNode):
rel = RelationshipTo(Foo, 'REL')
# if Foo isn't defined
class Bar(StructuredNode):
rel = RelationshipTo('Foo', 'REL')
I want to create a class in the runtime and provide it with the attribute RelationshipTo, which should make a relationship with undefined yet class, so I did:
Bar = type('Bar', (StructuredNode,), {'rel': RelationshipTo('Foo', 'REL')})
In some point in the runtime later, I define Foo:
Foo = type('Foo', (StructuredNode,), {})
Now if I want to use the class I've just made:
bar = Bar()
The next error still pops up as if I haven't defined Foo:
AttributeError: module '_pydevd_bundle.pydevd_exec2' has no attribute
'Foo'
Note: This error doesn't appear if I at least define Bar statically (not in the runtime)
Would someone explain why that happens and how to define them properly in runtime, please?
I appreciate any help!

Related

How to prevent Python class instance variable typo?

A python class function had something like this:
class Widget:
def __init__(self):
self.foo_bar = 0
def fun(self, xyz):
self.foobar = xyz
A typo. The code for fun() should have referenced self.foo_bar. This took surprisingly long to debug (as the actual functions were more complex).
Is there a way to enforce that class instance variables can only be introduced (declared) in __init__? Python happily created a new class instance variable instead of generating an error. An error would have saved a lot of time.
If I run pylint on this code, I get the following errors:
test.py:1:0: C0114: Missing module docstring (missing-module-docstring)
test.py:1:0: C0115: Missing class docstring (missing-class-docstring)
test.py:5:4: C0116: Missing function or method docstring (missing-function-docstring)
test.py:6:8: W0201: Attribute 'foobar' defined outside __init__ (attribute-defined-outside-init)
test.py:1:0: R0903: Too few public methods (1/2) (too-few-public-methods)
You can configure pylint to disable the warnings you might not care as much about, e.g. missing-module-docstring, but the one that catches your attribute typo is this one:
test.py:6:8: W0201: Attribute 'foobar' defined outside __init__ (attribute-defined-outside-init)

Default value for fields

I have problem accessing fields from an object in a python script I did. Basically it boils down to this little piece of code:
from enum import Enum
class AbstractFoo:
def __init__(self, foo='works', bar='nope'):
self.foo = foo
self.bar = bar
class Foo(Enum):
test = AbstractFoo('bla', 'tada')
So when in the python console I try to access an element of my enum with:
Foo.test.foo
I would expect it to print me 'bla' which is the value I pass to the constructor (or at least it should print 'works' which would be the default value I've assigned).
What I actually get is
AttributeError: 'Foo' object has no attribute 'foo'
you can probably tell by now that I'm pretty new to python and especially the concept objects in python (I mostly write code in Java which might lead to some missconceptions from my part about the behaviour of objects in python).
What I figured out though is that I can do:
Foo.test.foo = 'whatever'
and assign a value to foo in this way. But when doing this I can also assign a value to a field I haven't even specified in the constructor such as:
Foo.test.noField = 'shouldn't even exist'
and it will work just as fine which I don't understand at all.
I would be really glad about some clarification how objects work in python and/or how I could realize an enum of a class in python.
EDIT: Apparently the code behaves the way I want it to if I remove the inheritance from Enum.
That can be quite confusing, since you are literally saying that test is something and then it is not anymore. That is because Enum is a special kind of class that takes all of its members and "converts" them into instance of the class. So the type of test is not AbstractFoo anymore, but instead Foo. However, you can get back the original value assigned to the enum instance with the value property:
from enum import Enum
class AbstractFoo:
def __init__(self, foo='works', bar='nope'):
self.foo = foo
self.bar = bar
class Foo(Enum):
test = AbstractFoo('bla', 'tada')
print(Foo.test.value.foo)
>>> bla
As #jdehesa noted, Enum members are instances of their parent Enum class. If you need them to also be instances of some other class simply inherit from it as well:
class Foo(AbstractFoo, Enum):
test = 'bla', 'tada'
Note that you no longer need to call AbstractFoo directly.

Create dynamically named classes instances in Python

I need to create a new instance of a specific class named from the content of a variable.
For example create an instance of the Foo class named whatever the content of the "s" variable is. This is what I tried
class Foo:
pass
s = 'bar'
eval(s) = Foo
The above code returns a "can't assign to function call" error.
I need it to create an instance called 'bar' in the Foo class in this case but I also need to be able to change the 's' variable to any string and for it to still work.
If there is another way for me to create class instances and then access them later with the "s" variable that would work too.
A lot of similar questions have been answered by creating pre defined dictionaries but in my case these dictionaries would have to be several hundred items long and hand written, and so are impractical and not very pythonian. I need to create and access the instance completely dynamically, hopefully by name but if there is another way I'm open to that too.
This should do it.
def make_class(name):
class_text = """
global {} # Makes the class object global.
class {}: # You put the class here.
pass
""".format(name, name) # Formats the text. There are a couple different ways to do this.
exec(class_text)
Example:
>>> make_class("Foo")
>>> make_class("Bar")
>>> Foo()
<__main__.Foo object at 0x7fedebcda748>
>>> Bar()
<__main__.Bar object at 0x7fedebcda8d0>

Defining global accessors

I have two Python files:
"testclass.py":
class TestClass:
Result = 0
def __init__(self):
self.Result = 1
return
Manager = TestClass()
and "hostapp.py":
import testclass
print Manager.Result # should equal 1
I'd prefer to simply include the accessory class (testclass) in my main class, then use an accessor that's already been initialized, but when I run hostapp.py, I get the following error:
NameError: name 'Manager' is not defined
Would someone please explain to me why the "global" variable Manager (which should be an instance of TestClass) is only accessible from within the class? I know I can access it using:
testclass.Manager
but that's not how I planned to access it. Help?
Edit:
After making the change suggested by Martineau, the accessor works as intended:
from testclass import Manager

Python weird class variables usage

Suppose we have the following code:
class A:
var = 0
a = A()
I do understand that a.var and A.var are different variables, and I think I understand why this thing happens. I thought it was just a side effect of python's data model, since why would someone want to modify a class variable in an instance?
However, today I came across a strange example of such a usage: it is in google app engine db.Model reference. Google app engine datastore assumes we inherit db.Model class and introduce keys as class variables:
class Story(db.Model):
title = db.StringProperty()
body = db.TextProperty()
created = db.DateTimeProperty(auto_now_add=True)
s = Story(title="The Three Little Pigs")
I don't understand why do they expect me to do like that? Why not introduce a constructor and use only instance variables?
The db.Model class is a 'Model' style class in classic Model View Controller design pattern.
Each of the assignments in there are actually setting up columns in the database, while also giving an easy to use interface for you to program with. This is why
title="The Three Little Pigs"
will update the object as well as the column in the database.
There is a constructor (no doubt in db.Model) that handles this pass-off logic, and it will take a keyword args list and digest it to create this relational model.
This is why the variables are setup the way they are, so that relation is maintained.
Edit: Let me describe that better. A normal class just sets up the blue print for an object. It has instance variables and class variables. Because of the inheritence to db.Model, this is actually doing a third thing: Setting up column definitions in a database. In order to do this third task it is making EXTENSIVE behinds the scenes changes to things like attribute setting and getting. Pretty much once you inherit from db.Model you aren't really a class anymore, but a DB template. Long story short, this is a VERY specific edge case of the use of a class
If all variables are declared as instance variables then the classes using Story class as superclass will inherit nothing from it.
From the Model and Property docs, it looks like Model has overridden __getattr__ and __setattr__ methods so that, in effect, "Story.title = ..." does not actually set the instance attribute; instead it sets the value stored with the instance's Property.
If you ask for story.__dict__['title'], what does it give you?
I do understand that a.var and A.var are different variables
First off: as of now, no, they aren't.
In Python, everything you declare inside the class block belongs to the class. You can look up attributes of the class via the instance, if the instance doesn't already have something with that name. When you assign to an attribute of an instance, the instance now has that attribute, regardless of whether it had one before. (__init__, in this regard, is just another function; it's called automatically by Python's machinery, but it simply adds attributes to an object, it doesn't magically specify some kind of template for the contents of all instances of the class - there's the magic __slots__ class attribute for that, but it still doesn't do quite what you might expect.)
But right now, a has no .var of its own, so a.var refers to A.var. And you can modify a class attribute via an instance - but note modify, not replace. This requires, of course, that the original value of the attribute is something modifiable - a list qualifies, a str doesn't.
Your GAE example, though, is something totally different. The class Story has attributes which specifically are "properties", which can do assorted magic when you "assign to" them. This works by using the class' __getattr__, __setattr__ etc. methods to change the behaviour of the assignment syntax.
The other answers have it mostly right, but miss one critical thing.
If you define a class like this:
class Foo(object):
a = 5
and an instance:
myinstance = Foo()
Then Foo.a and myinstance.a are the very same variable. Changing one will change the other, and if you create multiple instances of Foo, the .a property on each will be the same variable. This is because of the way Python resolves attribute access: First it looks in the object's dict, and if it doesn't find it there, it looks in the class's dict, and so forth.
That also helps explain why assignments don't work the way you'd expect given the shared nature of the variable:
>>> bar = Foo()
>>> baz = Foo()
>>> Foo.a = 6
>>> bar.a = 7
>>> bar.a
7
>>> baz.a
6
What happened here is that when we assigned to Foo.a, it modified the variable that all instance of Foo normally resolve when you ask for instance.a. But when we assigned to bar.a, Python created a new variable on that instance called a, which now masks the class variable - from now on, that particular instance will always see its own local value.
If you wanted each instance of your class to have a separate variable initialized to 5, the normal way to do it would be like this:
class Foo(object);
def __init__(self):
self.a = 5
That is, you define a class with a constructor that sets the a variable on the new instance to 5.
Finally, what App Engine is doing is an entirely different kind of black magic called descriptors. In short, Python allows objects to define special __get__ and __set__ methods. When an instance of a class that defines these special methods is attached to a class, and you create an instance of that class, attempts to access the attribute will, instead of setting or returning the instance or class variable, they call the special __get__ and __set__ methods. A much more comprehensive introduction to descriptors can be found here, but here's a simple demo:
class MultiplyDescriptor(object):
def __init__(self, multiplicand, initial=0):
self.multiplicand = multiplicand
self.value = initial
def __get__(self, obj, objtype):
if obj is None:
return self
return self.multiplicand * self.value
def __set__(self, obj, value):
self.value = value
Now you can do something like this:
class Foo(object):
a = MultiplyDescriptor(2)
bar = Foo()
bar.a = 10
print bar.a # Prints 20!
Descriptors are the secret sauce behind a surprising amount of the Python language. For instance, property is implemented using descriptors, as are methods, static and class methods, and a bunch of other stuff.
These class variables are metadata to Google App Engine generate their models.
FYI, in your example, a.var == A.var.
>>> class A:
... var = 0
...
... a = A()
... A.var = 3
... a.var == A.var
1: True

Categories

Resources