Why python metaclass is not working in this code? - python

class My_meta(type):
def hello(cls):
print("hey")
class Just_a_class(metaclass=My_meta):
pass
a = Just_a_class()
a.hello()
Above code is giving:
AttributeError: 'Just_a_class' object has no attribute 'hello'
Please suggest the changes to make it work. Thanks.

Methods in a metaclass are inherited by the class object, not class instances. You can call the function this way:
Just_a_class.hello()
// or
a = Just_a_class()
a.__class__.hello()

Related

Understanding the difference between `self`and `cls` and whether they refer to the same attributes

I'm trying to understand if there are differences between self and cls but I'm struggling, even though a lot of discussion on this topic exists. For instance:
class maclass():
A = "class method"
def __init__(self):
self.B = "instance method"
def getA_s(self):
print(self.A)
def getA_c(cls):
print(cls.A)
def getB_s(self):
print(self.B)
def getB_c(cls):
print(cls.B)
C = maclass()
C.getA_s()
C.getA_c()
C.getB_s()
C.getB_c()
which give me:
class method
class method
instance method
instance method
So whether I use self or cls, it always refers to the same variable. When I add a self.A in the Init__, the cls.A is just replaced
def __init__(self):
self.B = "instance method"
self.A = "new instance method"
and I get:
new instance method
new instance method
instance method
instance method
I don't understand the point of having two ways to call a class member if they are the same? I know this is a common question on this forum, yet I really don't understand why we would use different words to refer to the same thing (we even could use any variable name instead of self or cls).
update
In the following case:
class maclass():
A = "class method, "
def __init__(self):
self.A = "instance method, "
def getA_s(self):
print(self.A) #give me "instance method, "
#classmethod
def getA_c(cls):
print(cls.A) #give me "class method, "
C = maclass()
C.getA_s()
C.getA_c()
print(' ')
print(C.A) #give me "instance method, "
I get :
instance method,
class method,
instance method,
So in this case, in maclass: cls.A and self.A do not refer to the same variable.
All your methods are instance methods. None of them are class methods.
The first argument to a method is named self only by convention. You can name it anything you want, and naming it cls instead will not make it a reference to the class. That the first argument is bound to an instance is due to how method lookup works (accessing C.getA_s produces a bound method object, and calling that object causes C to be passed into the original function getA_s), the names of the parameters play no role.
In your methods, you are merely referencing instance attributes. That the A attribute is ultimately only defined on the class doesn't matter, you are still accessing that attribute through C.A (where C is the instance you created), not maclass.A. Looking up an attribute on the instance will also find attributes defined on the class if there is no instance attribute shadowing it.
To make a method a class method, decorate it with the #classmethod decorator:
#classmethod
def getA_c(cls):
print(cls.A)
Now cls will always be a reference to the class, never to the instance. I need to stress again that it doesn't actually matter to Python what name I picked for that first argument, but cls is the convention here as that makes it easier to remind the reader that this method is bound to the class object.
Note that if you do this for the getB_c() method, then trying to access cls.B in the method will fail because there is no B attribute on the maclass class object.
That's because classmethod wraps the function in a descriptor object that overrides the normal function binding behaviour. It is the descriptor protocol that causes methods to be bound to instances when accessed as attributes on the instance, a classmethod object redirects that binding process.
Here is a short demonstration with inline comments, I used the Python convertions for naming classes (using CamelCase), and for instances, attributes, functions and methods (using snake_case):
>>> class MyClass():
... class_attribute = "String attribute on the class"
... def __init__(self):
... self.instance_attribute = "String attribute on the instance"
... #classmethod
... def get_class_attribute(cls):
... return cls.class_attribute
... def get_instance_attribute(self):
... return self.instance_attribute
... #classmethod
... def get_instance_attribute_on_class(cls):
... return cls.instance_attribute
...
>>> instance = MyClass()
>>> instance.class_attribute # class attributes are visible on the instance
'String attribute on the class'
>>> MyClass.class_attribute # class attributes are also visible on the class
'String attribute on the class'
>>> instance.get_class_attribute() # bound to the class, but that doesn't matter here
'String attribute on the class'
>>> instance.class_attribute = "String attribute value overriding the class attribute"
>>> instance.get_class_attribute() # bound to the class, so the class attribute is found
'String attribute on the class'
>>> MyClass.get_instance_attribute_on_class() # fails, there is instance_attribute on the class
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 12, in get_instance_attribute_on_class
AttributeError: type object 'MyClass' has no attribute 'instance_attribute'
Note that the class method accesses the class attribute even though we set an attribute with the same name on the instance.
Next is binding behaviour:
>>> MyClass.get_instance_attribute # accessing the method on the class gives you the function
<function MyClass.get_instance_attribute at 0x10f94f268>
>>> instance.get_instance_attribute # accessing the method on the instance gives you the bound method
<bound method MyClass.get_instance_attribute of <__main__.MyClass object at 0x10f92b5f8>>
>>> MyClass.get_class_attribute # class methods are always bound, to the class
<bound method MyClass.get_class_attribute of <class '__main__.MyClass'>>
>>> instance.get_class_attribute # class methods are always bound, to the class
<bound method MyClass.get_class_attribute of <class '__main__.MyClass'>>
The bound methods tell you what they are bound to, calling the method passes in that bound object as the first argument. That object can also be introspected by looking at the __self__ attribute of a bound method:
>>> instance.get_instance_attribute.__self__ # the instance
<__main__.MyClass object at 0x10f92b5f8>
>>> instance.get_class_attribute.__self__ # the class
<class '__main__.MyClass'>

how to solve attribute error when all attributes do exist?

I am writing a program for my A level course in python and i need to access an attribute from one class in to another using inheritance. here is an example of what I am trying to do.
class class1():
def __init__(self):
self.testValue = 'hello'
class class2(class1):
def __init__(self):
self.inheritedValue = class1.testValue
print(self.inheritedValue)
object = class2()
when running this code i get the following attribute error.
AttributeError: type object 'class1' has no attribute 'testValue'
anyone got a solution for this??
First a comment to code style: class names are written in CamelCase, so name them Class1 and Class2.
Secondly, your class Class1 doesn't have the said attribute, but each instance does.
So your class2 should look like
class Class2(Class1):
def __init__(self):
super().__init__() # now we have everything Class1 provides us with
self.inheritedValue = self.testValue
print(self.inheritedValue)
because each object of Class2 is also an object of Class1
The attribute does not exist within the scope of class2 the way you've implemented it. By passing it in the class definition, it is inherited but the attribute doesn't exist yet. That is, unless you've called the constructor. Two ways of doing this, by either using the super built-in function(not recommended in real life, see here, it's a nice read. Anyway, here are a few solutions:
class class1():
def __init__(self):
self.testValue = 'hello'
class class2(class1):
def __init__(self):
class1.__init__(self)
print(self.testValue)
obj = class2()
if you do not want to call the constructor of the class you are inheriting, you could do something like this:
class class1():
testValue = 'hello'
def __init__(self):
pass
class class2(class1):
def __init__(self):
self.inheritedValue = class1.testValue
print(self.inheritedValue)
obj = class2()
Side note, object is a built-in so you shouldn't use it.

Python: Predefined class variable access

In Python, I am able to access the non-predefined class variables both from the class as well as instances. However, I am not able to access the predefined class variables (such as "name") from the object instances. What am I missing? Thanks.
Here is a test program that I wrote.
class Test:
'''
This is a test class to understand why we can't access predefined class variables
like __name__, __module__ etc from an instance of the class while still able
to access the non-predefined class variables from instances
'''
PI_VALUE = 3.14 #This is a non-predefined class variable
# the constructor of the class
def __init__(self, arg1):
self.value = arg1
def print_value(self):
print self.value
an_object = Test("Hello")
an_object.print_value()
print Test.PI_VALUE # print the class variable PI_VALUE from an instance of the class
print an_object.PI_VALUE # print the class variable PI_VALUE from the class
print Test.__name__ # print pre-defined class variable __name__ from the class
print an_object.__name__ #print the pre-defined class varible __name__ from an instance of the class
That's normal. Instances of a class look in that class's __dict__ for attribute resolution, as well as the __dict__s of all ancestors, but not all attributes of a class come from its __dict__.
In particular, Test's __name__ is held in a field in the C struct representing the class, rather than in the class's __dict__, and the attribute is found through a __name__ descriptor in type.__dict__. Instances of Test don't look at this for attribute lookup.
I don't have a great answer for "why". But here's how you can get to them, using __class__:
>>> class Foo(object): pass
...
>>> foo = Foo()
>>> foo.__name__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__name__'
>>> foo.__class__.__name__
'Foo'
>>>

How to convert (inherit) parent to child class?

I would like to know how to convert parent object that was return by some function to child class.
class A(object):
def __init__():
pass
class B(A):
def functionIneed():
pass
i = module.getObject() # i will get object that is class A
j = B(i) # this will return exception
j.functionIneed()
I cannot change class A. If I could I would implement functionIneed to class A, but it is impossible because of structure of code.
Python does not support "casting". You will need to write B.__init__() so that it can take an A and initialize itself appropriately.
I have a strong suspicion, nay, conviction, that there is something horribly wrong with your program design that it requires you to do this. In Python, unlike Java, very few problems require classes to solve. If there's a function you need, simply define it:
def function_i_need(a):
"""parameter a: an instance of A"""
pass # do something with 'a'
However, if I cannot dissuade you from making your function a method of the class, you can change an instance's class by setting its __class__ attribute:
>>> class A(object):
... def __init__(self):
... pass
...
>>> class B(A):
... def functionIneed(self):
... print 'functionIneed'
...
>>> a = A()
>>> a.functionIneed()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'functionIneed'
>>> a.__class__ = B
>>> a.functionIneed()
functionIneed
This will work as long as B has no __init__ method, since, obviously, that __init__ will never be called.
You said you want to implement something like this:
class B(A):
def functionIneed():
pass
But really what you would be making is something more like this (unless you had intended on making a class or static method in the first place):
class B(A):
def functionIneed(self):
pass
Then you can call B.functionIneed(instance_of_A). (This is one of the advantages of having to pass self explicitly to methods.)
You did not correctly define your classes.
Should be like this:
class A(object):
def __init__(self):
pass
class B(A):
def __init__(self):
super(B,self).__init__()
def functionIneed(self):
pass
Then you can
j=B()
j.fuctionIneed()
as expected
You forgot to refer to the ins
Just thinking outside the box:
Instead of a new class with the function you want, how about just adding the function to the class or instance you already have?
There is a good description of this in
Adding a Method to an Existing Object Instance
How about:
i = module.getObject() # i will get object that is class A
try:
i.functionIneed()
except AttributeError:
# handle case when u have a bad object
Read up on duck typing.

Can't access parent member variable in Python

I'm trying to access a parent member variable from an extended class. But running the following code...
class Mother(object):
def __init__(self):
self._haircolor = "Brown"
class Child(Mother):
def __init__(self):
Mother.__init__(self)
def print_haircolor(self):
print Mother._haircolor
c = Child()
c.print_haircolor()
Gets me this error:
AttributeError: type object 'Mother' has no attribute '_haircolor'
What am I doing wrong?
You're mixing up class and instance attributes.
print self._haircolor
You want the instance attribute, not the class attribute, so you should use self._haircolor.
Also, you really should use super in the __init__ in case you decide to change your inheritance to Father or something.
class Child(Mother):
def __init__(self):
super(Child, self).__init__()
def print_haircolor(self):
print self._haircolor

Categories