Can we overload behavior of class object [duplicate] - python

This question already has answers here:
What are metaclasses in Python?
(25 answers)
Closed 7 years ago.
I know we can overload behavior of instances of a class, e.g. -
class Sample(object): pass
s = Sample()
print s
<__main__.Sample object at 0x026277D0>
print Sample
<class '__main__.Sample'>
We can change the result of print s:
class Sample(object):
def __str__(self):
return "Instance of Sample"
s = Sample()
print s
Instance of Sample
Can we change the result of print Sample?

You can use a metaclass:
class SampleMeta(type):
def __str__(cls):
return ' I am a Sample class.'
Python 3:
class Sample(metaclass=SampleMeta):
pass
Python 2:
class Sample(object):
__metaclass__ = SampleMeta
Output:
I am a Sample class.
A metaclass is the class of class. Its relationship to a class is analogous to that of a class to an instance. The same classstatement is used. Inheriting form type instead from object makes it a metaclass. By convention self is replaced by cls.

Related

How can I define plain console output of a class object (vs. __str__)? [duplicate]

This question already has answers here:
What is the difference between __str__ and __repr__?
(28 answers)
Object string representation in Python/IPython shell
(3 answers)
Closed 28 days ago.
When defining my own class, I can overwrite the __str__ to define its print(my_class) behavior. What do I have to do to overwrite the behavior when just calling an my_class object?
What I get:
> obj = my_class("ABC") # define
> print(obj) # call with print
'my class with ABC'
> obj # call obj only
'<__console__.my_class object at 0x7fedf752398532d9d0>'
What I want (e.g. obj returning the same as print(obj) or some other manually defined text).
> obj # when obj is called plainly, I want to define its default
'my class with ABC (or some other default representation of the class object)'
With:
class my_class:
def __init__(self, some_string_argument)
self.some_string = some_string_argument
def __str__(self): #
return f"my_class with {self.some_string}"
Magic method __repr__ is the one. But this is discouraged.
In general __str__ should be understandable for the end user and __repr__ should return a string which when passed to eval would produce a valid instance of the object for which it's defined.
class A:
def __repr__(self):
return "I'm A!"
a = A()
a # This will print "I'm A!"
What it should/could be:
class A:
def __repr__(self):
return "A()"
a = A()
a_repr = a.__repr__()
b = eval(a_repr) # "b" is an instance of class A in this case

Is it possible to call parent class-private methods from child class in Python? [duplicate]

This question already has answers here:
Getting parent private or protected values from the child class
(2 answers)
Closed 8 months ago.
I'm trying to call __search from parent class A in child class B but I get the error:
AttributeError: 'B' object has no attribute '_B__search'
This seems to be only happening for methods starting with __. Is there a way to call these class-private methods when doing inheritance?
class A:
def __init__(self, a):
self.a = a
def __search(self):
return self.a
def display(self):
print(self.a)
class B(A):
def display(self):
res = self.__search()
return res
cB = B(2)
cB.display()
Yes, but it's terrible practice.
In Python, a method whose name begins with __ and does not end with it (so magic methods like __add__ are excluded) is obfuscated with the class name. That is,
class A:
def __foo(self):
return 1
is equivalent to
class A:
def _A__foo(self):
return 1
So if you really want to call __search defined on A, you should write
res = self._A__search()
Again, this is bad practice. Methods starting with __ are obfuscated because that's the Python convention for private functions, so they shouldn't be called from outside the class or in subclasses. You mention in the comments that this is a temporary fix, so that's understandable, but I do hope it's not intended to stay this way for very long.
An attribute name beginning with __ is private, and mangled to _classname__attribute. You need to call it by the mangled name.
class B(A):
def display(self):
res = self._A__search()
return res

Does order of class bases in python matter? [duplicate]

This question already has answers here:
How does Python's super() work with multiple inheritance?
(18 answers)
Closed 2 years ago.
Is there a (meaningful) difference the two classes below?
class A(Foo, Bar):
...
vs
class B(Bar, Foo):
...
Does order of class bases in python matter?
Yes, it does. Consider the following:
class A:
def foo(self):
print('class A')
class B:
def foo(self):
print('class B')
class C(A, B):
pass
c = C()
c.foo() # class A
Methods are resolved from left-to-right—e.g., in the example, the foo method comes from class A because A comes before B.

Get parent class name? [duplicate]

This question already has answers here:
Get class that defined method
(8 answers)
Closed 6 years ago.
The community reviewed whether to reopen this question 6 months ago and left it closed:
Original close reason(s) were not resolved
class A(object):
def get_class(self):
return self.__class__
class B(A):
def __init__(self):
A.__init__(self)
b = B()
print b.get_class()
This code will print <class '__main__.B'>.
How can I get the class name where the method has been defined (namely A)?
From the documentation: https://docs.python.org/2/reference/datamodel.html#the-standard-type-hierarchy
Class objects have a __name__ attribute. It might cleaner to introspect the base class(es) through the __bases__ attr of the derived class (if the code is to live in the derived class for example).
>>> class Base(object):
... pass
...
>>> class Derived(Base):
... def print_base(self):
... for base in self.__class__.__bases__:
... print base.__name__
...
>>> foo = Derived()
>>> foo.print_base()
Base
inspect.getmro(cls)
Return a tuple of class cls’s base classes,
including cls, in method resolution order. No class appears more than
once in this tuple. Note that the method resolution order depends on
cls’s type. Unless a very peculiar user-defined metatype is in use,
cls will be the first element of the tuple.
import inspect
inspect.getmro(B)
result will be:
(<class '__main__.B'>, <class '__main__.A'>, <type 'object'>)
First element is the class itself, second element is always first of the parents. After that things can get bit more complicated.
You could change
return self.__class__
return A().__class__
Since there is no other instance of A() available...

__bases__ doesn't work! What's next?

The following code doesn't work in Python 3.x, but it used to work with old-style classes:
class Extender:
def extension(self):
print("Some work...")
class Base:
pass
Base.__bases__ += (Extender,)
Base().extension()
Question is simple: How can I add dynamically (at runtime) a super class to a class in Python 3.x?
But I'm ready the answer will be hard! )
It appears that it is possible to dynamically change Base.__bases__
if Base.__base__ is not object. (By dynamically change, I mean in such a way that all pre-existing instances that inherit from Base also get dynamically changed. Otherwise see Mykola Kharechko's solution).
If Base.__base__ is some dummy class TopBase, then assignment to Base.__bases__ seems to work:
class Extender(object):
def extension(self):
print("Some work...")
class TopBase(object):
pass
class Base(TopBase):
pass
b=Base()
print(Base.__bases__)
# (<class '__main__.TopBase'>,)
Base.__bases__ += (Extender,)
print(Base.__bases__)
# (<class '__main__.TopBase'>, <class '__main__.Extender'>)
Base().extension()
# Some work...
b.extension()
# Some work...
Base.__bases__ = (Extender, TopBase)
print(Base.__bases__)
# (<class '__main__.Extender'>, <class '__main__.TopBase'>)
Base().extension()
# Some work...
b.extension()
# Some work...
This was tested to work in Python 2 (for new- and old-style classes) and for Python 3. I have no idea why it works while this does not:
class Extender(object):
def extension(self):
print("Some work...")
class Base(object):
pass
Base.__bases__ = (Extender, object)
# TypeError: __bases__ assignment: 'Extender' deallocator differs from 'object'
As for me it is impossible. But you can create new class dynamically:
class Extender(object):
def extension(self):
print("Some work...")
class Base(object):
pass
Base = type('Base', (Base, Extender, object), {})
Base().extension()

Categories

Resources