Is it possible to add a base class to an object instance (not a class!) at runtime? Something along the lines of how Object#extend works in Ruby:
class Gentleman(object):
def introduce_self(self):
return "Hello, my name is %s" % self.name
class Person(object):
def __init__(self, name):
self.name = name
p = Person("John")
# how to implement this method?
extend(p, Gentleman)
p.introduce_self() # => "Hello, my name is John"
This dynamically defines a new class GentlePerson, and reassigns p's class to it:
class Gentleman(object):
def introduce_self(self):
return "Hello, my name is %s" % self.name
class Person(object):
def __init__(self, name):
self.name = name
p = Person("John")
p.__class__ = type('GentlePerson',(Person,Gentleman),{})
print(p.introduce_self())
# "Hello, my name is John"
Per your request, this modifies p's bases, but does not alter p's original class Person. Thus, other instances of Person are unaffected (and would raise an AttributeError if introduce_self were called).
Although it was not directly asked in the question, I'll add for googlers and curiosity seekers, that it is also possible to dynamically change a class's bases but (AFAIK) only if the class does not inherit directly from object:
class Gentleman(object):
def introduce_self(self):
return "Hello, my name is %s" % self.name
class Base(object):pass
class Person(Base):
def __init__(self, name):
self.name = name
p = Person("John")
Person.__bases__=(Gentleman,object,)
print(p.introduce_self())
# "Hello, my name is John"
q = Person("Pete")
print(q.introduce_self())
# Hello, my name is Pete
Slightly cleaner version:
def extend_instance(obj, cls):
"""Apply mixins to a class instance after creation"""
base_cls = obj.__class__
base_cls_name = obj.__class__.__name__
obj.__class__ = type(base_cls_name, (base_cls, cls),{})
Although it's already answered, here is a function:
def extend(instance, new_class):
instance.__class__ = type(
'%s_extended_with_%s' % (instance.__class__.__name__, new_class.__name__),
(instance.__class__, new_class),
{},
)
Related
I am trying to learn the difference between the instance attributes and class attributes and attributes. I have the code below and I am trying to distinguish these factors.
class Student:
firstname = ""
lastname = ""
ucid = ""
department = ""
nationality = ""
courses = {}
def __init__(self, fname, lname, ucid, dept, n):
self.firstname = fname
self.lastname = lname
self.ucid = ucid
self.department = dept
self.nationality = n
self.courses = {}
def setName(self, fname, lname):
self.firstname = fname
self.lastname = lname
def setDepartment(self, d):
self.department = d
def setUcid(self, u):
self.ucid = u
def setNationality(self, n):
self.nationality = n
def addCourse(self, coursename, gpa):
self.courses[coursename] = gpa
def printAll(self):
print("The name of the student is ", self.firstname, self.lastname)
print("nationality and UCID: ", self.nationality, self.ucid)
print("Department: ", self.department)
print("Result: ")
for key in self.courses.keys():
print(key, self.courses[key])
print("--------------------\n")
s1=Student("Beth","Bean","30303","Computer Science","International")
s1.addCourse("SCIENCE",3.75)
s1.printAll()
s2=Student("Mac","Miller","30303","Envr Science","American")
s2.addCourse("MATH",4.00)
s2.printAll()
From what I understood the attributes would be: firstname,lastname,ucid,department,nationality,courses But I do not know what instance attributes and class attributes would be.
I am trying to learn the difference between the instance attributes and class attributes and attributes.
there should be two attributes, class attribute, instance attribute. or instance attribute&none-instance attribute for convenience.
instance attribute
these are things activated only when __init__ has been called.
you can only access thenm after Class is initialized, which commonly seen as self.xxx.
and methods in class with self as its first parameter(normally), these functions are instance methods, and you can only access after you initialized the Class.
and methods in class with #property deco, they are instance attributes
common seen instance attribute
class Name(object):
def __init__(self):
self.age = 100
def func(self):
pass
#property
def age(self):
return self.age
class attribute
non-instance attribute or static attribute, whatever you call it
these things stay activated along with Class.
which means you can access them whenever you need to, like __init__, even in __new__.
they can be called by both Class and instance.
common seen class attribute
class Name(object):
attr = 'Im class attribute'
there is something else you may should know, class method, which stay activated along with Class but the difference is class method can't be called by instance but only Class. example here
class Name(object)
attr = 'Im class attribute'
#classmethod
def get_attr(cls):
return cls.attr
Conclusion
"class attribute" can be called by both instance and Class
"instance attribute" can only called by instance.
I have a question regarding accessing class variable from the class.
Which way is preferred? Why Version 1 works? name isn't instance variable, how it can be accessed using .self?
Version 1:
class Base:
def get_name(self): return self.name
class Child_1(Base):
name = 'Child 1 name'
child = Child_1()
print(child.get_name())
Version 2:
class Base:
#classmethod
def get_name(cls): return cls.name
class Child_1(Base):
name = 'Child 1 name'
child = Child_1()
print(child.get_name())
Motivation behind this, is defining name once for all instances to save space.
self.name by default refers to cls.name
if you set it it only sets it for that instance however
self.name = "bob"
now overrides the class level name
just the same for methods as well
class Foo:
#staticmethod
def hello():
print("Hi There From Foo!")
def __init__(self):
self.hello() #this works
Foo.hello() # this also works
Foo() # print from in the init
I am new to OOP. My idea was to implement the following class:
class name(object, name):
def __init__(self, name):
print name
Then the idea was to create two instances of that class:
person1 = name("jean")
person2 = name("dean")
I know, that is not possible, but how can I pass an input-argument into an instance of a class?
The problem in your initial definition of the class is that you've written:
class name(object, name):
This means that the class inherits the base class called "object", and the base class called "name". However, there is no base class called "name", so it fails. Instead, all you need to do is have the variable in the special init method, which will mean that the class takes it as a variable.
class name(object):
def __init__(self, name):
print name
If you wanted to use the variable in other methods that you define within the class, you can assign name to self.name, and use that in any other method in the class without needing to pass it to the method.
For example:
class name(object):
def __init__(self, name):
self.name = name
def PrintName(self):
print self.name
a = name('bob')
a.PrintName()
bob
>>> class name(object):
... def __init__(self, name):
... self.name = name
...
>>> person1 = name("jean")
>>> person2 = name("dean")
>>> person1.name
'jean'
>>> person2.name
'dean'
>>>
You just need to do it in correct syntax. Let me give you a minimal example I just did with Python interactive shell:
>>> class MyNameClass():
... def __init__(self, myname):
... print myname
...
>>> p1 = MyNameClass('John')
John
Remove the name param from the class declaration. The init method is used to pass arguments to a class at creation.
class Person(object):
def __init__(self, name):
self.name = name
me = Person("TheLazyScripter")
print me.name
Actually you can!
How about this?
class name(str):
def __init__(self, name):
print (name)
# ------
person1 = name("jean")
person2 = name("dean")
print('===')
print(person1)
print(person2)
Output:
jean
dean
===
jean
dean
Python Classes
class name:
def __init__(self, name):
self.name = name
print("name: "+name)
Somewhere else:
john = name("john")
Output:
name: john
class Person:
def init(self,name,age,weight,sex,mob_no,place):
self.name = str(name)
self.age = int(age)
self.weight = int(weight)
self.sex = str(sex)
self.mob_no = int(mob_no)
self.place = str(place)
Creating an instance to class Person
p1 = Person(Muthuswamy,50,70,Male,94*****23,India)
print(p1.name)
print(p1.place)
Output
Muthuswamy
India
Hi I am trying to use composition to create a new class using instances of another class when I try to turn the new object into a dictionary using __dict__, it's shows me <__main__.myobjec object at 0x00000000029CA908>, not sure am I using the __dict__ incorrectly though I have heard its related to new classes, any help greatly appreciated.
class User:
def __init__(self, name, job=None):
self.name = name
self.job = job
class Customer(User):
_ID = 100
def __init__(self, name, job=None):
self.name = name
self.job = job
class Account:
_ID = 0
def __init__(self, name, job=None):
self.customer = Customer(name , "Customer")
def __getattr__(self, attr):
return getattr(self.customer, attr)
>>> A = Account("Abdi")
>>> A.__dict__
{'customer': <__main__.Customer object at 0x109fdbfc8>}
>>>
You need to implement the __repr__ method to represent all of the instances of the Customer class.
def __repr__(self): return repr(self.__dict__) # the dictionary of attributes in __repr__
My code is like this, and I want to use super() to inherit the features of Papa, how to do that?
class Mama(object):
def __init__(self):
self.name = 'Mama'
def feature(self):
print "%s have big eyes" % self.name
class Papa(object):
def __init__(self):
self.name = 'Papa'
def feature(self):
print "%s have fierce beards" % self.name
class Offspring(Mama,Papa):
def __init__(self, name):
self.name = name
def feature(self):
super(Offspring, self).feature()
offspring = Offspring('Tommy')
offspring.feature()
# This will result "Tommy have big eyes"
You can alter the MRO (method resolution order) by inheriting from Papa first:
class Offspring(Papa, Mama):
The alternative is to skip the MRO and call the (unbound) method on Papa explicitly:
class Offspring(Mama, Papa):
def __init__(self, name):
self.name = name
def feature(self):
Papa.feature(self)
All the classes in your heirachy need to use super for it to go through all of the methods. Eventually, you will run into a problem whereby the next superclass is object, which doesn't have feature, so you also need to detect that case and ignore it - ie, you need to do this:
class Mama(object):
def __init__(self):
self.name = 'Mama'
def feature(self):
try:
super(Mama, self).feature()
except AttributeError:
# only superclass is object
pass
print "%s have big eyes" % self.name
class Papa(object):
def __init__(self):
self.name = 'Papa'
def feature(self):
try:
super(Papa, self).feature()
except AttributeError:
# only superclass is object
pass
print "%s have fierce beards" % self.name
class Offspring(Mama,Papa):
def __init__(self, name):
self.name = name
def feature(self):
super(Offspring, self).feature()
Instead of catching the AttributeError, you could also make a further class that exists only to provide feature (without calling super) for other classes to inherit. Then both Mama and Papa inherit that class and override feature, like this:
class Grandma(object):
def feature(self):
pass
class Mama(Grandma):
def feature(self):
super(Mama, self).feature()
print "%s have big eyes" % self.name
You may want to consider making feature an abstractmethod, to emphasise that it exists only for inheritance.
In either case, what will happen is that you will keep calling the next method until you get to the end of the chain. If neither Mama nor Papa calls super, you will always stop after one call.