Python Class Variable Initialization - python

I'd like to store some information about a class as class (static) variables. However, I can't figure out how these things get initialized. Here is a basic, dumb example:
class A(object):
clsVar = 'a'
#classmethod
def clsMeth(cls):
print 'changing clsVar'
cls.clsVar = 'b'
A.clsMeth()
# prints 'changing clsVar'
print A.clsVar # prints 'a'
A.clsVar = 'b'
print A.clsVar # prints 'b'
Since the function got called (as the print statement worked), why didn't the class variable stay changed? Do I have to use a metaclass if I don't want to do it after the class definition completes?
[Specifically, I want clsMeth to be a decorator and have the class variable be a list of all the functions that were so decorated. I'm guessing this isn't the right way to go about accomplishing that, so I've moved on, but I'm still curious.]
EDIT: As numerous people have pointed out, the code above won't run. I was running it in an IPython session where the call to A.clsMeth() would refer to a previous version of A and run. Such are the risks of using an interpreted language, I guess. I ended up going with something like this:
outsideDict = {}
def outsideDec(func):
outsideDict[func.__name__] = func
class A(object):
#outsideDec
def someMethod(self):
print 'ID %s' % id(self)
def otherMethod(self):
print 'other'
print outsideDict
one, two = A(), A()
outsideDict['someMethod'](one)
outsideDict['someMethod'](two)
Perhaps this should be another question, but when outsideDec gets run, is there a way to tell what class it's argument is a member of? Or is there a better way of doing introspection like this in Python? I recognize I'm veering off course here so I'll accept the answer below and do more research. Thanks everyone!

The call to A.clsMeth() in the definition of A will not run, as A does not exist at that point:
>>> class A(object):
... clsVar = 'a'
... #classmethod
... def clsMeth(cls):
... print 'changing clsVar'
... cls.clsVar = 'b'
... A.clsMeth()
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in A
NameError: name 'A' is not defined
The code may have seemed to work if A had been defined previously (eg, if you were testing it out in the REPL), but the call to A.clsMeth would have been called on the old class, which would be shadowed by the new one.
However, we can definitely put that call after the definition and get the result you want:
>>> class A(object):
... clsVar = 'a'
... #classmethod
... def clsMeth(cls):
... print 'changing clsVar'
... cls.clsVar = 'b'
...
>>> A.clsMeth()
changing clsVar
>>> A.clsVar
'b'
Of course, as fabianhrj noted, you can put it in the constructor as well, but it won't be called until you create an instance.

Related

Why python understanding "self", "this" and "that"?

I am new to Python with Java background, the concept of "self" in function confuses me. I understand first argument "self" mean the object itself, but I do not understand how Python make this work. I also know that I could use "this" or "that" or "somethingElse", and Python would still understanding I mean to use the object.
I copied some code from a reddit post:
class A():
def __init__(self):
self.value = ""
def b(this):
this.value = "b"
def c(that):
that.value = "c"
a = A()
print(a.value)
a.b()
print(a.value)
>>>"b"
a.c()
print(a.value)
>>>"c"
How do python knows I do not mean to use an object here in the first argument? For example I modified the above code a bit:
class A():
def __init__(self):
self.value = ""
def b(this):
this.value = "b"
def c(that):
that.value = "c"
def somethingElse(someObjectIWantToPass):
someObjectIWantToPass.value = "still referring A.value"
class B():
def __init__(self):
self.value = ""
a = A()
print(a.value)
a.b()
print(a.value)
a.c()
print(a.value)
a.somethingElse()
print(a.value)
b = B()
a.somethingElse(b)
print (b.value)
And it broke:
b
c
still referring A.value
Traceback (most recent call last):
File "D:/Documents/test.py", line 32, in <module>
a.somethingElse(b)
TypeError: somethingElse() takes 1 positional argument but 2 were given
A method's first argument is always1 its instance. Calling it self is idiomatic in Python but that name is strictly convention.
class A():
def some_method(me): # not called `self`
print(str(id(me))
a = A()
a.some_method()
print(id(a))
If you're trying to pass another arbitrary object in, it has to be the second argument.
class B():
def another_method(self, other):
print(id(other))
b = B()
b.another_method(a)
print(id(b)) # different!
print(id(a)) # the same.
1 Not actually always. #classmethod decorated methods use cls as their first argument, and #staticmethod` decorated methods have nothing passed to its first argument by default.
class C():
#classmethod
def some_classmethod(cls, other, arguments):
# first argument is not the instance, but
# the class C itself.
#staticmethod
def something_related(other, arguments):
# the first argument gets neither the instance
# nor the class.
You are too focused on syntactic sugar. Just realize that the first parameter in a non static member function in python is the reference to the current object. Whether you want to call it this, that, foobar, poop, it doesn't matter. The first parameter of a member function is considered the reference to the object on which the method is called.
The use of self is just a universal way everyone has understood it and the way Python recommends - a convention if you may.
The same goes for **kwargs and *args. These are simply conventions that have permeated the Python ecosystem and everyone just uses it that way, but it doesn't mean you can't give them a different name.
Your last example broke because the function you are calling (A.something) does not take any parameters. This will make sense if you understood what I had said earlier about first parameter in non static member function being a reference to the object on which the method was called.

making a function as an else inside an __init__

How to get a function inside if/else inside an __init__ :
class Foo(object):
def __init__(self, q, **keywords):
if a == "":
print "No empty strings"
else:
def on_g(self, response):
if response.error:
print "Check your internet settings"
else:
self.Bar()
http_client.fetch("http://www.google.com/", self.on_g)
because the program dont read the on_g() if i put an empty string!
If i use the on_g() outside in parallel with __init__() i need a declared variable, for example:
class Foo(object):
def __init__(self, q, **keywords):
if a == "":
print "No empty strings"
else:
self.on_g()
def on_g(self):
print 'hello there'
will return hello there
Your bug is in
http_client.fetch("http://www.google.com/", self.on_g)
which should be
http_client.fetch("http://www.google.com/", on_g)
since you defined a function, not a method.
self (the instance you're creating through __init__ ) doesn't have a on_g method.
Functions for the class-es need to be defined at the class level (as shown on your second chunk of code). They are evaluated when the class is first... erm... "looked-up"? "evaluated"?
That's why your second piece of code works. How come you can call self.on_g within the __init__ when the actual definition of the on_g method seems to come later in the code? It's an odd behavior (at a first glance) for an interpreter, right? Well... That's because when you run self.on_g(), the whole Foo class has already been evaluated and on_g has been added to the class (not to the instance!: To the class)
class Foo(object):
def __init__(self, q, **keywords):
[ . . . ]
else:
self.on_g() # I can use self.on_g() eventhough is defined... _
# |
# |
def on_g(self): # <------------ LATER ---------------------------|
print 'hello there'
Whereas if you define your method within the __init__, the interpreter will yell at you:
class Test(object):
def __init__(self):
def test(self):
print "Hello"
self.test()
a = Test()
Throws:
Traceback (most recent call last):
File "./test.py", line 10, in <module>
a = Test()
File "./test.py", line 8, in __init__
self.test()
AttributeError: 'Test' object has no attribute 'test'
Even if you think Oh, maybe the class doesn't have the test method because it's still within the __init__, and it will have it once the initialization is completed... Meeeck... Wrong:
class Test(object):
def __init__(self):
def test(self):
print "Hello"
a = Test()
a.test()
Same AttributeError.
If you still want to add on_g to the class at runtime (very bad idea, IMHO) you can do the interpreter's job by doing this:
class Test(object):
def __init__(self):
def test(self):
print "Hello"
self.__class__.test = test
self.test()
a = Test()
a.test()
... which correctly prints:
Hello
Hello
Now, the two most straightforward things to do I can think of are:
You move the def on_g(self) to the class level (as you showed in your second code snippet)
You call your http_client.fetch with on_g as a function local to the __init__'s scope (being picky with the language: on_g now is a function, not a method, since is not bound to an object anymore).
def __init__(self, q, **keywords):
if a == "":
print "No empty strings"
else:
def on_g(response):
if response.error:
print "Check your internet settings"
else:
self.Bar()
http_client.fetch("http://www.google.com/", on_g)

The self parameter with a dictionary of functions within a class

I'm attempting to create a dictionary of executable functions within a class. But having trouble getting the self parameter to work correctly.
Consider the following code:
class myclass(object):
def x(self):
return 'x'
def y(self):
return 'y'
EF= {
'a':x,
'b':y,
}
def test(self):
print self.EF['a']()
When I attempt to execute the 'test' function of the class, I get an error around the number of parameters as it evaluates and executes one of the functions in the dictionary.
>>> class myclass(object):
... def x(self):
... return 'x'
... def y(self):
... return 'y'
... EF= {
... 'a':x,
... 'b':y,
... }
... def test(self):
... print self.EF['a']()
...
>>>
>>>
>>> m=myclass()
>>> m.test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in test
TypeError: x() takes exactly 1 argument (0 given)
I've tried a few variations, including this which doesn't work.
EF= {
'a':self.x,
'b':self.y,
}
The only thing that did work was when I explicitly passed self as a parameter, like this.
... def test(self):
... print self.EF['a'](self)
...
>>> m=myclass()
>>> m.test()
x
I've seen other questions about using a dictionary to index functions, but none from within a class.
Here are my questions:
What is the proper way to do handle the self parameter?
I'd prefer to move my dictionary constant outside of the class into my constants section. Can I do that, and if so how? Should I do that?
If I should/have to have my dictionary within my class, why can't I move it to the top of the class?
That's all I got. Thanks for the help.
What is the proper way to do handle the self parameter?
Python uses the self identifier in similar ways to other imperative languages using the this identifier, but it is explicit (as explicit is better than implicit!)
This allows you to use the class as either an instantiated object, or the static class itself.
For an instantiated version, you are probably looking for
>>> class myclass:
def __init__(self):
self.EF = {'a':self.x,'b':self.y}
def x(self):
return 'x'
def y(self):
return 'y'
def test(self):
print self.EF['a']()
>>> my_test_class = myclass()
>>> my_test_class.test()
x
I'd prefer to move my dictionary constant outside of the class into my constants section. Can I do that, and if so how? Should I do that?
If you wanted to use them as static method in a dict outside your class definition, you would need to use the #staticmethod decorator
>>> class myclass(object):
#staticmethod
def x():
return 'x'
#staticmethod
def y():
return 'y'
>>> EF = {'a':myclass.x,'b':myclass.y}
>>> EF['a']()
'x'
If I should/have to have my dictionary within my class, why can't I move it to the top of the class?
Any object attributes should be defined either in the __init__ function, or by explicitly setting them.
Having the dictionary in an init method will make it work
class Myclass(object):
def x(self):
return 'x'
def y(self):
return 'y'
def __init__(self):
self.EF= {
'a':self.x,
'b':self.y
}
def test(self):
print self.EF['a']()
m=Myclass()
m.test()
In reference to your questions. The class is kind of a dictionary or named tuple of attributes and executable functions. The functions themselves only define behavior. self is a sack of state related to your instance. if you save a pointer to that function somewhere else and provide it with a given self that is an instance of your class it should work as normal.
class MyClass(object):
def __init__(self, x):
self.x = x
def fun(self):
return self.x
i = MyClass(1)
print i.fun()
f = MyClass.fun
i2 = MyClass(2)
print f(i2)
When you call using the standard i.fun() all it's doing is passing i in implicitly as the selfargument.

Determining scope / context of a method call in python

I would like to write a decorator for a python class method that can determine if the method was called from a public context or private context. For example, given the following code
def public_check_decorator(f):
def wrapper(self):
if self.f is `called publicly`: # <-- how do I make this line work correctly?
print 'called publicly'
else:
print 'called privately'
return f(self)
return wrapper
class C(object):
#public_check_decorator
def public_method(self):
pass
def calls_public_method(self):
self.public_method()
runtime execution would ideally look something like this:
>>> c = C()
>>> c.public_method()
called publicly
>>> c.calls_public_method()
called privately
Is there any way to do this in python? That is, alter the line
if self.f is `called publicly`: # <-- how do I make this line work correctly?
to give the desired output?
Given the name of the package decides whether a function is being called from a private context or public one:
import inspect
import re
def run():
package_name = '/my_package/'
p = re.match(r'^.*' + package_name, inspect.stack()[0].filename).group()
is_private_call = any(re.match(p, frame.filename) is not None for frame in inspect.stack()[1:])
print(is_private_call)
Try running from within the package and then from outside the package!!!
see inspect.stack()
Some of this seems like trying to swim against the current of "python". Is that appropriate?
Do you know about the double-unscore standard? It makes methods "more private":
>>> class C(object):
... def __hide_me(self):
... return 11
... def public(self):
... return self.__hide_me()
...
>>> c = C()
>>> c.__hide_me()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute '__hide_me'
>>> c.public()
11
>>> c._C__hide_me()
11
>>>
Is that private enough? And using this technique is pythonic.

Get the list of a class's variables & methods in Python

If I have the following class, what's the best way of getting the exact list of variables and methods, excluding those from the superclass?
class Foo(Bar):
var1 = 3.14159265
var2 = Baz()
#property
def var3(self):
return 42
def meth1(self, var):
return var
I want the tuple ('var1','var2','var3','meth1') with minimum overhead. This is being run in a Django environment, which seems to be putting some of it's class instance variables in the read-only __dict__ variable; a feat which I can't find a way to replicate.
Here's what I'm seeing while playing with it, any suggestions beyond trimming out the __* from the dir() or manually listing them?
>>> a=Foo()
>>> a
<__main__.Foo instance at 0x7f48c1e835f0>
>>> dict(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: iteration over non-sequence
>>> dir(a)
['__doc__', '__module__', 'meth1', 'var1', 'var2', 'var3']
>>> a.__dict__
{}
If the class and its superclasses are known, something like:
tuple(set(dir(Foo)) - set(dir(Bar)))
If you want it to be more generic, you can get a list of the base classes using something like
bases = Foo.mro()
...and then use that list to subtract out attributes from all the base classes.
In your example, a is an instance, its __dict__ will include all variables set in its __init__ function. To get all class variables, use a.__class__.__dict__
A third answer is the inspect module which does the same as above
def getVariablesClass(inst):
var = []
cls = inst.__class__
for v in cls.__dict__:
if not callable(getattr(cls, v)):
var.append(v)
return var
if you want exclude inline variables check names on the __ at the start and the end of variable
If you want to introspect your own classes, you can do it on class definition and cache it by the way:
class Bar:
parent_prop = 0
class Foo(Bar):
my_prop1 = 1
my_prop2 = 2
def method1(self):
pass
SYMBOLS = [k for k in locals().keys() if not k.startswith('_')]
if __name__ == '__main__':
print(Foo.SYMBOLS)
Output:
['my_prop1', 'my_prop2', 'method1']

Categories