Python classes/subclasses - python

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.

Related

Storing Method In Dictionary in Python

I am trying to write a program that can initialize classes from various submodules. In order to make it easy to expand the modules in future, I would like to store their constructor functions and some of the key functions in dictionaries. I am getting the issue with the functions not being recognized as an attribute and am not certain how to fix this. It seems to be fine for the constructors. The code should look something like this:
import my_class
class_ctor = {"my_class":my_class.my_class, ...}
class_func = {"my_class":my_class.my_class.func, ...}
my_inst = class_ctor["my_class"](what,ever,arguments)
my_inst.class_func["my_class"](some,other,arguments)
Inside my_class.py:
class my_class:
def __init__(self):
...
def func(...):
...
Is there a way that I could achieve something like this? I have seen a few examples which have dispatchers that work in a similar way, but would like to abstract this to methods.
I appreciate any help!
The problem is this line:
my_inst.class_func["my_class"](some,other,arguments)
class_func doesn't belong to my_inst (from what you've shown).

How do you create an instance of a class when the class type is stored in a variable?

So I have a somewhat long and growing list of classes in a script. At a certain point in the script I want to be able to test an arbitrary instance for its type, and then whatever that type is, I want to create a second object of the same type. I've tried researching this and I know I can accomplish this by storing every class in a dictionary, like so:
class Foo(object):
pass
class Bar(object):
pass
d = {"Foo": Foo, "Bar": Bar}
x = dict["Foo"]()
It does the trick, allowing me to use a variable or string containing the name of the class, in order to create an instance of the class. However, it requires that every time I create a new class I have to remember to also put a new entry in the dictionary--which isn't the worst thing in the world, but as they say, if you're doing the same task more than once you should make a computer do it.
Is there a better way? Can you somehow take a variable or string containing the name of a class, and without knowing what value the variable or string has, generate an instance of the class?
So this is answering your problem rather than your question, but it seems you actually want to create another instance of an object rather than find a class by name. So that is even easier because you can find the class of an object with the type function. So to create a new instance b of the same type as a but with constructor parameters args simply do:
b = type(a)(args)
All classes are in globals dictionary (dictionary containing the current scope's global variables). Get the dictionary with globals(), and then find it by name (string). As a result you will get a class, which can be instantiated with ().
class Foo(object):
pass
x = globals()['Foo']()
Not sure why Huazuo Gao didn't make that an answer, but it solves my problem exactly and I've never seen that solution in my research on this problem--so I'll go ahead and punch it up as an answer.
You can do it using the string of the name of the class and the eval() function. So
class Foo(object):
pass
a = Foo()
s = str(type(a))
# The string produced isn't quite the name of the class so it has to be stripped
# of some surrounding characters.
m = s.find('.')
n1 = s.find("'")
n2 = s[n1+1:].find("'")
s = s[m+1:n1+n2+1]
b = eval(s + "()")
produces the desired behavior.

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.

Set Python attributes from a list, but recall them outside of a list

Not sure if this the recommended way of doing things in Python. I have a class with a bunch of attributes, like so
class MyClass:
def __init__(self):
self.attr1 = "first_value"
self.attr2 = "second_value"
...
However, this is tedious, I want to be able to do this in a loop:
self.attr_list = ["attr1", "attr2", "another_attr",...]
def __init__(self, values_list):
self.attr_values = [some_func(i) for i in values_list]
But I also later want to call these values like so:
foo = MyClass(values_list)
...
bar = foo.attr1
myFunc(foo.another_attr, ..., some_other_parameters)
So the question is, how do I avoid the tedious first method where the line for each attribute is hard-coded, but still get the convenience of referring to an attribute without having to know/remember where in the list it is?
Hope this is clearer.
Thanks
P.S. I'm using Python 3
I'm not sure I understand the question. Are you looking for setattr? Something like this:
def assign(self, attr_names, value_list):
for i in range(len(attr_names)):
setattr(self, attr_names[i], some_func(value_list[i]))
You can use it like that:
foo.assign(["attr1", "attr2"], value_list)
print(foo.attr1)
I don't think that using setattr is wrong per se however I advice using dictionaries instead since you might overwrite other attributes by accident, for example consider this:
foo.assign(["assign"], [1])
foo.assign(["assign"], [1]) # <-- exception now

How to access globals from a different point in code

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)

Categories