How to access globals from a different point in code - python

I'm trying to find a way of basically doing a late eval, using context from a different location in the code. As an example, I have a class Friend, and it can be used like this:
>>> class A:
... friend = Friend('B')
...
>>> class B:
... friend = Friend('A')
...
>>> A.friend.getobject()
<class '__main__.B'>
However, Friend is defined elsewhere in the code, in a separate library, and would look something like this:
class Friend:
def __init__(self, objname):
self.objname = objname
def getobject(self):
return eval(self.objname, original_context)
The sqlalchemy ORM has a similar pattern for defining columns, but they implement it by tracking all owning classes (i.e. tables) in a session. I could do something similar if I need to, but I'd like to know if there is another way to do this. I've been looking at frames and the interpreter stack, and I think I can get to the relevant frame's locals using something like inspect.stack()[1][0].f_locals, but I would have to do this in Frame.__init__ which is called before the object is defined.
My questions is how to find original_context, but only at the time it is needed. This comes down to two issues:
1. How to access the environment (or frame?) in which Friend was instantiated.
2. How to access it at the time getobject is called.

You will have to use the fully qualified classname, ie:
class A:
friend = Friend('themodule.B')
And then take that string, extract out the module and import the B class, and generate it like this.
However, in general, a better way is to do:
class A:
friend = Friend(B)
In this case B isn't defined at that point, but you can easily do:
class A:
pass
class B:
pass
A.friend = Friend(B)
B.friend = Friend(A)

Related

Python classes/subclasses

I've read over the Python documents regarding classes and subclasses but I've still not seen anything to accomplish what I'm after. Maybe I'm just using the wrong terminology for it. But basically I have created a class and now I want to create a subclass that will have properties so that I can call them similarly to the following:
import MyClass
mc = MyClass()
print mc.MySubclass.Property
The reason for this is because currently I have several properties in my class and I'd like to make it easier to get them. Like currently I'm just saying mc.category_value where "category" represents a might be like "color" and "value" would be like "red", so it looks like "mc.color_red" or "mc.color_blue" but I'd rather be able to say "mc.color.red". Is this possible?
So inner classes, are possible:
class Foo():
x = 1
def y():
print("hello")
class Bar():
z = 2
x = Foo.Bar()
print(x.z)
print(Foo.Bar.z) # added this example to be closer to what you want
I use these often with the inner class being private, called something like _Bar when I want a struct like object that I don't want to expose. But we also use them when they are like you say, property objects of a factory or something.

Get Outer Class Name for Nested Class (Python)

Background
(Might be relevant because there might be a simpler way to achieve what I want.)
I want to build a declarative way to define "aspects" that can be analyzed by a static code analysis tool. The whole concept is written down here. Every aspect (say Redundancy) may have sub aspects recursively (say Redundancy.Clone) and every aspect shall have documentation and arbitrary other properties. The user shall be able to choose which aspects to analyze and I have to programmatically find out for the internal representation of an aspect if it's the one choosen by the user (i.e. for a given class Redundancy.Clone I want to validate that it belongs to a given string redundancy.clone but not redundancy.unused_import).
I decided to use classes like this:
class Redundancy(Aspect):
"""
This meta aspect describes any kind of redundancy in your source code.
"""
# Can't inherit from Redundancy here because of the recursion
class Clone(Aspect):
"""
This redundancy describes a code clone. Code clones are different pieces of
code in your codebase that are very similar.
"""
# Stuff...
Problem
For a given Aspect class I want to get the describing string (Redundancy.Clone -> redundancy.clone). For that I have to get the name of the surrounding module/class/whatever it is, check if it's a class (trivial) and construct a string out of it.
Possible Solutions and How They Failed
I did try looking at the dir of my classes to see if there's anything useful in the dunder methods I could use but found nothing except the repr which in the above case is <class 'coalib.bearlib.aspects.Redundancy.Clone'> when living in the aspects module. This shows that it should be possible but I have no idea on how repr gets this information and I would like to avoid using repr and stripping off the unneeded stuff as that's kind of a hack.
I am not able to inherit the nested class from the outer one as it is not completely defined yet. I want them nested for the usability, being able to from ... import Redundancy and in my source code write Redundancy.Clone is a huge plus.
Any suggestions, including changing my approach, would be appreciated.
You could use __qualname__ (PEP 3155)
>>> class C:
... def f(): pass
... class D:
... def g(): pass
...
>>> C.__qualname__
'C'
>>> C.f.__qualname__
'C.f'
>>> C.D.__qualname__
'C.D'
>>> C.D.g.__qualname__
'C.D.g'
You can construct the class after class Redundancy statement finish its execution with the type class. For example:
class Aspect:
pass
class Redundancy(Aspect):
#classmethod
def init(cls):
cls.make_Clone()
#classmethod
def make_Clone(cls):
def __init__(self):
print('inside Redundancy.Clone')
methods = {}
methods["__init__"] = __init__
cls.Clone = type("{0}.Clone".format(cls.__name__), (Redundancy,), methods )
Redundancy.init()
print(Redundancy.Clone)
print(Redundancy.Clone())
# output:
# <class '__main__.Redundancy.Clone'>
# inside Redundancy.Clone
# <__main__.Redundancy.Clone object at 0x01DCA130>

Passing an instance to __init__. Is this a good idea?

Suppose I have a simple class like this:
class Class1(object):
def __init__(self, property):
self.property = property
def method1(self):
pass
An instances of Class1 returns a value that can be used in other class:
class Class2(object):
def __init__(self, instance_of_class1, other_property):
self.other_property = other_property
self.instance_of_class1 = instance_of_class1
def method1(self):
# A method that uses self.instance_of_class1.property and self.other_property
This is working. However, I have the feeling that this is not a very common approach and maybe there are alternatives. Having said this, I tried to refactor my classes to pass simpler objects to Class2, but I found that passing the whole instance as an argument actually simplifies the code significantly. In order to use this, I have to do this:
instance_of_class1 = Class1(property=value)
instance_of_class2 = Class2(instance_of_class1, other_property=other_value)
instance_of_class2.method1()
This is very similar to the way some R packages look like. Is there a more "Pythonic" alternative?
There's nothing wrong with doing that, though in this particular example it looks like you could just as easily do
instance_of_class2 = Class2(instance_of_class1.property, other_property=other_value).
But if you find you need to use other properties/methods of Class1 inside of Class2, just go ahead and pass the whole Class1 instance into Class2. This kind of approach is used all the time in Python and OOP in general. Many common design patterns call for a class to take an instance (or several instances) of other classes: Proxy, Facade, Adapter, etc.

Naming practice for objects of a class in Python

I have this weird problem as to how to name objects of a class.
For example, consider the class:
>>> class DoSomething:
pass
What should I call the object of this class? do_something or what? Since I came out of the learning stage, I used to use x, y or z or whatever came to my mind. But now since I am learning to write proper code and not the language, I always face this problem. Any suggestions?
Name it something representative of what it's actually being used for. For instance:
class Cereal:
def eat(self):
print 'yum'
breakfast = Cereal()
breakfast.eat()
or
class User:
def __init__(self, userid):
# ...
admin_user = User(ADMIN_ID)
You should name it after what it represents. For example if I have a class User in a web application and I want to refer to the currently logged-in user, I name the variable current_user.
And if you have more objects of one class, your approach fails immediately. Giving the variable an index like do_something1, do_something2 is not and will never be an option.
Use something meaningful, so that a reader of your code knows what this variable represents.
Btw. this applies to all programming languages, not just Python.
One good naming practise is to give plural names to collections such as sets and lists.

python classes that refer to each other

I have two classes that refer to each other, but obviously the compiler complains. Is there any way around this?
EDIT
Actually my code is slightly different than what Hank Gay uses. So python can definitely deal with some kinds of circular references, but it tosses an error in the following situation. Below is what I've got and I get an 'name Y not defined error'
class X(models.Model):
creator = Registry()
creator.register(Y)
class Y(models.Model):
a = models.ForeignKey(X)
b = models.CharField(max_length=200)
Hope this helps clarify. Any suggestions.
In python, the code in a class is run when the class is loaded.
Now, what the hell does that mean? ;-)
Consider the following code:
class x:
print "hello"
def __init__(self): print "hello again"
When you load the module that contains the code, python will print hello. Whenever you create an x, python will print hello again.
You can think of def __init__(self): ... as equivalent with __init__ = lambda self: ..., except none of the python lambda restrictions apply. That is, def is an assignment, which might explain why code outside methods but not inside methods is run.
When your code says
class X(models.Model):
creator = Registry()
creator.register(Y)
You refer to Y when the module is loaded, before Y has a value. You can think of class X as an assignment (but I can't remember the syntax for creating anonymous classes off-hand; maybe it's an invocation of type?)
What you may want to do is this:
class X(models.Model):
pass
class Y(models.Model):
foo = something_that_uses_(X)
X.bar = something_which_uses(Y)
That is, create the class attributes of X which reference Y after Y is created. Or vice versa: create Y first, then X, then the attributes of Y which depend on X, if that's easier.
Hope this helps :)
The error is that execution of creator.register(Y) is attempted during the (executable) definition of class X, and at that stage, class Y is not defined. Understand this: class and def are statements that are executed (typically at import time); they are not "declarations".
Suggestion: tell us what you are trying to achieve -- perhaps as a new question.
UPDATE: He changed the question after my answer. The currently accepted solution is better in light of the new question.
What are you saying is the problem?
class A(object):
def __init__(self):
super(A, self).__init__()
def b(self):
return B()
class B(object):
def __init__(self):
super(B, self).__init__()
def a(self):
return A()
This compiles and runs just fine.
As long as you are working within a method you can access the class object.
Thus the example above has no problems if creator.register(Y) is moved inside __init__. However, you cannot have circular references to classes outside of methods.
This is a great question. Although others have already answered it, I will feel free to provide another example.
Consider this program.
#dataclass
class A:
b: B
class B:
def __init__(self):
pass
b is now a class-level variable and this program does not work. The name B is not defined at the moment when the Python interpreter loads (executes) the code of class A. Unlike compiled languages (such as C/C++), interpreters execute the code from the beginning to the end of the file command by command, in one pass. Since Python needs to know what B is when it defines the class A, it fails. B is only defined later.
Now, consider a slightly different program.
class A:
def __init__(self):
self.b = B()
class B:
def __init__(self):
pass
b is now an object-level variable and this program works. Python still executes the code from the beginning to the end of the file in the single pass, however, now it does not need to know what B is at the moment it reads the self.b = B() line. This is because the __init__ method is executed only when someone wants to construct an object of class A. Since the construction of an object will happen somewhere later in the program (when B is already defined), __init__ will work fine when it is needed.
I came here late, but I want to show how I resolved this problem.
You can have a class nested to the other, and both classes will be able to reference each other
Here a demonstration:
class X():
class Y():
def x(self):
return X()
def y(self):
return self.Y()
a1 = X()
a2 = a1.y()
b1 = X.Y()
b2 = b1.x()
And you can create a BaseClass that contains the classes you want to referenciate
class Z():
class X():
def y(self):
return Z.Y()
class Y():
def x(self):
return Z.X()
As we well know, it looks like a self-evident contradiction that we try to imagine of two independent but inter-dependent entities just from a point of their birth in physical world. But, when it comes to the area of software, we often encounter this kind of issues so called 'circular or mutual references'. That may come more seriously in object-oriented design, in which inter-operating software elements are usually defined and related to one another in imitation of such a way as physical ones, but still as pure logical existences.
In many programming languages, these issues have been resolved by declaring to-be-referenced elements in time before their to-reference elements just in form of signatures (no body definitions) for functions or classes. However, that sort of evading tricks seems neither longer available nor useful for a script-based language like Python.
In Python, we'd better approach 'circular reference' in a view of software engineering, as follows:
It's much better to redesign classes not circular if possible; there are several ways (e.g. class de- or composition, call-back function, observer or subscriber patterns, and etc.) to make references between elements occur within the same class, removed or inverse.
In cases that linearizing some circular chains between elements might cause more serious problem in some aspect like quality or productivity, we can take another measure to separate their traditional construction phase into two: creating and structuring.
For example, two persons in friends who are destined to have their birth absolutely after observing the other's birth can do in a way that they are first born and then have their friendship just before any meaningful and observable occasions happen.
Note that if we face some extreme complexity or need some high degree of integrity in dealing with inter-aggregated objects, applying a Factory pattern will pay off.
The problem is most likely not Python. I would think it is an SQL issue. The classes are via an abstraction layer converted to an SQL query to create a table.
You are trying to reference from one table another one that at the time does not exist yet.
In SQL you would solve this by creating the table first without the references and after that modify them to make those references,
However I am not sure about my answer, so take it with lots of seasoning, I would be actually quite surprised if Django's database abstraction layer doesn't deal with cross references nicely.

Categories