If I have a file, say first.py, which looks like this -
class Person(object):
pass
class Dog(object):
pass
and I have a second file, second.py.
How can I get all the classes that were defined in first.py in second.py?
Perhaps I should mention that the use-case I'm trying to implement is similar to the one that happens when initializing models in Django - When I run the manage.py sql myapp command, I assume Django goes through all my models in models.py and generates an SQL query for them.
So what I'm trying to do is similar to what Django does when it takes all models defined in models.py.
How can I get all the user defined classes from a file? (Unless there's a smarter way to do what Django does)
Thanks in advance!
If you have a file first.py, in second.py, you would have to write the following code to return all the user-defined classes in first.py:
import first
from types import *
userDefinedClasses = [i for i in dir(first) if type(getattr(first, i)) is TypeType]
In your simple example, pre-defining first.py, dir(first) would return the list ['Dog', 'Person', '__builtins__', '__doc__', '__file__', '__name__', '__package__']. To prune it, you would have to use the above compressed for loop to check the type of each object in the directory of first.
This would return all objects in first with type "type", which is practically all user-defined classes.
All django-Models are subclasses of models.Model which has a meta class, that collects all model-subclasses.
In general it is not possible to get all 'user-defined' classes.
Related
I'm simultaneously learning Python while picking up Django. I'm familiar with many other languages.
In the following code snippet, x is a class variable of class Foo.
class Foo(object):
x = 9000
Given the previous declaration, the following works fine.
print Foo.x
The Django framework lets you create your model by defining Python classes. It makes fields out of the different class variables in your Python classes.
class Question(models.Model):
question_text = models.CharField(max_length=200)
Why does the following code snippet:
#!/usr/bin/env
import os, django
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
django.setup()
from polls.models import Question, Choice
print Question.question_text
throw the following error:
AttributeError: type object 'Question' has no attribute 'question_text'
As far as I'm understanding everything my Question class has a single static member defined: Question.question_text.
Django models use a metaclass to alter what is normal class behaviour.
Use dir(Question) and you'll see there are different attributes on that class now. This is custom behaviour just for Django models however.
If you are curious you can study the metaclass __new__ method, but it does a lot of work specific to Object Relational Mapping tasks.
Magic.
No, really.
Python classes aren't set-in-stone structure, like they are in C++. They are, themselves, just objects — instances of another type:
class Foo(object):
pass
print(type(Foo)) # <class 'type'>
You can even make a class like you'd make any other object, by calling type. This:
class Bar(object):
a = 1
b = 2
Is really (more or less) syntactic sugar for this:
Bar = type('Bar', (object,), {'a': 1, 'b': 2})
type takes the name of your new class, a list of its superclasses, and a dict of all the attributes of the class, and spits out a new class.
But, because type is just a class like any other, it's possible to subclass it and give it different behavior. And this is what Django has done: it's created a subclass of type that does something different with the dict of attributes you pass to it.
You don't see this happening directly in your own code, but if you check type(models.Model), you'll find out its type is not type, but something specific to Django. It probably has "meta" in the name, because it's called a metaclass: the class of a class.
This is a fairly common pattern for making "declarative" libraries in Python, where the attributes of a class actually define some kind of structure. You can see the same thing in form validation (wtforms), schema validation (colander), other ORMs (sqlalchemy), and even the stdlib enum module.
Question is an object of type type. You want an instance of Question:
>>> q= Question(text = "Does a dog have the buddha nature?")
Then you should get
q.text
"Does a dog have the buddha nature?"
Note that this object will not persist unless you save() it:
>>> q.save()
I have a very basic class that looks something like the following:
class Car(Model):
name = CharField(max_length=255, unique=True)
#classmethod
def create_simple_examples(cls):
for c in ['Sedan', 'Coupe', 'Van', 'SUV']:
cls.objects.get_or_create(name=c)
#classmethod
def get_default(cls):
c, _ = cls.objects.get_or_create(name='Sedan')
return c
def __unicode__(self):
return self.name
I am trying to add it to a django app. I have the two class methods to 1. a function to populate the table quickly, and 2. to grab a default one which will be used often.
When I run
python manage.py makemigrations myapp
I get the following error
ValueError: Cannot serialize: <bound method ModelBase.get_default of <class 'crunch.django.myapp.models.Car'>>
I am not quite sure why it's trying to serialize my get_default function as that's not really part of the migration of the table itself. Any help would be greatly appreciated
UPDATE I think I may have found the source of the problem (still not sure how to fix it though...)
I have other classes that are FKing to my new class, and the default uses my default above...something like this
class OtherClass(Model):
car = ForeignKey(Car, default=Car.get_default)
It looks like the migration is trying to serialize the function because of this. Any tips on how to get around this?
Add the #deconstructible decorator to the classes which have a classmethod
from django.utils.deconstruct import deconstructible
#deconstructible
class Car(Model):
...
More documentation on deconstructible can be found here
As explained in Django's migrations docs, Django can serialize function and method references, (in Python 3) unbound methods used from within the class body, and a bunch of other stuff, but it can't serialize everything.
In this case, because you've made get_default a #classmethod, Car.get_default is a bound method (i.e., it takes an implicit reference to Car as its first parameter), rather than a plain function or method reference, and Django doesn't know what to do with that.
Try making get_default a #staticmethod instead, or make a free function (top-level function) that calls Car.get_default.
I'm simultaneously learning Python while picking up Django. I'm familiar with many other languages.
In the following code snippet, x is a class variable of class Foo.
class Foo(object):
x = 9000
Given the previous declaration, the following works fine.
print Foo.x
The Django framework lets you create your model by defining Python classes. It makes fields out of the different class variables in your Python classes.
class Question(models.Model):
question_text = models.CharField(max_length=200)
Why does the following code snippet:
#!/usr/bin/env
import os, django
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
django.setup()
from polls.models import Question, Choice
print Question.question_text
throw the following error:
AttributeError: type object 'Question' has no attribute 'question_text'
As far as I'm understanding everything my Question class has a single static member defined: Question.question_text.
Django models use a metaclass to alter what is normal class behaviour.
Use dir(Question) and you'll see there are different attributes on that class now. This is custom behaviour just for Django models however.
If you are curious you can study the metaclass __new__ method, but it does a lot of work specific to Object Relational Mapping tasks.
Magic.
No, really.
Python classes aren't set-in-stone structure, like they are in C++. They are, themselves, just objects — instances of another type:
class Foo(object):
pass
print(type(Foo)) # <class 'type'>
You can even make a class like you'd make any other object, by calling type. This:
class Bar(object):
a = 1
b = 2
Is really (more or less) syntactic sugar for this:
Bar = type('Bar', (object,), {'a': 1, 'b': 2})
type takes the name of your new class, a list of its superclasses, and a dict of all the attributes of the class, and spits out a new class.
But, because type is just a class like any other, it's possible to subclass it and give it different behavior. And this is what Django has done: it's created a subclass of type that does something different with the dict of attributes you pass to it.
You don't see this happening directly in your own code, but if you check type(models.Model), you'll find out its type is not type, but something specific to Django. It probably has "meta" in the name, because it's called a metaclass: the class of a class.
This is a fairly common pattern for making "declarative" libraries in Python, where the attributes of a class actually define some kind of structure. You can see the same thing in form validation (wtforms), schema validation (colander), other ORMs (sqlalchemy), and even the stdlib enum module.
Question is an object of type type. You want an instance of Question:
>>> q= Question(text = "Does a dog have the buddha nature?")
Then you should get
q.text
"Does a dog have the buddha nature?"
Note that this object will not persist unless you save() it:
>>> q.save()
I am new to the community. In my Django project, I have a module called "social" in which I have several files like facebook.py, and twitter.py, each with classes that are subclasses of "SocialProvider"
Example
class Facebook(SocialProvider):
Also in my social module is a file called "helper.py" which contains a SocialProviderHelper, which I would like to keep track of all SocialProvider subclasses, and generate different lists, and identifiers for them. For example.. the SocialProviderHelper could "find" Facebook and Twitter and add them to various lists like cool_providers = [] popular_providers = [] old_providers, etc, etc. The goal is to make a universal SocialProviderHelper that other areas of code can import and use... for example.. in a view I may want to get all the "popular_providers" names.. so I would import SocialProviderHelper.. and do something like
helper = SocialProviderHelper()
helper.getOldProviders()
In my SocialProviderHelper, I have:
class SocialProviderHelper(object):
_providers = SocialProvider.__subclasses__()
but
subclasses()
returns an empty list seemingly because the "providers" are defined in other files that haven't been imported, and subclasses() only maintains weak references to the class if they are "alive".
Is there any way around this ?
**The end goal is to be able to whip up another subclass of SocialProvider anywhere simply by doing..
import SocialProvider
class NewSocialNetwork(SocialProvider)
...and have the SocialProviderHelper know of its existence.**
I have tried to implement "subclasses() with a metaclass that keeps a registry of subclasses, but a similar problem persists.
This could be done with a decorator:
from SocialProvider import SocialProvider
#SocialProvider.Register
class NewSocialProvider( SocialProvider ):
pass
I've assumed SocialProvider is a superclass written by you. If so, in your superclass file, the Register helper could be defined as a class method:
class SocialProvider:
subclasses = []
#classmethod
def Register( cls, subcl ):
cls.subclasses.append( subcl )
return subcl
If not, then you could still define a function somewhere, to be used as a decorator, but it and the list it appends to would have to be defined somewhere else, separate from the SocialProvider class. You mention the problem of not-yet-imported files. There's nothing you can do to detect a class that hasn't been defined yet, so you'd have to make sure that the files with the subclass definitions are imported (e.g. via statements like import facebook etc in the ___init__.py file of your module).
I have a main.py which contains class definitions for objects that are fetched from db and displayed.
I also have a scrape.py that fetches these same sorts of objects from the web, and stores them to the db.
How do I avoid having to have class definitions for these objects in both main.py and scrape.py?
Put the classes in a separate module (file) and import them in both of the other files.
models.py (new file)
class MyModel(object):
pass # Implementation here
scrape.py or main.py
from models import MyModel, SomeOtherModel
m = MyModel
m.put()
Make a seperate .py file called something like classes and variables, place all classes you use in your code in that file and call it upon startup for both files.