I have the following example from python page_object docs:
from page_objects import PageObject, PageElement
from selenium import webdriver
class LoginPage(PageObject):
username = PageElement(id_='username')
password = PageElement(name='password')
login = PageElement(css='input[type="submit"]')
driver = webdriver.PhantomJS()
driver.get("http://example.com")
page = LoginPage(driver)
page.username = 'secret'
page.password = 'squirrel'
assert page.username.text == 'secret'
page.login.click()
What bothers me is that we create a LoginPage with providing a driver to it's constructor, but we haven't define a __init__ method in LoginPage class.
Does that mean that the parent class PageObject's constructor is called with driver parameter? I thought that python doesn't implicitly call parent's constructors?
The __init__ method is just a method and as such python performs the same kind of lookup for it as other methods. If class B does not define a method/attribute x then python looks up it's base class A and so on, until it either finds the attribute/method or fails.
A simple example:
>>> class A:
... def method(self):
... print('A')
...
>>> class B(A): pass
...
>>> class C(B):
... def method(self):
... print('C')
...
>>> a = A()
>>> b = B()
>>> c = C()
>>> a.method()
A
>>> b.method() # doesn't find B.method, and so uses A.method
A
>>> c.method()
C
The same is with __init__: since LoginPage does not define __init__ python looks up the PageObject class and finds its definition there.
What is meant when we say that "python doesn't implicitly call parent class constructors" is that if you define an __init__ method the interpreter will just call that method and not call all the parent class __init__s, and as such if you want to call the parent class constructor you have to do so explicitly.
Note the difference among these classes:
>>> class A:
... def __init__(self):
... print('A')
...
>>> class B(A):
... pass
...
>>> class B2(A):
... def __init__(self):
... print('B')
...
>>> class B3(A):
... def __init__(self):
... print('B3')
... super().__init__()
...
>>> A()
A
<__main__.A object at 0x7f5193267eb8>
>>> B() # B.__init__ does not exists, uses A.__init__
A
<__main__.B object at 0x7f5193267ef0>
>>> B2() # B2.__init__ exists, no call to A.__init__
B
<__main__.B2 object at 0x7f5193267eb8>
>>> B3() # B3.__init__exists, and calls to A.__init__ too
B3
A
<__main__.B3 object at 0x7f5193267ef0>
Related
How can I check if method is called inside another method, when those methods are from different classes?
If they are from same class, I can do this:
from unittest import mock
class A():
def method_a(self):
pass
def method_b(self):
self.method_a()
a = A()
a.method_a = mock.MagicMock()
a.method_b()
a.method_a.assert_called_once_with()
But if method_a would be from different class, then it would raise AssertionError that it was not called.
How could I do same check if I would have these classes instead (and I want to check if method_b calls method_a)?:
class A():
def method_a(self):
pass
class B():
def method_b(self):
A().method_a()
You have to simply stub A within the same context as B, and validate against the way it would have been called. Example:
>>> class B():
... def method_b(self):
... A().method_a()
...
>>> A = mock.MagicMock()
>>> A().method_a.called
False
>>> b = B()
>>> b.method_b()
>>> A().method_a.called
True
>>>
Say I have class Test defined as this:
class Test
test_var = 2
def test_func():
print(test_var)
I can find out what test_var is fine like so:
>>> Test.test_var
2
...But calling Test.test_func() does not work.
>>> Test.test_func()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in test
NameError: name 'test_var' is not defined
If I change Test.test_func() like this (note that this is pseudo-code):
redef test_func():
print(Test.test_var)
It works fine:
>>> Test.test_func()
2
...and that makes sense. But how can I make the first example work, keeping in mind that I want test_func to be an instance method?
Note that the code posted above is example code, and so typos should be ignored.
You can always access class-level attributes via the instance, ie self, as long as you have not shadowed them with an instance attribute of the same name. So:
def test_func(self):
print(self.test_var)
In your example, test_func is just a function and although its defined in the class namespace, the function itself doesn't know about the class namespace. You want either a regular instance method or a class method.
class Test:
test_var = 2
def instance_test(self):
# instance methods will look in self first and class namespace second
print(self.test_var)
#classmethod
def class_test(cls):
# class methods take the class itself as first argument
print(cls.test_var)
t = Test()
t.instance_test()
Test.class_test()
You need to either pass self (almost always what you want) to the class method or add a #classmethod or #staticmethod decorator if you don't need self. Then create an instance of the class and call the test_func method.
Examples:
# test_var is an class variable and test_func has a classmethod decorator
>>> class Test:
... test_var = 2
... #classmethod
... def test_func(cls):
... print(cls.test_var)
...
>>> t = Test()
>>> t.test_func()
2
# test_var is an class variable and test_func has a staticmethod decorator
>>> class Test:
... test_var = 2
... #staticmethod
... def test_func():
... print(Test.test_var)
...
>>> t = Test()
>>> t.test_func()
2
# test_var is an instance variable here
>>> class Test:
... self.test_var = 2
... def test_func(self):
... print(self.test_var)
...
>>> t = Test()
>>> t.test_func()
2
I made a post here functions and class attributes (python)
When you define
a class attribute and gave it a function like this:
example 1
def add_age(cls,age):
cls.yrs_old = age
return cls
class Test:
age = add_age
a = Test()
a.age(5)
print(a.yrs_old)
self is automatically passed as the first argument of the add_age function.
However toying around with it more doing the same thing
but this time passing the function as an instance attribute like this:
example 2
def test_func(self):
self.class_attribute = "test"
class Test:
def __init__(self,func):
self.func = func
a = Test(test_func)
print(a.func())
Answers in the linked post stated that all functions in the class are automatically passed a self if the class is instantiated like this:
a = Test(test_func)
Now what's strange here is had I put test_func in a class attribute it works just like my very first example.
If you pass the function in the constructor/init like this:
def test_func(self):
self.class_attribute = "test"
class Test:
def __init__(self,func):
self.func = func
and call it like this:
a = Test(test_func)
print(a.func())
a.func is suddenly acting like a static method as opposed to example 1 where the function defined inside the class attribute becomes a regular class method.
What's going on?.
I thought all functions within a class are implicitly passed a self argument.
After the body of the class statement is evaluated, the metaclass wraps each function in a descriptor which takes care of the distinction between instance, class, and static methods. When you assign the function to an instance attribute, you bypass that machinery, so that the attribute refers to a plain function object.
From documentation -
Any function object that is a class attribute defines a method for instances of that class. It is not necessary that the function definition is textually enclosed in the class definition: assigning a function object to a local variable in the class is also ok.
This means that only methods that are assigned to classes are instance methods for the instances of the class.
Example -
>>> class A:
... def a(self):
... print("Hmm")
...
>>> b = A()
>>> b.a()
Hmm
>>> b.a
<bound method A.a of <__main__.A object at 0x006D13D0>>
But as soon as you assign a separate function object to the instance variable, it is no longer an instance method , since is is not defined at the class level, it is only defined for that particular instance , Example -
>>> def c():
... print("Hello")
...
>>> b.a = c
>>> b.a()
Hello
>>> b.a
<function c at 0x0017B198>
As you can see, when you directly assigned the function to the instance variable (instead of assigning it to class variable , it is now a normal instance attribute, that references a function object, and not an instance method.
You can also assign functions to class variables after the definition of class , and the instances would automatically get them as instance methods, Example -
>>> class A:
... def a(self):
... print("Hmm")
...
>>> def c(a):
... print("Hello - ", a)
...
>>> b = A()
>>> A.b = c
>>> b.b
<bound method A.c of <__main__.A object at 0x006D13D0>>
>>> b.b()
Hello <__main__.A object at 0x006D13D0>
TL;DR How do I find out whether a function was defined using #classmethod or something with the same effect?
My problem
For implementing a class decorator I would like to check if a method takes the class as its first argument, for example as achieved via
#classmethod
def function(cls, ...):
I found a solution to check for #staticmethod via the types module (isinstance(foo, types.UnboundMethodType) is False if the foo is static, see here), but did not find anything on how to do so for #classmethod
Context
What I am trying to do is something along the lines of
def class_decorator(cls):
for member in cls.__dict__:
if (isclassmethod(getattr(cls, member))):
# do something with the method
setattr(cls, member, modified_method)
return cls
and I do not know how to implement what I called isclassmethod in this example
If the object is a method object, and so has a method.__self__ attribute, and that attribute is the class you got the attribute from, then it'll take the class as the first argument. It has been bound to the class.
Note that you already have a bound object at this point, so you don't need to pass in the class again, unless you first extract the original function from method.__func__.
Here is an illustration, the class Foo has a class method bar and a regular method baz, which is not bound when you access it directly on the class:
>>> class Foo:
... #classmethod
... def bar(cls):
... pass
... def baz(self):
... pass
...
>>> Foo.baz
<function Foo.baz at 0x1097d1e18>
>>> Foo.bar
<bound method Foo.bar of <class '__main__.Foo'>>
>>> Foo.bar.__self__
<class '__main__.Foo'>
>>> Foo.bar.__self__ is Foo
True
Calling Foo.bar() automatically passes in Foo.bar.__self__ as the first argument.
If you need to test such methods, use inspect.ismethod(), and if that returns True test the __self__ attribute:
import inspect
if inspect.ismethod(cls.method) and cls.method.__self__ is cls:
# method bound to the class, e.g. a classmethod
This should work for any custom descriptors that work like classmethod does, as well.
If you need to know with certainty that the method was produced by a classmethod object, you'll need to look up the attributes directly in the class namespace (cls.__dict__ or vars(cls)), and do so in each class in the class hierarchy in method resolution order:
def isclassmethod(method):
bound_to = getattr(method, '__self__', None)
if not isinstance(bound_to, type):
# must be bound to a class
return False
name = method.__name__
for cls in bound_to.__mro__:
descriptor = vars(cls).get(name)
if descriptor is not None:
return isinstance(descriptor, classmethod)
return False
and a full test of the above two approaches using a base class and a derived class, with a custom descriptor that binds a function the same way a classmethod would, but is not, itself, a classmethod:
>>> class notclassmethod:
... def __init__(self, f):
... self.f = f
... def __get__(self, _, typ=None):
... return self.f.__get__(typ, typ)
...
>>> class Base:
... #classmethod
... def base_cm(cls): pass
... #notclassmethod
... def base_ncm(cls): pass
... def base_m(self): pass
...
>>> class Derived(Base):
... #classmethod
... def derived_cm(cls): pass
... #notclassmethod
... def derived_ncm(cls): pass
... def derived_m(self): pass
...
>>> inspect.ismethod(Derived.base_cm) and Derived.base_cm.__self__ is Derived
True
>>> inspect.ismethod(Derived.base_ncm) and Derived.base_ncm.__self__ is Derived
True
>>> inspect.ismethod(Derived.base_m) and Derived.base_m.__self__ is Derived
False
>>> inspect.ismethod(Derived.derived_cm) and Derived.derived_cm.__self__ is Derived
True
>>> inspect.ismethod(Derived.derived_ncm) and Derived.derived_ncm.__self__ is Derived
True
>>> inspect.ismethod(Derived.derived_m) and Derived.derived_m.__self__ is Derived
False
>>> isclassmethod(Derived.base_cm)
True
>>> isclassmethod(Derived.base_ncm)
False
>>> isclassmethod(Derived.base_m)
False
>>> isclassmethod(Derived.derived_cm)
True
>>> isclassmethod(Derived.derived_ncm)
False
>>> isclassmethod(Derived.derived_m)
False
The isclassmethod() function correctly distinguishes between the classmethod and notclassmethod descriptors.
Historical note: this answer included references to Python 2, but with Python 2 having reached EOL were removed as no longer relevant.
You should use inspect.ismethod. It works because classmethod binds the function to the class object. See the following code:
>>> class Foo:
... #classmethod
... def bar():
... pass
... def baz():
... pass
...
>>> Foo.bar
<bound method type.bar of <class '__main__.Foo'>>
>>> Foo.baz
<function Foo.baz at 0x0000000002CCC1E0>
>>> type(Foo.bar)
<class 'method'>
>>> type(Foo.baz)
<class 'function'>
>>> import inspect
>>> inspect.ismethod(Foo.bar)
True
>>> inspect.ismethod(Foo.baz)
False
class Foo(object):
#classmethod
def baaz(cls):
print "baaz"
isinstance(Foo.__dict__["baaz"], classmethod)
None of the answers address the problem of identifying whether a method is decorated with class method from an instance of the class. Following code explores the class dict of an instance to distinguish between classmethod from other methods.
class MyClass(object):
#classmethod
def class_method(cls):
pass
def instance_method(self):
pass
#staticmethod
def static_method():
pass
def blas(): pass
t = MyClass()
isinstance(t.__class__.__dict__[t.class_method.__name__], classmethod) # True
isinstance(t.__class__.__dict__[t.static_method.__name__], classmethod) # False
isinstance(t.__class__.__dict__[t.instance_method.__name__], classmethod) # False
isinstance(t.__class__.__dict__[t.blas.__name__], classmethod) # False
This will work for both Python 2 and 3.
This works for me:
def is_classmethod(method):
"""
Is method a classmethod?
"""
return isinstance(getattr(method, '__self__', None), type)
It basically tests if method.__self__ exists and is a class, as in Martijn's answer, but does not require access to the class itself.
i have a function which is a class method, and i want to test a attribute of the class which may or may not be None, but will exist always.
class classA():
def __init__(self, var1, var2 = None):
self.attribute1 = var1
self.attribute2 = var2
#classmethod
def func(self,x):
if self.attribute2 is None:
do something
i get the error
AttributeError: class classA has no attribute 'attributeB'
when i access the attribute like i showed but if on command line i can see it works,
x = classA()
x.attribute2 is None
True
so the test works.
if i remove the #classmethod decorator from func, the problem disapears.
if i leave the #classmethod decorator, it only seems to affect variables which are supplied default values in the super-class's constructor.
whats going on in the above code?
There is a difference between class attributes and instance attributes. A quick demonstration would be this:
>>> class A(object):
... x=4
... def __init__(self):
... self.y=2
>>> a=A() #a is now an instance of A
>>> A.x #Works as x is an attribute of the class
2: 4
>>> a.x #Works as instances can access class variables
3: 4
>>> a.y #Works as y is an attribute of the instance
4: 2
>>> A.y #Fails as the class A has no attribute y
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
A.y #Fails as the class A has no attribute y
AttributeError: type object 'A' has no attribute 'y'
>>>
Now, when a method of a class is decorated with classmethod, that signals that it does not take an instance, but takes the class itself as the parameter. Thus, conventionally we name the first argument cls, and not self. In your code, classA has no attributes, and so trying to access attribute2 fails. This difference can be shown with the below code:
>>> class B(object):
... x=2
... def __init__(self):
... self.x=7
... def pr1(self):
... print self.x
... #classmethod
... def pr2(cls):
... print cls.x
>>> b=B()
>>> B.x
2
>>> b.x
7
>>> b.pr1()
7
>>> b.pr2()
2
>>> B.pr2()
2
I might not have been clear enough, so if you are still confused just search classmethod or new-style classes and read up a bit on this.
You should first test to see if you HAVE the attribute with hasattr() or somesuch.
class classA(superClass):
def func(self,x):
if not hasattr(self, "attributeB") or self.attributeB is None:
do somthing
You may also want to make sure that the sub-class is calling the constructor method from the parent class. That attribute is obviously getting assigned after you're referencing it. So make sure the class is properly constructed with
parentclassName.__init__(self, ... )
self in an instance method is the instance. self (or more traditionally, cls) in a class method is the class. Attributes bound on an instance are not visible on the class. The only way to make this work would be to pass the instance to the class method, at which point you may as well just make it an instance method.
The two attributes are instance attributes, not class attributes. The class method is trying to reference class attributes. Neither your attribute1 nor your attribute2 exist on the class: they exist on the instance.
I don't know how to fix this, but this is the source of the problem.
(Verified by changing attribute2 to attribute1 in func.)
So the question should really be, "How to reference instance attributes within a class method?"