I don't understand the order of methods in python - python

I don't understand why the code uses the print_me method from Class D, and not the method in class A.
I did some testing using print-statements and can see that it reads the print_me-method of class D before initialising class A, but I don't understand why it doesn't do the same for class A.
class A:
name = "Alfa"
def __init__(self, foo):
self.foo = foo
foo = 100
self.print_me()
def print_me(self):
print(self.name, self.foo)
class B(A):
name = "Beta"
def __init__(self, bar = 40):
self.bar = bar
print(self.name, bar)
class C:
name = "Charlie"
class D(A, C):
name = "Delta"
def __init__(self, val):
A.__init__(self, val)
def print_me(self):
print(self.name, "says", self.foo)
d = D(60)
The output is: Delta says 60
I thought it would be: Delta 60

Because the self you are passing to the __init__ of A is still an instance of D, not A. And the function A.__init__ is calling self.print_me, which belongs to D.
If you do a = A(); a.print_me() you'd get what you expect.
Important note: The __init__ method in python is not the actual constructor, it is just a method that is automatically called after the actual construction of the object. However, when you call it yourself, it works just like any other method.

Related

Correct way of returning new class object (which could also be extended)

I am trying to find a good way for returning a (new) class object in class method that can be extended as well.
I have a class (classA) which has among other methods, a method that returns a new classA object after some processing
class classA:
def __init__(): ...
def methodX(self, **kwargs):
process data
return classA(new params)
Now, I am extending this class to another classB. I need methodX to do the same, but return classB this time, instead of classA
class classB(classA):
def __init__(self, params):
super().__init__(params)
self.newParams = XYZ
def methodX(self, **kwargs):
???
This may be something trivial but I simply cannot figure it out. In the end I dont want to rewrite the methodX each time the class gets extended.
Thank you for your time.
Use the __class__ attribute like this:
class A:
def __init__(self, **kwargs):
self.kwargs = kwargs
def methodX(self, **kwargs):
#do stuff with kwargs
return self.__class__(**kwargs)
def __repr__(self):
return f'{self.__class__}({self.kwargs})'
class B(A):
pass
a = A(foo='bar')
ax = a.methodX(gee='whiz')
b = B(yee='haw')
bx = b.methodX(cool='beans')
print(a)
print(ax)
print(b)
print(bx)
class classA:
def __init__(self, x):
self.x = x
def createNew(self, y):
t = type(self)
return t(y)
class classB(classA):
def __init__(self, params):
super().__init__(params)
a = classA(1)
newA = a.createNew(2)
b = classB(1)
newB = b.createNew(2)
print(type(newB))
# <class '__main__.classB'>
I want to propose what I think is the cleanest approach, albeit similar to existing answers. The problem feels like a good fit for a class method:
class A:
#classmethod
def method_x(cls, **kwargs):
return cls(<init params>)
Using the #classmethod decorator ensures that the first input (traditionally named cls) will refer to the Class to which the method belongs, rather than the instance.
(usually we call the first method input self and this refers to the instance to which the method belongs)
Because cls refers to A, rather than an instance of A, we can call cls() as we would call A().
However, in a class that inherits from A, cls will instead refer to the child class, as required:
class A:
def __init__(self, x):
self.x = x
#classmethod
def make_new(cls, **kwargs):
y = kwargs["y"]
return cls(y) # returns A(y) here
class B(A):
def __init__(self, x):
super().__init__(x)
self.z = 3 * x
inst = B(1).make_new(y=7)
print(inst.x, inst.z)
And now you can expect that print statement to produce 7 21.
That inst.z exists should confirm for you that the make_new call (which was only defined on A and inherited unaltered by B) has indeed made an instance of B.
However, there's something I must point out. Inheriting the unaltered make_new method only works because the __init__ method on B has the same call signature as the method on A. If this weren't the case then the call to cls might have had to be altered.
This can be circumvented by allowing **kwargs on the __init__ method and passing generic **kwargs into cls() in the parent class:
class A:
def __init__(self, **kwargs):
self.x = kwargs["x"]
#classmethod
def make_new(cls, **kwargs):
return cls(**kwargs)
class B(A):
def __init__(self, x, w):
super().__init__(x=x)
self.w = w
inst = B(1,2).make_new(x="spam", w="spam")
print(inst.x, inst.w)
Here we were able to give B a different (more restrictive!) signature.
This illustrates a general principle, which is that parent classes will typically be more abstract/less specific than their children.
It follows that, if you want two classes that substantially share behaviour but which do quite specific different things, it will be better to create three classes: one rather abstract one that defines the behaviour-in-common, and two children that give you the specific behaviours you want.

Inheritance using a function as the base object constructor

I've imported a package that provides me with a class and a wrapper function that creates an instance of that class.
For example:
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
def print_a(self):
print(self.a)
def print_b(self):
print(self.b)
def makeFoo(x, y):
a = x + y
b = x - y
return Foo(a, b)
I want to have a similar class NamedFoo, that has the same properties/methods, also has a name property, and with a constructor that calls makeFoo. I figure that this should be solved using inheritance, with NamedFoo being a subclass of Foo. However, I don't know how to make the NamedFoo constructor utilize makeFoo correctly:
class NamedFoo(Foo):
def __init__(self, x, y, name):
# ???
# Foo = makeFoo(x, y) ??
# self.Foo = makeFoo(x, y) ??
self.name = name
def printName(self):
print(self.name)
Example data:
myNamedFoo = NamedFoo(2,5,"first")
myNamedFoo.print_a() # (From makeFoo: a = x + y) ==> 2 + 5 = 7
myNamedFoo.print_b() # (From makeFoo: a = x - y) ==> 2 - 5 = -3
I'm not too familiar with object-oriented programming, so I might just be using the wrong search terms, but I haven't found anything similar to what I need. Is this possible, and if so how can I do it?
I'm also not sure if this is an X/Y problem, but here are the alternatives I've considered and why I don't think they're ideal:
Composition of Foo and the property name: It's ugly and doesn't seem right.
Manually adding the name property to each Foo object, and perhaps wrapping it in a function: Doesn't quite have the elegance of a one liner constructor.
Rewriting the constructor for the Foo class, to have the same code as what's in makeFoo: makeFoo is rather complex and needs to do a lot of setup, and this would in any case lead to code duplication
In the NamedFoo constructor, create an instance of the Foo class from the makeFoo wrapper function. Pass this instance's attributes to the super().__init__.
class NamedFoo(Foo):
def __init__(self, x, y, name):
_foo = makeFoo(x,y) # use the wrapper to handle complex logic from input params
super().__init__(_foo.a,_foo.b) # pass the properly derived Foo attributes to the superclass constructor
self.name = name
This way, we're instantiating NamedFoo from whatever magic happens within the makeFoo function. Pass your x and y to that, which creates a throwaway Foo instance (so we can have it properly constructed with whatever complex logic resides in the helper function). The final NamedFoo class is then instantiated from the Foo constructor.
i think this should work..
class Foo:
def __init__(self,a,b):
self.a = a + b
self.b = a - b
def print_a(self):
print(self.a)
def print_b(self):
print(self.b)
class NamedFoo(Foo):
def __init__(self,a,b,name):
super().__init__(a,b)
self.name = name
def main():
example = NamedFoo(2,5,"first")
example.print_a()
example.print_b()
main()
this prints out
7
-3
or if you really want to use a function to create self.a and self.b use this:
class Foo:
def __init__(self, a, b):
self.a, self.b = make_foo(a,b)
def print_a(self):
print(self.a)
def print_b(self):
print(self.b)
class NamedFoo(Foo):
def __init__(self, a,b,name):
super().__init__(a,b)
self.name = name
def make_foo(x,y):
return x+y, x-y
def main():
example = NamedFoo(2,5,"first")
example.print_a()
example.print_b()
main()

Initializing a class that consist of many classes in such a way that one of the classes has different attributes

Here are the classes and their relations:
http://i.imgur.com/HS5YrZZ.png
Code for clarification:
class A(object):
def __init__(self):
self.atr = 1
class B(object):
def __init__(self):
self.atr = A()
class C(object):
def __init__(self):
self.atr = A()
class D(object):
def __init__(self):
self.atr1 = B()
self.atr2 = C()
test1 = D()
Now what do I do if I want to initialize D in such a way that A's self.atr = 2, and that change reflects to all those classes (B and C) that use A as well when I initialize D
Like I imagine it in pseudo code:
test2 = D(A.self.atr = 2)
So you initialize D in such a manner that A's self.atr = 2
If you want B and C to have different properties, as required by a call from D, the way to do that is to pass parameters for the initialization of B and C so that they know what to do.
The parameter can be itself an instance of A, where the attributes you care for are set before inistantiatin B and C:
class A(object):
def __init__(self, atr=1):
self.atr = atr
class B(object):
def __init__(self, config):
self.atr = config
class C(object):
def __init__(self, config):
self.atr = config
class D(object):
def __init__(self):
my_a = A(2)
self.atr1 = B(my_a)
self.atr2 = C(my_a)
test1 = D()
update
I see from the comments above you seem to dislike this approach duew to the impression you'd have a lot of repetitive code everywhere -
That is not the case however - if for example, you have a lot of classes that have to be "preconfigured" like class A, passed to a lot of other classes, you could just create a bundle of all classes pre-configured - you'd still pass on a single parameter to each instance you create.
Also, there are, as you want, mechanisms in Python to allow dynamically reconfiguring classes - using "variables" being one of them - the probelm is that doing it in this naive way you want, you'd ahve pretty soon an unmaintainable mess.
For example, if you just use a module-level (= global) variable for "1" instead of hardcoding it into A, you could do:
CURRENT_ATR_VALUE = 1
class A(object):
def __init__(self):
self.atr = CURRENT_ATR_VALUE
class B(object):
def __init__(self):
self.atr = A()
class C(object):
def __init__(self):
self.atr = A()
class D(object):
def __init__(self, atr):
global CURRENT_ATR_VALUE
old = CURRENT_ATR_VALUE
CURRENT_ATR_VALUE = atr
self.atr1 = B()
self.atr2 = C()
CURRENT_ATR_VALUE = old
test1 = D(atr=2)
This would have thge exact effect you are intending, could not be simpler - whithout requiring any of the Language's advanced introspection capabilities, and still would lead you soon to an unmaintainable mess. The way passing parameters around does contain the custom values in the scopes they are wanted, without side-effects, not even in a multi-threading or multi-processing running environment, and is far more recomendable.
If you really want to mess things around, you could create a factory function that would produce a new class "A" with the desired attributes, and inject it in the module global namespace as a new "A" class while you instantiate the others - that would be "fancier" and maybe is what you'd like. Just write A inside something like:
def A_factory(atr=1):
class A(object):
def __init__(self, atr=1):
self.atr = atr
globals()["A"] = A
# creates default "A" class
A_factory(1)
And call this factory with your desired "atr" while instantiating "B" and "C" as above. This is absolutely unmanageable, but it is ultimately what you are asking for. T

Python : Set method attribute from within method

I am trying to make a python decorator that adds attributes to methods of a class so that I can access and modify those attributes from within the method itself. The decorator code is
from types import MethodType
class attribute(object):
def __init__(self, **attributes):
self.attributes = attributes
def __call__(self, function):
class override(object):
def __init__(self, function, attributes):
self.__function = function
for att in attributes:
setattr(self, att, attributes[att])
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, owner):
return MethodType(self, instance, owner)
retval = override(function, self.attributes)
return retval
I tried this decorator on the toy example that follows.
class bar(object):
#attribute(a=2)
def foo(self):
print self.foo.a
self.foo.a = 1
Though I am able to access the value of attribute 'a' from within foo(), I can't set it to another value. Indeed, when I call bar().foo(), I get the following AttributeError.
AttributeError: 'instancemethod' object has no attribute 'a'
Why is this? More importantly how can I achieve my goal?
Edit
Just to be more specific, I am trying to find a simple way to implement static variable that are located within class methods. Continuing from the example above, I would like instantiate b = bar(), call both foo() and doo() methods and then access b.foo.a and b.doo.a later on.
class bar(object):
#attribute(a=2)
def foo(self):
self.foo.a = 1
#attribute(a=4)
def doo(self):
self.foo.a = 3
The best way to do this is to not do it at all.
First of all, there is no need for an attribute decorator; you can just assign it yourself:
class bar(object):
def foo(self):
print self.foo.a
self.foo.a = 1
foo.a = 2
However, this still encounters the same errors. You need to do:
self.foo.__dict__['a'] = 1
You can instead use a metaclass...but that gets messy quickly.
On the other hand, there are cleaner alternatives.
You can use defaults:
def foo(self, a):
print a[0]
a[0] = 2
foo.func_defaults = foo.func_defaults[:-1] + ([2],)
Of course, my preferred way is to avoid this altogether and use a callable class ("functor" in C++ words):
class bar(object):
def __init__(self):
self.foo = self.foo_method(self)
class foo_method(object):
def __init__(self, bar):
self.bar = bar
self.a = 2
def __call__(self):
print self.a
self.a = 1
Or just use classic class attributes:
class bar(object):
def __init__(self):
self.a = 1
def foo(self):
print self.a
self.a = 2
If it's that you want to hide a from derived classes, use whatever private attributes are called in Python terminology:
class bar(object):
def __init__(self):
self.__a = 1 # this will be implicitly mangled as __bar__a or similar
def foo(self):
print self.__a
self.__a = 2
EDIT: You want static attributes?
class bar(object):
a = 1
def foo(self):
print self.a
self.a = 2
EDIT 2: If you want static attributes visible to only the current function, you can use PyExt's modify_function:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
#wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
It's slightly ugly and hackish. But it works.
My recommendation would be just to use double underscores:
class bar(object):
__a = 1
def foo(self):
print self.__a
self.__a = 2
Although this is visible to the other functions, it's invisible to anything else (actually, it's there, but it's mangled).
FINAL EDIT: Use this:
import pyext
def wrap_mod(*args, **kw):
def inner(f):
return pyext.modify_function(f, *args, **kw)
return inner
class bar(object):
#wrap_mod(globals={'a': [1]})
def foo(self):
print a[0]
a[0] = 2
foo.a = foo.func_globals['a']
b = bar()
b.foo() # prints 1
b.foo() # prints 2
# external access
b.foo.a[0] = 77
b.foo() # prints 77
While You can accomplish Your goal by replacing self.foo.a = 1 with self.foo.__dict__['a'] = 1 it is generally not recommended.
If you are using Python2 - (and not Python3) - whenever you retrieve a method from an instance, a new instance method object is created which is a wrapper to the original function defined in the class body.
The instance method is a rather transparent proxy to the function - you can retrieve the function's attributes through it, but not set them - that is why setting an item in self.foo.__dict__ works.
Alternatively you can reach the function object itself using: self.foo.im_func - the im_func attribute of instance methods point the underlying function.
Based on other contributors's answers, I came up with the following workaround. First, wrap a dictionnary in a class resolving non-existant attributes to the wrapped dictionnary such as the following code.
class DictWrapper(object):
def __init__(self, d):
self.d = d
def __getattr__(self, key):
return self.d[key]
Credits to Lucas Jones for this code.
Then implement a addstatic decorator with a statics attribute that will store the static attributes.
class addstatic(object):
def __init__(self, **statics):
self.statics = statics
def __call__(self, function):
class override(object):
def __init__(self, function, statics):
self.__function = function
self.statics = DictWrapper(statics)
def __call__(self, *args, **kwargs):
return self.__function(*args, **kwargs)
def __get__(self, instance, objtype):
from types import MethodType
return MethodType(self, instance)
retval = override(function, self.statics)
return retval
The following code is an example of how the addstatic decorator can be used on methods.
class bar(object):
#attribute(a=2, b=3)
def foo(self):
self.foo.statics.a = 1
self.foo.statics.b = 2
Then, playing with an instance of the bar class yields :
>>> b = bar()
>>> b.foo.statics.a
2
>>> b.foo.statics.b
3
>>> b.foo()
>>> b.foo.statics.a
3
>>> b.foo.statics.b
5
The reason for using this statics dictionnary follows jsbueno's answer which suggest that what I want would require overloading the dot operator of and instance method wrapping the foo function, which I am not sure is possible. Of course, the method's attribute could be set in self.foo.__dict__, but since it not recommended (as suggested by brainovergrow), I came up with this workaround. I am not certain this would be recommended either and I guess it is up for comments.

How can I call methods between two classes?

I have a class A. During the __init__ method of an instance of A;
I create these following two instances of classes B and C:
b = B()
c = C()
Once all's set, I need to call, within a method of B, a method from C.
Example:
Triggered:
b.call_c()
Does:
def call_c(self):
parent.c.a_method_of_c()
What do I need to do to achieve this structure?
You need to pass either of self or c to B() so that it can know about the other object.
Here is how this looks if you pass the A object to both B and C as a parent/container object:
class A(object):
def __init__(self):
self.b = B(self)
self.c = C(self)
class B(object):
def __init__(self, parent):
self.parent = parent
def call_c(self):
self.parent.c.a_method_of_c()
class C(object):
def __init__(self, parent):
self.parent = parent
# whatever...
Or, you can just pass the C instance to B's initializer like this:
class A(object):
def __init__(self):
self.c = C()
self.b = B(self.c)
class B(object):
def __init__(self, c):
self.cobj = c
def call_c(self):
self.cobj.a_method_of_c()
class C(object):
# whatever...
I like the second approach better, since it cuts out the dependencies of B and C on A, and the necessity of A to implement b and c attributes.
If B and C have to call methods on each other, you can still use A to make these associations, but keep B and C ignorant of A:
class A(object):
def __init__(self):
self.b = B()
self.c = C()
self.b.cobj = self.c
self.c.bobj = self.b
class B(object):
def __init__(self, c):
self.cobj = None
def call_c(self):
if self.cobj is not None:
self.cobj.a_method_of_c()
else:
raise Exception("B instance not fully initialized")
class C(object):
# similar to B
In general, your goal is to try to avoid or at least minimize these dependencies - have a parent know about a child, but a child be ignorant of the parent. Or a container knows its contained objects, but the contained objects do not know their container. Once you add circular references (back references to a parent or container object), things can get ugly in all kinds of surprising ways. A relationship can get corrupted when one of the links gets cleared but not the reflecting link. Or garbage-collection in circular relations can get tricky (handled in Python itself, but may not be handled if these objects and relations are persisted or replicated in a framework).
I need to call, within a method of B, a method from C.
Basically, if the method is not a class method or a static method, then calling a method always means that you have access to the (c) object of the C class.
Have a look at the example:
#!python3
class B:
def __init__(self, value):
self.value = value
def __str__(self):
return 'class B object with the value ' + str(self.value)
class C:
def __init__(self, value):
self.value = value
def __str__(self):
return 'class C object with the value ' + str(self.value)
class A:
def __init__(self, value):
self.value = value
self.b = B(value * 2)
self.c = C(value * 3)
def __str__(self):
lst = ['class A object with the value ' + str(self.value),
' containing the ' + self.b.__str__(),
' containing also the ' + str(self.c),
]
return '\n'.join(lst)
a = A(1)
print(a)
print(a.b)
print(a.c)
The self.b.__str__() is the example of calling the method of the object of the B class from the method of the object of the A class. The str(self.c) is the same, only called indirectly via the str() function.
The following is displayed:
class A object with the value 1
containing the class B object with the value 2
containing also the class C object with the value 3
class B object with the value 2
class C object with the value 3

Categories

Resources