Use method within class to define a global variable - python

class Foo:
def add(self, a, b):
return (a+b)
def sub(self, a, b):
return (a-b)
C = add(1,2)
TypeError: add() missing 1 required positional argument: 'b'
How can I use a method within that class? When using a method within the class it is defined in, what should I pass in for the 'self' parameter?

I'm not too sure what you're getting at. The summary and description don't seem to match. I'll try to answer both to the best of my ability though.
GLOBAL_VAR = int()
class Foo:
def add(self, a, b):
return (a+b)
#staticmethod
def sub(a, b):
return (a - b)
def call_add(self, *args):
global GLOBAL_VAR
GLOBAL_VAR = self.add(*args)
C = Foo().add(1, 2)
D = Foo.sub(1, 2)
Foo().call_add(1, 2)
print(GLOBAL_VAR, C, D)
So the explanation.
If you want to update a global variable in a class method you have to bring it into the method with the it with the global keyword
if you want to access a class method you have to instantiate the class in the C = Foo().method() example
if you just want to call the method directly you can remove self and make it a static method in the D = Foo.sub() example.
if you want to call add in the class you need to call self.add
Hope that helps!

Related

Calling an object of a method of a class within another method of the same class

I was trying to call the objects of a method in one of my classes within antoher method of the same class. Below you can find a small example of how I tried to do it:
class example_class():
def some_method(self):
#... calculate something ...
a = 1
b = 2
def second_method(self):
call = self.some_method()
c = call.a + call.b
If I do this, I get the error: "'NoneType' object has no attribute 'a'".
I am sure this is a fearly basic problem, but I am using classes, objects and methods for the first time and would really appreciate the help!
Thank you in advance and stay safe!
class example_class():
def some_method(self):
#... calculate something ...
self.a = 1
self.b = 2
def second_method(self):
# call = self.some_method()
c = self.a + self.b
This should work
class example_class:
def some_method(self):
self.a = 1
self.b = 2
def second_method(self):
self.some_method()
print(self.a + self.b)
You can't access a method's local variables from another method, you should store them as attributes.

Override use self variables only if they are not defined in Python Class

I have a question on Python Classes, is there a more Pythonic way to do the following?
I have a class where I define some class variables, but when I class a class function, I'd like to be able to override some of the variables and if I don't, I'd like to use the 'self' version.
Here is a simple example (in my actual code, my class as a lot of variables that could be overridden hence I want to find a better way to do this):
class MyClass:
def __init__ (self, A, B):
self.A = A
self.B = B
def calc_C (self, A=False, B=False):
if A == False :
A = self.A
if B == False :
B = self.B
return A * B
x = MyClass(5, 6)
This return 30:
x.calc_C()
This return 5:
x.calc_C(B=1)
Appreciate any advice. Thank you
If you have many such variables, a decorator might come in handy to do this self-based default operation:
Here is the decorator:
import inspect
def selfy(func):
def wrapper(*args, **kwargs):
# Extract the "self"
self, = args
# Get the parameters the function "func" accepts
sig = inspect.signature(func)
params = [param for param in sig.parameters if param != "self"] # ["A", "B"]
# Make the selfified version of arguments
selfed_kwargs = {var: kwargs.get(var, getattr(self, var)) for var in params}
# Call the function with this "selfifed" arguments
return func(*args, **selfed_kwargs)
return wrapper
And the class will look like:
class MyClass:
def __init__ (self, A, B):
self.A = A
self.B = B
#selfy
def calc_C (self, A=None, B=None):
return A * B
and you can call the method with keyword arguments however you like:
x = MyClass(5, 6)
x.calc_C() # 5*6 = 30
x.calc_C(A=12) # 12*6 = 72
x.calc_C(B=-7) # 5*-7 = -35
x.calc_C(A=4, B=9) # 4*9 = 36
How does it work?
The decorator selfy has an access to how the function of interest is called. All the arguments and keyword arguments are accessible in *args and **kwargs.
If, for example, we call x.calc_C(A=12), then args is a 1-tuple containing x instance; and kwargs is a dict as {"A": 12}. Now, with the help of inspect.signature, we access to the function signature (that of calc_C) and get the parameter names as a list ["self", "A", "B"].
Here, we are interested in explicit parameters i.e. A and B. Now all we need to do is look at each of these parameters and get their value from the keyword arguments dict passed by user i.e. the dict {"A": 12} if it is there; or get it from the self. This is what kwargs.get(var, getattr(self, var)) does.
For example, when var is "A", we get 12 as it exists in kwargs dict. But for "B", since it does not exist in kwargs dict, .get returns its second argument i.e. self.B (this is by getattr).
You might add a lot of variables as you wish to calc_C.

Using classmethods to implement alternative constructors, how can I add functions to those alternative constructors?

I have an class that can be constructed via alternative constructors using class methods.
class A:
def __init__(self, a, b):
self.a = a
self.b = b
#classmethod
def empty(cls, b):
return cls( 0 , b)
So let's say instead of constructing A like A() I can now also do A.empty().
For user convenience, I would like to extend this empty method even further, so that I can initialize A via A.empty() as well as the more specialized but closely-related A.empty.typeI() and A.empty.typeII().
My naive approach did not quite do what I wanted:
class A:
def __init__(self, a, b):
self.a = a
self.b = b
#classmethod
def empty(cls, b):
def TypeI(b):
return cls( 0 , b-1)
def TypeII(b):
return cls( 0 , b-2)
return cls( 0 , b)
Can anyone tell me how that could be done (or at least convince me why that would be terrible idea). I want to stress that for usage I imagine such an approach to be very convenient and clear for the users as the functions are grouped intuitively.
You can implement what you want by making Empty a nested class of A rather than a class method. More than anything else this provides a convenient namespace — instances of it are never created — in which to place various alternative constructors and can easily be extended.
class A(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return 'A({}, {})'.format(self.a, self.b)
class Empty(object): # nested class
def __new__(cls, b):
return A(0, b) # ignore cls & return instance of enclosing class
#staticmethod
def TypeI(b):
return A(0, b-1)
#staticmethod
def TypeII(b):
return A(0, b-2)
a = A(1, 1)
print('a: {}'.format(a)) # --> a: A(1, 1)
b = A.Empty(2)
print('b: {}'.format(b)) # --> b: A(0, 2)
bi = A.Empty.TypeI(4)
print('bi: {}'.format(bi)) # --> bi: A(0, 3)
bii = A.Empty.TypeII(6)
print('bii: {}'.format(bii)) # --> bii: A(0, 4)
You can’t really do that because A.empty.something would require the underlying method object to be bound to the type, so you can actually call it. And Python simply won’t do that because the type’s member is empty, not TypeI.
So what you would need to do is to have some object empty (for example a SimpleNamespace) in your type which returns bound classmethods. The problem is that we cannot yet access the type as we define it with the class structure. So we cannot access its members to set up such an object. Instead, we would have to do it afterwards:
class A:
def __init__ (self, a, b):
self.a = a
self.b = b
#classmethod
def _empty_a (cls, b):
return cls(1, b)
#classmethod
def _empty_b (cls, b):
return cls(2, b)
A.empty = SimpleNamespace(a = A._empty_a, b = A._empty_b)
Now, you can access that member’s items and get bound methods:
>>> A.empty.a
<bound method type._empty_a of <class '__main__.A'>>
>>> A.empty.a('foo').a
1
Of course, that isn’t really that pretty. Ideally, we want to set this up when we define the type. We could use meta classes for this but we can actually solve this easily using a class decorator. For example this one:
def delegateMember (name, members):
def classDecorator (cls):
mapping = { m: getattr(cls, '_' + m) for m in members }
setattr(cls, name, SimpleNamespace(**mapping))
return cls
return classDecorator
#delegateMember('empty', ['empty_a', 'empty_b'])
class A:
def __init__ (self, a, b):
self.a = a
self.b = b
#classmethod
def _empty_a (cls, b):
return cls(1, b)
#classmethod
def _empty_b (cls, b):
return cls(2, b)
And magically, it works:
>>> A.empty.empty_a
<bound method type._empty_a of <class '__main__.A'>>
Now that we got it working somehow, of course we should discuss whether this is actually something you want to do. My opinion is that you shouldn’t. You can already see from the effort it took that this isn’t something that’s usually done in Python. And that’s already a good sign that you shouldn’t do it. Explicit is better than implicit, so it’s probably a better idea to just expect your users to type the full name of the class method. My example above was of course structured in a way that A.empty.empty_a would have been longer than just a A.empty_a. But even with your name, there isn’t a reason why it couldn’t be just an underscore instead of a dot.
And also, you can simply add multiple default paths inside a single method. Provide default argument values, or use sensible fallbacks, and you probably don’t need many class methods to create alternative versions of your type.
It is generally better to have uniform class interfaces, meaning the different usages should be consistent with each other. I consider A.empty() and A.empty.type1() to be inconsistent with each other, because the prefix A.empty ituitively means different things in each of them.
A better interface would be:
class A:
#classmethod
def empty_default(cls, ...): ...
#classmethod
def empty_type1(cls, ...): ...
#classmethod
def empty_type2(cls, ...): ...
Or:
class A:
#classmethod
def empty(cls, empty_type, ...): ...
Here's an enhanced implementation of my other answer that makes it — as one commenter put it — "play well with inheritance". You may not need this, but others doing something similar might.
It accomplishes this by using a metaclass to dynamically create and add an nested Empty class similar to that shown in the other answer. The main difference is that the default Empty class in derived classes will now return Derived instances instead of instances of A, the base class.
Derived classes can override this default behavior by defining their own nested Empty class (it can even be derived from the one in the one in the base class). Also note that for Python 3, metaclasses are specified using different syntax:
class A(object, metaclass=MyMetaClass):
Here's the revised implementation using Python 2 metaclass syntax:
class MyMetaClass(type):
def __new__(metaclass, name, bases, classdict):
# create the class normally
MyClass = super(MyMetaClass, metaclass).__new__(metaclass, name, bases,
classdict)
# add a default nested Empty class if one wasn't defined
if 'Empty' not in classdict:
class Empty(object):
def __new__(cls, b):
return MyClass(0, b)
#staticmethod
def TypeI(b):
return MyClass(0, b-1)
#staticmethod
def TypeII(b):
return MyClass(0, b-2)
setattr(MyClass, 'Empty', Empty)
return MyClass
class A(object):
__metaclass__ = MyMetaClass
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return '{}({}, {})'.format(self.__class__.__name__, self.a, self.b)
a = A(1, 1)
print('a: {}'.format(a)) # --> a: A(1, 1)
b = A.Empty(2)
print('b: {}'.format(b)) # --> b: A(0, 2)
bi = A.Empty.TypeI(4)
print('bi: {}'.format(bi)) # --> bi: A(0, 3)
bii = A.Empty.TypeII(6)
print('bii: {}'.format(bii)) # --> bii: A(0, 4)
With the above, you can now do something like this:
class Derived(A):
pass # inherits everything, except it will get a custom Empty
d = Derived(1, 2)
print('d: {}'.format(d)) # --> d: Derived(1, 2)
e = Derived.Empty(3)
print('e: {}'.format(e)) # --> e: Derived(0, 3)
ei = Derived.Empty.TypeI(5)
print('ei: {}'.format(ei)) # --> ei: Derived(0, 4)
eii = Derived.Empty.TypeII(7)
print('eii: {}'.format(eii)) # --> eii: Derived(0, 5)

Dynamically update attributes of an object that depend on the state of other attributes of same object

Say I have an class that looks like this:
class Test(object):
def __init__(self, a, b):
self.a = a
self.b = b
self.c = self.a + self.b
I would like the value of self.c to change whenever the value of attributes self.a or self.b changes for the same instance.
e.g.
test1 = Test(2,4)
print test1.c # prints 6
test1.a = 3
print test1.c # prints = 6
I know why it would still print 6, but is there a mechanism I could use to fire an update to self.c when self.a has changed. Or the only option I have is to have a method that returns me the value of self.c based on the current state of self.a and self.b
Yes, there is! It's called properties.
Read Only Properties
class Test(object):
def __init__(self,a,b):
self.a = a
self.b = b
#property
def c(self):
return self.a + self.b
With the above code, c is now a read-only property of the Test class.
Mutable Properties
You can also give a property a setter, which would make it read/write and allow you to set its value directly. It would look like this:
class Test(object):
def __init__(self, c = SomeDefaultValue):
self._c = SomeDefaultValue
#property
def c(self):
return self._c
#c.setter
def c(self,value):
self._c = value
However, in this case, it would not make sense to have a setter for self.c, since its value depends on self.a and self.b.
What does #property mean?
The #property bit is an example of something called a decorator. A decorator actually wraps the function (or class) it decorates into another function (the decorator function). After a function has been decorated, when it is called it is actually the decorator that is called with the function (and its arguments) as an argument. Usually (but not always!) the decorated function does something interesting, and then calls the original (decorated) function like it would normally. For example:
def my_decorator(thedecoratedfunction):
def wrapped(*allofthearguments):
print("This function has been decorated!") #something interesting
thedecoratedfunction(*allofthearguments) #calls the function as normal
return wrapped
#my_decorator
def myfunction(arg1, arg2):
pass
This is equivalent to:
def myfunction(arg1, arg2):
pass
myfunction = my_decorator(myfunction)
So this means in the class example above, instead of using the decorator you could also do this:
def c(self):
return self.a + self.b
c = property(c)
They are exactly the same thing. The #property is just syntactic sugar to replace calls for myobject.c with the property getter and setter (deleters are also an option).
Wait - How does that work?
You might be wondering why simply doing this once:
myfunction = my_decorator(myfunction)
...results in such a drastic change! So that, from now on, when calling:
myfunction(arg1, arg2)
...you are actually calling my_decorator(myfunction), with arg1, arg2 sent to the interior wrapped function inside of my_decorator. And not only that, but all of this happens even though you didn't even mention my_decorator or wrapped in your function call at all!
All of this works by virtue of something called a closure. When the function is passed into the decorator in this way (e.g., property(c)), the function's name is re-bound to the wrapped version of the function instead of the original function, and the original function's arguments are always passed to wrapped instead of the original function. This is simply the way that closures work, and there's nothing magical about it. Here is some more information about closures.
Descriptors
So to summarize so far: #property is just a way of wrapping the class method inside of the property() function so the wrapped class method is called instead of the original, unwrapped class method. But what is the property function? What does it do?
The property function adds something called a descriptor to the class. Put simply, a descriptor is an object class that can have separate get, set, and delete methods. When you do this:
#property
def c(self):
return self._c
...you are adding a descriptor to the Test class called c, and defining the get method (actually, __get__()) of the c descriptor as equal to the c(self) method.
When you do this:
#c.setter
def c(self,value):
self._c
...you are defining the set method (actually, __set__()) of the c descriptor as equal to the c(self,value) method.
Summary
An amazing amount of stuff is accomplished by simply adding #property to your def c(self) method! In practice, you probably don't need to understand all of this right away to begin using it. However, I recommend keeping in mind that when you use #property, you are using decorators, closures, and descriptors, and if you are at all serious about learning Python it would be well worth your time to investigate each of these topics on their own.
The simplest solution is to make c a read-only property:
class Test(object):
def __init__(self, a, b):
self.a = a
self.b = b
#property
def c(self):
return self.a + self.b
Now every time you access test_instance.c, it calls the property getter and calculates the appropriate value from the other attributes. In use:
>>> t = Test(2, 4)
>>> t.c
6
>>> t.a = 3
>>> t.c
7
Note that this means that you cannot set c directly:
>>> t.c = 6
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
t.c = 6
AttributeError: can't set attribute

How to instantiate a class function for not instantiated objects?

Does anyone know if there is a way to instantiate a function of a class for not yet instantiated objects in Python? I would like something like this:
class C():
def __init__(self, var):
self.var = var
def f1(self):
self.var += 1
def f2(self):
self.var += 2
cond = True
if cond : f = C.f1
else: f = C.f2
for i in xrange(1e7):
a = C(1)
for j in xrange(1e3):
a.f()
The goal is to be able to use 'f' as 'min', 'max' or 'mean' for nparrays at the beginning and not checking at each loops which function to use.
The types of a and b are numpy.ndarray. You have imported ndarray, so you can simply call ndarray.min on a and b:
f = ndarray.min
print f(a), f(b)
Here, ndarray.min(x) is equivalent to x.min().
Edit getting the numpy.ndarray.min without explicit knowledge of the type of a call to rand:
f = type(rand(int())).min
Note that you still need to know that this type has a min function.
One does not "instantiate" a function; one instantiates objects, as instances of classes.
Now, one simply calls a class method of a class klass by calling the method on the class: klass.method(foo).
If rand.min is a function which can be called on a, then one would simply do rand.min(a) or f(a).

Categories

Resources