How to surely refer to global objects in a class during definition? - python

While defining a class, I need to set a global function (say, abc) as default arg value on a method. Usually, its just trivial to refer to them as abc.
But problem here is that abc is itself set as a classmethod on that class. So, the
usual soln doesnt work as abc refers to "abc, the classmethod" during class definition when "abcd" is being created. One soln might be to re-order things such that the classmethod defn. comes at the last, but I need a sure-shot (order-agnostic) way of refering to the global abc there.
There is only one crude way of doing it, that I know of, using globals()["abc"]. I want to know if theres a better way of tackling this problem.
def abc(cls,a=1):
print a+1
class A(object):
abc=classmethod(abc)
#classmethod
def abcd(cls,func=abc):
pass
from inspect import getargspec
getargspec(A.abcd).defaults[0] #should be "abc" the function, not "abc" classmethod
Possible (but not so good ?) soln
def abcd(cls,func=globals()["abc"])
Edit:
Also, do you think globals() is quite slow?

Wrap abc and similar use case options in their own namespace, like so
class A:
#staticmethod
def abc(cls, *args, **kwargs):
pass
Then you can refer to them cleanly
class Foo:
abc = classmethod(A.abc)
#classmethod
def abcd(cls, fn=A.abc):
pass
And order is not important.
You could also consider these workarounds:
Avoid name collisions:
def _abc(cls, *args, **kwargs):
pass
class Foo:
abc = classmethod(_abc)
#classmethod
def abcd(cls, fn=_abc):
pass
Do all affected defs outside of class:
def abc(cls, *args, **kwargs):
pass
def abcd(cls, fn=abc):
pass
class Foo:
abc = classmethod(abc)
abcd = classmethod(abcd)

Here's a way:
def abc(cls,a=1):
print a+1
class A(object):
#classmethod
def abcd(cls,func=abc):
pass
A.abc=classmethod(abc)
It's up to you whether this is "better" than using globals.

Related

How to initialize a class member using a classmethod

I have a class, which holds some member x (say, some data that is needed by all instances, but independent of them):
class Foo(object):
x = 23
# some more code goes here
Now, the procedure of determining x became more complex plus I wanted to be able to "refresh" x at certain times, so I decided to write an extra function for it
class Foo(object):
#classmethod
def generate_x(cls):
cls.x = 23
# some more code goes here
However, this class definition lacks an initialization call of generate_x.
What I tried so far:
This does not work:
class Foo(object):
# generate_x() # NameError: name 'generate_x' is not defined
# Foo.generate_x() # NameError: name 'Foo' is not defined
#classmethod
def generate_x(cls):
cls.x = 23
This works but less clear, because code is used outside the class definition
class Foo(object):
#classmethod
def generate_x(cls):
cls.x = 23
# ...
Foo.generate_x()
Are there better alternatives to this? Is using #classmethod the best approach here? What I'm searching is a class-equivalent of __init__.
Considering code clarity, is there a better way than the latter to instantiate Foo.x automatically using a function?
One way to achieve this is by using a decorator:
def with_x(cls):
cls.generate_x()
return cls
#with_x
class Foo(object):
#classmethod
def generate_x(cls):
cls.x = 23
(That said, I personally would just call Foo.generate_x explicitly after the class declaration, and avoid all the magic altogether.)
Use a descriptor.
class Complicated:
def __init__(self, location, get_value):
self.location =location
self.get_value = staticmethod(get_value)
def __get__(self, obj, owner):
try:
a = getattr(owner, self.location)
except AttributeError:
a = self.get_value()
setattr(owner, self.location, a)
return a
class My class:
x = Complicated ('_x', get_x)

Dynamically add class methods during class definition

I have a bunch of methods somewhere, already defined. I want a class to just be a collection of those methods.
def _a(self):
pass
def _b(self):
pass
#decorated()
class MyClass(object):
a = _a
b = _b
The decorator is written by someone else, and it does some analysis on the class immediately.
What I want is to stick those methods on the class, but they need to be on there before the decorator does its magic.
methods = { 'a': _a, 'b': _b }
#decorated(...)
class MyClass(object):
for name, impl in methods
# What goes here?
How can I do this. I assume it's some form of setattr(), but how do I get the target when it's the class I'm currently building?
Update
Current experiment is:
def merged(method_dict):
def _impl(cls):
for name, impl in method_dict.iteritems():
setattr(cls, name, impl)
return cls
return _impl
#decorated(...)
#merged(methods)
class MyClass(object):
c = _c
pass
The decorated decorator is reporting that it sees c, but not a or b
The problem is that as soon as your class is defined, it is immediately getting decorated, as you use the # syntax. Some alternatives are to go the way jonrsharpe and Ashwini Chaudhary suggested.
Also, another way you can do the thing, is wrapping the decorator into your custom one, where you will do your stuff and then only, manually decorate with the provided one, like this:
def your_decorator(func):
# your stuff
return decorated(func)
#your_decorator
class MyClass():
# ...
I'd go with what jonrsharpe suggested in the comments section: Instead of decorating the class using the # syntax, which decorates the class immediately after it's created, you should decorate it manually afterwards:
class MyClass:
pass
def _method_to_add_later(self):
pass
MyClass.method_to_add_later = _method_to_add_later
MyClass = decorated(...)(MyClass)
For example, may be right
def decorator(fn):
def _fn(*args, **kwargs):
print "Decorator"
fn(*args, **kwargs)
return _fn
#decorator
class MyClass(object):
def __init__(self):
print "Init"
def _a():
print "a"
def _b():
print "b"
if __name__ == '__main__':
methods = { 'a': _a, 'b': _b }
my = decorator(MyClass())
for name in methods:
setattr(my, name, methods[name])
my.a()
my.b()
Out:
Decorator
Init
a
b

Python: How to update the calls of a third class to the overriden method of the original class?

class ThirdPartyA(object):
def __init__(self):
...
def ...():
...
-------------------
from xxx import ThirdPartyA
class ThirdPartyB(object):
def a(self):
...
#call to ThirdPartyA
....
def b(self):
...
#call to ThirdPartyA
...
def c(self):
...
#call to ThirdPartyA
...
-----------------------------------
from xxx import ThirdPartyA
class MyCodeA(ThirdPartyA):
def __init__(self):
# overriding code
When overriding the __init__ method of A class, how could I instruct B class that it should call MyCodeA instead of ThirdPartyA in all its methods?
The real code is here:
CLass Geoposition: ThirdPartyA
Class GeopositionField: ThirdPartyB
My override to class Geoposition so it returns max 5 decimal digits:
class AccuracyGeoposition(Geoposition):
def __init__(self, latitude, longitude):
if isinstance(latitude, float) or isinstance(latitude, int):
latitude = '{0:.5f}'.format(latitude)
if isinstance(longitude, float) or isinstance(longitude, int):
longitude = '{0:.5f}'.format(longitude)
self.latitude = Decimal(latitude)
self.longitude = Decimal(longitude)
From your updated code, I think what you're trying to do is change GeopositionField. to_python() so that it returns AccuracyGeoposition values instead of Geoposition values.
There's no way to do that directly; the code in GeopositionField explicitly says it wants to construct a Geoposition, so that's what happens.
The cleanest solution is to subclass GeopositionField as well, so you can wrap that method:
class AccuracyGeopositionField(GeopositionField):
def topython(self, value):
geo = super(AccuracyGeopositionField, self).topython(value)
return AccuracyGeoposition(geo.latitude, geo.longitude)
If creating a Geoposition and then re-wrapping the values in an AccuracyGeoposition is insufficient (because accuracy has already been lost), you might be able to pre-process things before calling the super method as well/instead. For example, if the way it deals with list is not acceptable (I realize that's not true here, but it serves as a simple example), but everything else you can just let it do its thing and wrap the result, you could do this:
class AccuracyGeopositionField(GeopositionField):
def topython(self, value):
if isinstance(value, list):
return AccuracyGeoposition(value[0], value[1])
geo = super(AccuracyGeopositionField, self).topython(value)
return AccuracyGeoposition(geo.latitude, geo.longitude)
If worst comes to worst, you may have to reimplement the entire method (maybe by copying, pasting, and modifying its code), but hopefully that will rarely come up.
There are hacky alternatives to this. For example, you could monkeypatch the module to globally replace the Geoposition class with your AccuracyGeoposition class But, while that may save some work up front, you're almost certain to be unhappy with it when you're debugging things later. Systems that are designed for aspect-oriented programming (which is basically controlled monkeypatching) are great, but trying to cram it into systems that were designed to resist it will give you headaches.
Assuming your real code works like your example—that is, every method of B creates a new A instance just to call a method on it and discard it—well, that's a very weird design, but if it makes sense for your use case, you can make it work.
The key here is that classes are first-class objects. Instead of hardcoding A, store the class you want as a member of the B instance, like this:
class B(object):
def __init__(self, aclass=A):
self.aclass = aclass
def a(self):
self.aclass().a()
Now, you just create a B instance with your subclass:
b = B(OverriddenA)
Your edited version does a different strange thing: instead of constructing a new A instance each time to call methods on it, you're calling class methods on A itself. Again, this is probably not what you want—but, if it is, you can do it:
class B(object):
def __init__(self, aclass=A):
self.aclass = aclass
def a(self):
self.aclass.a()
However, more likely you don't really want either of these. You want to take an A instance at construction time, store it, and use it repeatedly. Like this:
class B(object):
def __init__(self, ainstance):
self.ainstance = ainstance
def a(self):
self.ainstance.a()
b1 = B(A())
b2 = B(OverriddenA())
If this all seems abstract and hard to understand… well, that's because we're using meaningless names like A, B, and OverriddenA. If you tell us the actual types you're thinking about, or just plug those types in mechanically, it should make a lot more sense.
For example:
class Vehicle(object):
def move(self):
print('I am a vehicle, and I am moving')
class Operator(object):
def __init__(self, vehicle):
self.vehicle = vehicle
def move(self):
print('I am moving my vehicle')
self.vehicle.move()
class Car(object):
def move(self):
print('I am a car, and I am driving')
driver = Operator(Car())
driver.move()

Python Method overriding, does signature matter?

Lets say I have
class Super():
def method1():
pass
class Sub(Super):
def method1(param1, param2, param3):
stuff
Is this correct? Will calls to method1 always go to the sub class? My plan is to have 2 sub classes each override method1 with different params
In Python, methods are just key-value pairs in the dictionary attached to the class. When you are deriving a class from a base class, you are essentially saying that method name will be looked into first derived class dictionary and then in the base class dictionary. In order to "override" a method, you simply re-declare the method in the derived class.
So, what if you change the signature of the overridden method in the derived class? Everything works correctly if the call is on the derived instance but if you make the call on the base instance, you will get an error because the base class uses a different signature for that same method name.
There are however frequent scenarios where you want derived class method have additional parameters and you want method call work without error on base as well. This is called "Liskov substitution principle" (or LSP) which guarantees that if person switches from base to derived instance or vice versa, they don't have to revamp their code. To do this in Python, you need to design your base class with the following technique:
class Base:
# simply allow additional args in base class
def hello(self, name, *args, **kwargs):
print("Hello", name)
class Derived(Base):
# derived class also has unused optional args so people can
# derive new class from this class as well while maintaining LSP
def hello(self, name, age=None, *args, **kwargs):
super(Derived, self).hello(name, age, *args, **kwargs)
print('Your age is ', age)
b = Base()
d = Derived()
b.hello('Alice') # works on base, without additional params
b.hello('Bob', age=24) # works on base, with additional params
d.hello('Rick') # works on derived, without additional params
d.hello('John', age=30) # works on derived, with additional params
Above will print:
Hello Alice
Hello Bob
Hello Rick
Your age is None
Hello John
Your age is 30
.
Play with this code
Python will allow this, but if method1() is intended to be executed from external code then you may want to reconsider this, as it violates LSP and so won't always work properly.
You could do something like this if it's ok to use default arguments:
>>> class Super():
... def method1(self):
... print("Super")
...
>>> class Sub(Super):
... def method1(self, param1="X"):
... super(Sub, self).method1()
... print("Sub" + param1)
...
>>> sup = Super()
>>> sub = Sub()
>>> sup.method1()
Super
>>> sub.method1()
Super
SubX
In python, all class methods are "virtual" (in terms of C++). So, in the case of your code, if you'd like to call method1() in super class, it has to be:
class Super():
def method1(self):
pass
class Sub(Super):
def method1(self, param1, param2, param3):
super(Sub, self).method1() # a proxy object, see http://docs.python.org/library/functions.html#super
pass
And the method signature does matter. You can't call a method like this:
sub = Sub()
sub.method1()
It will work:
>>> class Foo(object):
... def Bar(self):
... print 'Foo'
... def Baz(self):
... self.Bar()
...
>>> class Foo2(Foo):
... def Bar(self):
... print 'Foo2'
...
>>> foo = Foo()
>>> foo.Baz()
Foo
>>>
>>> foo2 = Foo2()
>>> foo2.Baz()
Foo2
However, this isn't generally recommended. Take a look at S.Lott's answer: Methods with the same name and different arguments are a code smell.

Implementing the decorator pattern in Python

I want to implement the decorator pattern in Python, and I wondered if there is a way to write a decorator that just implements the function it wants to modify, without writing boiler-plate for all the functions that are just forwarded to the decorated object. Like so:
class foo(object):
def f1(self):
print "original f1"
def f2(self):
print "original f2"
class foo_decorator(object):
def __init__(self, decoratee):
self._decoratee = decoratee
def f1(self):
print "decorated f1"
self._decoratee.f1()
def f2(self): # I would like to leave that part out
self._decoratee.f2()
I would like to have calls to foo_decorator.f2 forwarded to decoratee.f2 automatically. Is there a way to write a generic method that forwards all unimplemented function-calls to decoratee?
You could use __getattr__:
class foo(object):
def f1(self):
print "original f1"
def f2(self):
print "original f2"
class foo_decorator(object):
def __init__(self, decoratee):
self._decoratee = decoratee
def f1(self):
print "decorated f1"
self._decoratee.f1()
def __getattr__(self, name):
return getattr(self._decoratee, name)
u = foo()
v = foo_decorator(u)
v.f1()
v.f2()
As an addendum to Philipp's answer; if you need to not only decorate, but preserve the type of an object, Python allows you to subclass an instance at runtime:
class foo(object):
def f1(self):
print "original f1"
def f2(self):
print "original f2"
class foo_decorator(object):
def __new__(cls, decoratee):
cls = type('decorated',
(foo_decorator, decoratee.__class__),
decoratee.__dict__)
return object.__new__(cls)
def f1(self):
print "decorated f1"
super(foo_decorator, self).f1()
u = foo()
v = foo_decorator(u)
v.f1()
v.f2()
print 'isinstance(v, foo) ==', isinstance(v, foo)
This is a bit more involved than strictly necessary for your example, where you know the class being decorated in advance.
This might suffice:
class foo_decorator(foo):
def __init__(self, decoratee):
self.__dict__.update(decoratee.__dict__)
def f1(self):
print "decorated f1"
super(foo_decorator, self).f1()
It's arguably not the best practice, but you can add functionality to instances, as I've done to help transition my code from Django's ORM to SQLAlachemy, as follows:
def _save(self):
session.add(self)
session.commit()
setattr(Base,'save',_save)
The UML diagram in the linked Wikipedia article is wrong and so is your code.
If you follow the "decorator pattern", the decorator class is derived from the base decorated class. (In the UML diagram an inheritance arrow from the WindowDecorator to Window is missing).
with
class foo_decorator(foo):
you don't need to implement undecorated methods.
BTW: In strong typed languages there is one more reason, why the decorator must be derived from the decorated class: Otherwise you wouldnt be able to chain decorators.
In one of my projects, I also needed to do one particular thing, that is that even the underlying object should actually execute the method that was reimplemented in the decorator. It is actually quite easy to do if you know where to target it.
The use case is:
I have an object X with methods A and B.
I create a decorator class Y that overrides A.
If I instantiate Y(X) and call A, it will use the decorated A as expected.
If B calls A, then if I instantiate Y(X) and call B on the decorator, the call from within B then goes to the old A on the original object which was undesirable. I want the old B to call the new A as well.
It is possible to reach this behaviour like this:
import inspect
import six # for handling 2-3 compatibility
class MyBaseDecorator(object):
def __init__(self, decorated):
self.decorated = decorated
def __getattr__(self, attr):
value = getattr(self.decorated, attr)
if inspect.ismethod(value):
function = six.get_method_function(value)
value = function.__get__(self, type(self))
return value
class SomeObject(object):
def a(self):
pass
def b(self):
pass
class MyDecorator(MyBaseDecorator):
def a(self):
pass
decorated = MyDecorator(SomeObject())
This may not work out of the box as I typed everything else apart from the getattr method from top of my head.
The code looks up the requested attribute in the decorated object, and if it is a method (doesn't work for properties now, but the change to support them should not be too difficult), the code then pulls the actual function out of the method and using the descriptor interface invocation it "rebinds" the function as a method, but on the decorator. Then it is returned and most likely executed.
The effect of this is that if b ever calls a on the original object, then when you have the object decorated and there is any method call coming from the decorator, the decorator makes sure that all methods accessed are bound to the decorator instead, therefore looking up things using the decorator and not the original object, therefore the methods specified in the decorator taking precedence.
P.S.: Yes I know it looks pretty much like inheritance, but this done in the sense of composition of multiple objects.
To complement #Alec Thomas reply. I modified his answer to follow the decorator pattern. This way you don't need to know the class you're decorating in advance.
class Decorator(object):
def __new__(cls, decoratee):
cls = type('decorated',
(cls, decoratee.__class__),
decoratee.__dict__)
return object.__new__(cls)
Then, you can use it as:
class SpecificDecorator(Decorator):
def f1(self):
print "decorated f1"
super(foo_decorator, self).f1()
class Decorated(object):
def f1(self):
print "original f1"
d = SpecificDecorator(Decorated())
d.f1()
In Python 3, Philipp's accepted answer raised RuntimeError: maximum recursion depth exceeded.
The way that worked for me:
class Foo(object):
def f1(self):
print("original f1")
def f2(self):
print("original f2")
class FooDecorator(object):
def __init__(self, decoratee):
self._decoratee = decoratee
def f1(self):
print("decorated f1")
return self._decoratee.f1()
def __getattr__(self, name):
if name in ['f1', '_decoratee']:
raise AttributeError()
return getattr(self._decoratee, name)
f = FooDecorator(Foo())
f.f1()
# decorated f1
# original f1
f.f2()
# original f2
The workaround is inspired by Ned Batchelder's blog

Categories

Resources