Accessing attribute from parent class inside child class - python

When I access an attribute from the parent class via the child class like this all works fine:
class A():
a=1
b=2
class B(A):
c=3
d=B.a+B.b+B.c
print d
But if I try to access an attribute from the parent class inside the child class like this, it doesn't work:
class A():
a=1
b=2
class B(A):
c=3
d=a+b+c
print d
I receive the error: name 'a' is not defined
Let assume that I have many equation like d=a+b+c (but more complicated) and I can't edit them - I have to call in class B "a" as "a", not "self.a" or "something.a". But I can, before equations, do A.a=a. But it is not the smartest way to reload all variables manually. I want to bypass it using inheritance. Is it possible or i should do all manually? Or maybe it is 3th route in this code?

During the class definition, none of the inherited attributes are available:
>>> class Super(object):
class_attribute = None
def instance_method(self):
pass
>>> class Sub(Super):
foo = class_attribute
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
class Sub(Super):
File "<pyshell#7>", line 2, in Sub
foo = class_attribute
NameError: name 'class_attribute' is not defined
>>> class Sub(Super):
foo = instance_method
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
class Sub(Super):
File "<pyshell#9>", line 2, in Sub
foo = instance_method
NameError: name 'instance_method' is not defined
You can't even access them using super, as the name of the subclass isn't defined within the definition block*:
>>> class Sub(Super):
foo = super(Sub).instance_method
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
class Sub(Super):
File "<pyshell#11>", line 2, in Sub
foo = super(Sub).instance_method
NameError: name 'Sub' is not defined
The only way to access the inherited attributes at definition time is to do so explicitly, using the name of the superclass:
>>> class Sub(Super):
foo = Super.class_attribute
>>> Sub.foo is Super.class_attribute
True
Alternatively you can access them within class or instance methods, but then you need to use the appropriate prefix of the class (conventionally cls) or instance (conventionally self) parameter.
* for anyone thinking "ah, but in 3.x you don't need arguments to super":
>>> class Sub(Super):
foo = super().instance_method
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
class Sub(Super):
File "<pyshell#6>", line 2, in Sub
foo = super().instance_method
RuntimeError: super(): no arguments
That's only true inside instance/class methods!

I may be wrong on this, but are you sure you don't want rather this?
class A(object):
def __init__(self):
self.a = 1
self.b = 2
class B(A):
def __init__(self):
super(B, self).__init__()
self.c = 3
#property
def d(self):
return self.a + self.b + self.c
BB = B()
print BB.d
or, as jonrsharpe pointed out:
class A():
a=1
b=2
class B(A):
c=3
d=A.a+A.b+c
print B.d

Related

Make function in class only accessible without calling the class

Let's say I have this class:
class A:
def __init__(self, a):
self.a = a
#classmethod
def foo(self):
return 'hello world!'
I use #classmethod, so that I can directly call the function without calling the class:
>>> A.foo()
'hello world!'
>>>
But now I am wondering, since I still can access it with calling the class:
>>> A(1).foo()
'hello world!'
>>>
Would I be able to make it that it would raise an error if the function foo is called from a called class. And only let it to be called without calling the class, like A.foo().
So if I do:
A(1).foo()
It should give an error.
The functionality of how classmethod, staticmethod and in fact normal methods are lookedup / bound is implemented via descriptors. Similarly, one can define a descriptor that forbids lookup/binding on an instance.
A naive implementation of such a descriptor checks whether it is looked up via an instance and raises an error in this case:
class NoInstanceMethod:
"""Descriptor to forbid that other descriptors can be looked up on an instance"""
def __init__(self, descr, name=None):
self.descr = descr
self.name = name
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
# enforce the instance cannot look up the attribute at all
if instance is not None:
raise AttributeError(f"{type(instance).__name__!r} has no attribute {self.name!r}")
# invoke any descriptor we are wrapping
return self.descr.__get__(instance, owner)
This can be applied on top of other descriptors to prevent them from being looked up on an instance. Prominently, it can be combined with classmethod or staticmethod to prevent using them on an instance:
class A:
def __init__(self, a):
self.a = a
#NoInstanceMethod
#classmethod
def foo(cls):
return 'hello world!'
A.foo() # Stdout: hello world!
A(1).foo() # AttributeError: 'A' object has no attribute 'foo'
The above NoInstanceMethod is "naive" in that it does not take care of propagating descriptor calls other than __get__ to its wrapped descriptor. For example, one could propagate __set_name__ calls to allow the wrapped descriptor to know its name.
Since descriptors are free to (not) implement any of the descriptor methods, this can be supported but needs appropriate error handling. Extend the NoInstanceMethod to support whatever descriptor methods are needed in practice.
A workaround is to override its value upon initialization of a class object to make sure it wouldn't be called from self.
def raise_(exc):
raise exc
class A:
STRICTLY_CLASS_METHODS = [
"foo",
]
def __init__(self, a):
self.a = a
for method in self.STRICTLY_CLASS_METHODS:
# Option 1: Using generator.throw() to raise exception. See https://www.python.org/dev/peps/pep-0342/#new-generator-method-throw-type-value-none-traceback-none
# setattr(self, method, lambda *args, **kwargs: (_ for _ in ()).throw(AttributeError(method)))
# Option 2: Using a function to raise exception
setattr(self, method, lambda *args, **kwargs: raise_(AttributeError(method)))
#classmethod
def foo(cls):
return 'hello world!'
def bar(self):
return 'hola mundo!', self.a
Output
>>> A.foo()
'hello world!'
>>> a = A(123)
>>> a.bar()
('hola mundo!', 123)
>>> a.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in <lambda>
File "<stdin>", line 2, in raise_
AttributeError: foo
>>> a.bar()
('hola mundo!', 123)
>>> A(45).bar()
('hola mundo!', 45)
>>> A(6789).foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in <lambda>
File "<stdin>", line 2, in raise_
AttributeError: foo
>>> A.foo()
'hello world!'

Is there any way to create a Python class method that does NOT pollute the attribute namespace of its instances?

I want to provide a method that can be used on a Python 2.7 class object, but does not pollute the attribute namespace of its instances. Is there any way to do this?
>>> class Foo(object):
... #classmethod
... def ugh(cls):
... return 33
...
>>> Foo.ugh()
33
>>> foo = Foo()
>>> foo.ugh()
33
You could subclass the classmethod descriptor:
class classonly(classmethod):
def __get__(self, obj, type):
if obj: raise AttributeError
return super(classonly, self).__get__(obj, type)
This is how it would behave:
class C(object):
#classonly
def foo(cls):
return 42
>>> C.foo()
42
>>> c=C()
>>> c.foo()
AttributeError
This desugars to the descriptor call (rather, it is invoked by the default implementation of __getattribute__):
>>> C.__dict__['foo'].__get__(None, C)
<bound method C.foo of <class '__main__.C'>>
>>> C.__dict__['foo'].__get__(c, type(c))
AttributeError
Required reading: Data Model — Implementing Descriptors and Descriptor HowTo Guide.
ugh is not in the namespace:
>>> foo.__dict__
{}
but the rules for attribute lookup fall back to the type of the instance for missing names. You can override Foo.__getattribute__ to prevent this.
class Foo(object):
#classmethod
def ugh(cls):
return 33
def __getattribute__(self, name):
if name == 'ugh':
raise AttributeError("Access to class method 'ugh' block from instance")
return super(Foo,self).__getattribute__(name)
This produces:
>>> foo = Foo()
>>> foo.ugh()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "tmp.py", line 8, in __getattribute__
raise AttributeError("Access to class method 'ugh' block from instance")
AttributeError: Access to class method 'ugh' block from instance
>>> Foo.ugh()
33
You must use __getattribute__, which is called unconditionally on any attribute access, rather than __getattr__, which is only called after the normal lookup (which includes checking the type's namespace) fails.
Python has quasi-private variables that use name-munging to reduce accidental access. Methods and object variables of the form __name are converted to _ClassName__name. Python automatically changes the name when compiling methods on the class but doesn't change the name for subclasses.
I can use the private method in a class
>>> class A(object):
... def __private(self):
... print('boo')
... def hello(self):
... self.__private()
...
>>>
>>> A().hello()
boo
But not outside the class
>>> A().__private()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute '__private'
>>>
Or in subclasses
>>> class B(A):
... def hello2(self):
... self.__private()
...
>>>
>>> B().hello()
boo
>>> B().hello2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in hello2
AttributeError: 'B' object has no attribute '_B__private'
Yes, you can create the method in the metaclass.
class FooMeta(type):
# No #classmethod here
def ugh(cls):
return 33
class Foo(object):
__metaclass__ = FooMeta
Foo.ugh() # returns 33
Foo().ugh() # AttributeError
Note that metaclasses are a power feature, and their use is discouraged if unnecessary. In particular, multiple inheritance requires special care if the parent classes have different metaclasses.

How to access private variable of Python module from class

In Python 3, prefixing a class variable makes it private my mangling the name within the class. How do I access a module variable within a class?
For example, the following two ways do not work:
__a = 3
class B:
def __init__(self):
self.a = __a
b = B()
results in:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __init__
NameError: name '_B__a' is not defined
Using global does not help either:
__a = 3
class B:
def __init__(self):
global __a
self.a = __a
b = B()
results in:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __init__
NameError: name '_B__a' is not defined
Running locals() shows that the variable __a exists unmangled:
>>> locals()
{'__package__': None, '__name__': '__main__',
'__loader__': <class '_frozen_importlib.BuiltinImporter'>,
'__doc__': None, '__a': 3, 'B': <class '__main__.B'>,
'__builtins__': <module 'builtins' (built-in)>, '__spec__': None}
[Newlines added for legibility]
Running same code in a module (as opposed to interpreter) results in the exact same behavior. Using Anaconda's Python 3.5.1 :: Continuum Analytics, Inc..
It's ugly but You could access globals:
__a = 3
class B:
def __init__(self):
self.a = globals()["__a"]
b = B()
You can also put it in a dict:
__a = 3
d = {"__a": __a}
class B:
def __init__(self):
self.a = d["__a"]
b = B()
Or a list, tuple etc.. and index:
__a = 3
l = [__a]
class B:
def __init__(self):
self.a = l[0]
b = B()
Apparently the "official" answer is not to use double underscores outside of a class. This is implied in the documentation here: https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references. Furthermore, the following (failed) bug report (and this response) make it explicit.
You are instantiating a class by passing a variable which is not defined. putting __a outside the class will not not work as the class will not see this variable. What you should do instead is:
__a = 3
class B:
def __init__(self, __a):
self.a = __a
b = B(__a)
This way you would have passed an argument in the constructor for initializing.
If you are going to mangle the names as you are trying to do then I would refer you to this article: http://shahriar.svbtle.com/underscores-in-python
As such, my solution to what you are trying to do is as follows:`
class R:
global _R__a
_R__a = 3
def __init__(self):
pass
class B:
global _R__a
def __init__(self):
self.a = _R__a
b = B()
print b.a
#3`
This way, you are also more specific about the variable you are calling without much room for modifying it later. Hope this works.

Decide baseclass at runtime

I want to do something like this:
class A:
def methodA(self):
return 5
class B:
def methodB(self):
return 10
class X(...):
def __init__(self, baseclass):
if baseclass =='A' : derive X from A
elif baseclass == 'B' : derive X from B
else: raise Exception("Not supported baseclass %s!" % (baseclass))
def methodX(self):
return 42
X('A').methodA() # returns 5
X('A').methodX() # returns 42
X('A').methodB() # methodB not defined
X('B').methodB() # returns 10
X('B').methodX() # returns 42
X('A').methodA() # methodA not defined
How can I implement this?
If you want to add methodX to the existing classes, you could consider multiple inheritance:
class A:
def methodA(self):
return 5
class B:
def methodB(self):
return 10
class X():
#classmethod
def new(cls, baseclass):
if baseclass == A:
return AX()
elif baseclass == B:
return BX()
else: raise Exception("Not supported baseclass %s!" % str(baseclass))
def methodX(self):
return 42
class AX(A, X):
pass
class BX(B, X):
pass
You can add args and kwargs to X.new and pass them on to the specific constructors. Here are the outputs of your tests (I corrected the last on in your question):
>>> ax = X.new(A)
>>> ax.methodA() # returns 5
5
>>> ax.methodX() # returns 42
42
>>> ax.methodB() # methodB not defined
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: AX instance has no attribute 'methodB'
>>> bx = X.new(B)
>>> bx.methodB() # returns 10
10
>>> bx.new(B).methodX() # returns 42
42
>>> bx.new(B).methodA() # methodA not defined
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: BX instance has no attribute 'methodA'
You should define two classes, X and Y, and a factory-method to instantiate either X or Y, depending on a parameter.
In general, the behavior you try to implement is somewhat confusing. When you create an instance (that is what X(...) does) you should get an instance of X, and instances of a class should have same attributes. That is one of the main reasons why classes exist.
Example:
class A:
def methodA(self):
return 5
class B:
def methodB(self):
return 10
def x(class_name):
name2class = {"A":A, "B":B}
return name2class[class_name]()
for name in ["A","B","C"]:
instance = x(name)
print name, instance
will print
A <__main__.A instance at 0x022C8D50>
B <__main__.B instance at 0x022C8DF0>
Traceback (most recent call last):
File ".../14834949.py", line 21, in <module>
instance = x(name)
File ".../14834949.py", line 18, in x
return name2class[class_name]()
KeyError: 'C'

Python, a function in a method

I have a method (__init__) in a class, and I want to use a function from the class in this method.
But when I want to run my program. I get: NameError: global name 'myfunction' is not defined
Someone, who knows what I have to do? :)
Thank you. But I have still a problem, because def myFunc(self, a): is a method and I wanted a function.
class Myclass(object):
def __init__(self, a):
self.a = self.myFunc(a)
def myFunc(self, a):
return a+1
Then you don't have a function call in the method, but you have a method call in it.
When creating a class you must specify the object when calling its methods:
>>> class A(object):
... def __init__(self, val):
... self.val = self._process(val)
... def _process(self, val):
... return val % 7
... process = _process #if you are outside methods then you don't
... #have to add "self.".
...
>>> a = A(5)
>>> a.process(3)
3
>>> a._process(6) #"a" is passed as the "self" parameter
6
As you can see in a class definition, but outside the methods you must specify the method name only, and not the "self.". Also you can't refer to a method not already defined:
>>> class B(object):
... def __init__(self):pass
... def method1(self):pass
... __call__ = method2 #method2 not defined!
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in B
NameError: name 'method2' is not defined

Categories

Resources