How can i add atrributes to the class method from outside class? - python

This is gonna be my first question on this website. If I do mistake about English, sorry.
Okey, my question is how can I add or set attribute to the class method from outside class?
If i am not wrong,we use settatr() to do this. Can you guys help me pls?
class sss():
def __init__(self,name,surname):
self.name = name
self.surname = surname
def method1(self):
a = "Python"
When we do this:
object = sss("Adam","Roger") #This 2 lines are on outside the class
setattr(object,"Age",19)
What exactly happens? Now this "Age" attribute belong to our object? What is the value of the "Age" attribute now? I mean is that class attribute or what?
My second question is how can I add attribute to the class method?
Thank you

If you instanciate your class with e.g. person = Sss("Adam", "Roger") you can access and add attributes with a dot like this:
person.age = 19
Full example:
class Sss:
# You should name your class with capital letter and without brackets
def __init__(self, name, surname):
self.name = name
self.surname = surname
person = Sss("Adam", "Roger")
print(person.name) # access attribute
person.age = 19 # add attribute
print(person.age)

As #Julian Fock mentioned, you can add attributes to an object by simply writing statements, such as person.age = 19. Your instance/object of the sss-Person class would now have this attribute, but not the class itself.
To modify the class sss-Person itself, you would need to implement some ugly methods, which would be labelled as "hacky" or "bad practices" by most programmers. Companies could refuse to accept the code as valid. You should instead consider using other methods such as class inheritance, where you can derive a modified class adding more advanced functionality.
Still, changing a class definition can be useful for debugging or exceptional emergencies. In that case, you can define external functions, and link them to override your class methods as follows:
# A) Initial Analysis
class Person:
def __init__(self,name,surname):
self.name = name
self.surname = surname
def method1(self):
a = "Python"
person1 = Person("Adam","Roger")
person2 = Person("Adam","Roger")
person1.age = 19
print(person1.age)
# Output: 19
# print(person2.age)
# AttributeError: 'Person' object has no attribute 'age'
# B) Change class attributes
def __init2__(self, name, surname, age):
self.name = name
self.surname = surname
self.age = age
Person.__init__ = __init2__
person3 = Person("Adam","Roger", 20)
print(person3.age)
# Output: 20
# person4 = Person("Adam","Roger")
# TypeError: __init2__() missing 1 required positional argument: 'age'
# C) Overwrite method1
def method2(self):
self.a = "Python"
Person.method1 = method2
person5 = Person("Adam","Roger",44)
person5.method1()
print(person5.a)
# Output: "Python"

What is "Age" attribute now? I mean is that class attribute or what?
Age is now an instance variable on your instance of sss named object.
How can i add attribute to the class method?
I'm not sure what you're asking for here.

PS.: I will not get into the merit of wether it is recommended to do things that I will exemplify here.
Adding to Bill Lynch's answer
What is "Age" attribute now? I mean is that class attribute or what?
Age is now an instance variable on your instance of sss named object.
PS.: Don't use object for it is a keyword in python.
What is the value of the "Age" attribute now?
The value is 19.
I mean is that class attribute or what?
It is a attribute of the instance you created from the class, and only for that instance.
how can I add attribute to the class method?
If you want to add the attribute to the class so that every instance has a new attribute of your choosing, you can do this:
setattr(sss, 'b', 'Python')
obj1 = sss("Adam", "Roger")
print(obj1.b)
obj2 = sss("Adam", "Roger")
print(obj2.b)
obj2.b = "New"
print(obj1.b) # will still be Python
print(obj2.b) # now will be New
If you want to overwrite method1 with a new method:
sss_obj = sss("Adam", "Roger")
def method1(self):
self.b = 'New'
setattr(sss, 'method1', method1)
print('Should be False because the instance has no b attribute yet.', hasattr(sss_obj, 'b'))
sss_obj.method1()
print('Now it has and b value is', sss_obj.b)
If you want to change the method on a specific instance of class sss:
sss_obj = sss("Adam", "Roger")
sss_obj2 = sss("Adam", "Roger")
def method1():
sss_obj2.b = 'New'
setattr(sss_obj2, 'method1', method1)
sss_obj.method1()
print('Should be False because method1 from instance sss_obj does not set b.', hasattr(sss_obj, 'b'))
sss_obj2.method1()
print('Now on instance 2 the b value is', sss_obj2.b)
If you want to change the source of the method as a string programatically:
sss_obj = sss("Adam", "Roger")
new_method_source = 'self.b = "NotRecommended"\n' \
'print("Got into changed method")'
def method1(self):
return exec(
compile(new_method_source, '', mode='exec'),
None,
{
'self': self
}
)
setattr(sss, 'method1', method1)
If you want to change the code from method1, first grab the source with the following line
method1_src = inspect.getsource(sss_obj.method1)
Then change the string as you will and do a similar thing as previously mentioned (compile and stuff).
Cheers

Related

Why won't my python class inherit from another class?

class Media_Work(object):
def __init__(self):
_id: int = 0
_IdDict: {}
_titleDict: {}
class Poem(Media_Work):
def __init__(self, id, title, author, content, age, mtype, verbs):
super().__init__()
self.id = id
self.title = title
self.author = author
self.content = content
self.age = age
self.mtype = mtype
self.verbs = verbs
Poem._IdDict.update({id: self})
My error message:
AttributeError: 'Poem' object has no attribute '_IdDict'
Similar error if I change the bottom line to:
self._IdDict.update({id:self})
New error message:
AttributeError: type object 'Poem' has no attribute '_IdDict'
It is inheriting, but you haven't defined the _IdDict class attribute. _IdDict: {} is type hint, not a definition, and it's a local name in __init__, not a class attribute.
Here's an example of how to fix it. You might need to tailor this to fit your needs:
class Media_Work:
_IdDict = {}
class Poem(Media_Work):
def __init__(self, _id):
Poem._IdDict.update({_id: self})
Example usage:
>>> p = Poem(17)
>>> Poem._IdDict
{17: <__main__.Poem object at 0x7f13689a3ba8>}
>>> Media_Work._IdDict
{17: <__main__.Poem object at 0x7f13689a3ba8>}
By the way, don't use id as a variable name, since it's a builtin.
As-written, your intended dict _IdDict is really a type hint (see comment by ShadowRanger)!
Set the attribute as either a class variable (probably your intention) or assign the attribute in __init__()
Class Variable
Reference will be created in class declaration and shared by all instances of the class
There is no need to call super() to init in this case
class Media_Work():
_id = 0
_IdDict = {}
Attribute
Reference will be created at class init and unique to each instance of the class
class Media_Work():
def __init__(self):
self._id = 0
self._IdDict = {}
[My previous version of this answer was lacking].... You have two issues there. The first is that you failed to assign a value to _IdDict so it was not created. Second, you defined it in the wrong scope. If you wanted to create a Class attribute you need to refer to it as Media_Work._IdDict from within the __init__ method or you needed to define it outside the method. Such as:
class Media_Work(object):
_id: int = 0
_IdDict: {} = {}
_titleDict: {} = {}
def __init__(self):
Media_Work._id = 0

When assigning class name as a identifier to a variable there is a confusing behavior

I was playing around in Python as I am relatively new to it. Below is a snippet
class Person:
version = "1.0"
def __init__(self, name="john doe",age=25):
self.name = name
self.first_name = name.split()[0]
self.second_name = name.split()[1]
self.age = age
def printi(self):
print(self.name)
new_person = Person()
new_person.printi()
refPerson = Person
print(refPerson.version)
another_one = refPerson()
#another_one.version = "2.0"
print(another_one.version)
another_one.printi()
print(Person.version)
Person.version = "2.0"
print(another_one.version)
print(refPerson.version)
And If you notice, the class name Person is directly assigned to a variable refPerson. I was under the impression that post this assignment new class of name refPerson will be created. But when I modify the Person class attribute, I could see that the value change is reflected in the new class. What am I missing here? I just need a clear picture.
Thanks in advance.
Classes are first-class objects in Python; you can pass references to them around.
Person is a reference to the class defined by the class statement. Person() (calling the class object like a function) returns an instance of that class.
Attribute lookup rules can get complicated, but for this example the following simplification will suffice. Since neither new_person.version nor another_one.version is defined, an attempt to look either one up will result in a class attribute lookup. That is, new_person.version == type(new_person).version.
If you create an instance attribute with the same name, it will shadow the class attribute:
>>> new_person.version = 3
>>> new_person.version
3
>>> type(new_person).version
"1.0"
>>> another_one.version
"1.0"
Going into more detail than you are probably ready for at this stage, Person() breaks down into the following calls:
Person() is equivalent to Person.__call__(Person), where __call__ is an instance method of the class type, of which Person is an instance. (That is, type(Person) returns type.)
Person.__call__ calls Person.__new__, which returns a new instance of Person; call it p.
Person.__call__ then calls Person.__init__ with p as its argument.
Finally, Person.__call__ returns p.

How to set an instance of base class as attribute of child class?

I am trying to set an instance of base class (Human) as attribute (baby) of child class (Mother) but got unexpected behavior.
In my example I was expecting print(mother.baby.name) to print Tom.
How can I set an instance of base class as attribute of child class?
I am pretty sure I need deeper understanding of classes in python but what am I missing here?
class Human:
def __init__(self, name):
Human.name = name
class Mother(Human):
def __init__(self, name_mother, name_baby):
Mother.baby = Human(name_baby)
Human.__init__(self, name_mother)
mother = Mother("Mary", "Tom")
print(mother.name)
print(mother.baby.name)
Output:
Mary
Mary
Note: Am using Python 3.5.2
The problem
You are setting the names on the type of the object that is being initialized.
After mother = Mother("Mary", "Tom") the attribute Human.name has been set to 'Mary' via line 2 of Mother.__init__.
Neither the instance mother nor mother.baby has the attribute name:
>>> vars(mother)
>>> {}
>>> vars(mother.baby)
>>> {}
Additionally, the class Mother lacks the attribute as well:
>>> 'name' in vars(Mother)
>>> False
The attribute name has only been set on the class Human:
>>> vars(Human)['name']
>>> 'Mary'
Thus, mother.name falls back to Human.name because the attribute name cannot be found on the instance mother or the class Mother. (Python tries to search the base classes for an appropriate attribute when lookup on the instance and on the class level fails.)
mother.baby.name also falls back to Human.name because name cannot be found in the instance mother.baby, but on the class of that instance (Human).
How to fix it
You want to set the attribute on the instance (self) here.
class Human:
def __init__(self, name):
self.name = name
class Mother(Human):
def __init__(self, name_mother, name_baby):
self.baby = Human(name_baby)
super().__init__(name_mother)
mother = Mother("Mary", "Tom")
print(mother.name)
print(mother.baby.name)
Output:
Mary
Tom
I also changed the line
Human.__init__(self, name_mother)
to
super().__init__(name_mother)
because this avoids hardcoding the name of the base class.

Can't print out the child class variable in method overloading

I am a newbie in Python so please bear with me if the question is very simple for you.
Can someone explain why the class variable, name, in Dog class causes an error in the following example? It doesn't make sense to me that d.name is ok to be called, but d.eat() is not ok for method overloading. Thank you very much in advance for your help!
class Animal: # parent class
name = 'Animal'
def eat(self):
print "Animal eating"
class Dog(Animal): # child class
name = 'Dog'
def eat(self):
print name
d = Dog()
print d.name # OK
d.eat() # Error !
Since name is a class member variable, not a global nor local variable, it needs the . operator to look it up. Try one of these:
print self.name
print Dog.name
Which one you use will depend upon other aspects of your program design. The first will attempt to look up name in the current object, falling back to the class definition if required. The second will always use the class definition.
The reason for your error is because you can't define the method with the variable name within that scope. If you do this, then you won't have the error:
class Animal: # parent class
name = 'Animal'
def eat(self):
print "Animal eating"
class Dog(Animal): # child class
name = 'Dog'
def eat(self):
# name does not exist within this scope
print self.name
d = Dog()
print d.name # OK
d.eat() # No longer an error!

Where to set the class members in Python? [duplicate]

Is there any difference at all between these classes besides the name?
class WithClass ():
def __init__(self):
self.value = "Bob"
def my_func(self):
print(self.value)
class WithoutClass ():
value = "Bob"
def my_func(self):
print(self.value)
Does it make any difference if I use or don't use the __init__ method for declaring the variable value?
My main worry is that I'll be using it one way, when that'll cause me further problems down the road.
Variable set outside __init__ belong to the class. They're shared by all instances.
Variables created inside __init__ (and all other method functions) and prefaced with self. belong to the object instance.
Without Self
Create some objects:
class foo(object):
x = 'original class'
c1, c2 = foo(), foo()
I can change the c1 instance, and it will not affect the c2 instance:
c1.x = 'changed instance'
c2.x
>>> 'original class'
But if I change the foo class, all instances of that class will be changed as well:
foo.x = 'changed class'
c2.x
>>> 'changed class'
Please note how Python scoping works here:
c1.x
>>> 'changed instance'
With Self
Changing the class does not affect the instances:
class foo(object):
def __init__(self):
self.x = 'original self'
c1 = foo()
foo.x = 'changed class'
c1.x
>>> 'original self'
I would like to add something to the responses that I read in this thread and this thread (which references this one).
Disclaimer: this remarks come from the experiments I ran
Variables outside __init__:
These are, in fact, static class variables and are, therefore, accesible to all instances of the class.
Variables inside __init__:
The value of these instance variables are only accesible to the instance at hand (through the self reference)
My contribution:
One thing that programmers must consider when using static class variables is that they can be shadowed by instance variables (if you are accessing the static class variables through the self reference).
Explanation:
Previously, I thought that both ways of declaring the variables were exactly the same (silly me), and that was partly because I could access both kind of variables through the self reference. It was now, when I ran into trouble, that I researched the topic and cleared it up.
The problem with accessing static class variables through the
self reference is that it only references the static class variable if there is no instance variable with the same name, and to make things worse, trying to redefine a static class variable through the self reference does not work because an instance variable is created which then shadows the previously-accesible static class variable.
To get around this problem, you should always reference static class variables through the name of the class.
Example:
#!/usr/bin/env python
class Foo:
static_var = 'every instance has access'
def __init__(self,name):
self.instance_var = 'I am %s' % name
def printAll(self):
print 'self.instance_var = %s' % self.instance_var
print 'self.static_var = %s' % self.static_var
print 'Foo.static_var = %s' % Foo.static_var
f1 = Foo('f1')
f1.printAll()
f1.static_var = 'Shadowing static_var'
f1.printAll()
f2 = Foo('f2')
f2.printAll()
Foo.static_var = 'modified class'
f1.printAll()
f2.printAll()
Output:
self.instance_var = I am f1
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = every instance has access
self.instance_var = I am f2
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = modified class
self.instance_var = I am f2
self.static_var = modified class
Foo.static_var = modified class
I hope this is helpful to someone
further to S.Lott's reply, class variables get passed to metaclass new method and can be accessed through the dictionary when a metaclass is defined. So, class variables can be accessed even before classes are created and instantiated.
for example:
class meta(type):
def __new__(cls,name,bases,dicto):
# two chars missing in original of next line ...
if dicto['class_var'] == 'A':
print 'There'
class proxyclass(object):
class_var = 'A'
__metaclass__ = meta
...
...
class User(object):
email = 'none'
firstname = 'none'
lastname = 'none'
def __init__(self, email=None, firstname=None, lastname=None):
self.email = email
self.firstname = firstname
self.lastname = lastname
#classmethod
def print_var(cls, obj):
print ("obj.email obj.firstname obj.lastname")
print(obj.email, obj.firstname, obj.lastname)
print("cls.email cls.firstname cls.lastname")
print(cls.email, cls.firstname, cls.lastname)
u1 = User(email='abc#xyz', firstname='first', lastname='last')
User.print_var(u1)
In the above code, the User class has 3 global variables, each with value 'none'. u1 is the object created by instantiating this class. The method print_var prints the value of class variables of class User and object variables of object u1. In the output shown below, each of the class variables User.email, User.firstname and User.lastname has value 'none', while the object variables u1.email, u1.firstname and u1.lastname have values 'abc#xyz', 'first' and 'last'.
obj.email obj.firstname obj.lastname
('abc#xyz', 'first', 'last')
cls.email cls.firstname cls.lastname
('none', 'none', 'none')
In Python, a class comes with member functions (methods), class variables, attributes/instance variables (and probably class methods too):
class Employee:
# Class Variable
company = "mycompany.com"
def __init__(self, first_name, last_name, position):
# Instance Variables
self._first_name = first_name
self._last_name = last_name
self._position = position
# Member function
def get_full_name(self):
return f"{self._first_name} {self._last_name}"
By creating an instance of the object
my_employee = Employee("John", "Wood", "Software Engineer")
we essentially trigger __init__ that is going to initialise the instance variables of the newly created Employee. This means that _first_name, _last_name and _position are explicit parameters of the specific my_employee instance.
Likewise, member functions return information or change the state of a specific instance.
Now any variable defined outside the constructor __init__ are considered to be class variables. Those variables are shared amongst all the instances of the class.
john = Employee("John", "Wood", "Software Engineer")
bob = Employee("Bob", "Smith", "DevOps Engineer0")
print(john.get_full_name())
print(bob.get_full_name())
print(john.company)
print(bob.company)
>>> John Wood
>>> Bob Smith
>>> mycompany.com
>>> mycompany.com
You can also use class methods in order to change the class variable for all the instances of the class. For example:
#classmethod
def change_my_companys_name(cls, name):
cls.company = name
and now change_my_companys_name()
bob.change_my_companys_name("mynewcompany.com")
will have effect on all the instances of class Employee:
print(bob.company)
print(john.company)
>>> mynewcompany.com
>>> mynewcompany.com
Example code:
class inside:
def __init__(self):
self.l = []
def insert(self, element):
self.l.append(element)
class outside:
l = [] # static variable - the same for all instances
def insert(self, element):
self.l.append(element)
def main():
x = inside()
x.insert(8)
print(x.l) # [8]
y = inside()
print(y.l) # []
# ----------------------------
x = outside()
x.insert(8)
print(x.l) # [8]
y = outside()
print(y.l) # [8] # here is the difference
if __name__ == '__main__':
main()
This is very easy to understand if you track class and instance dictionaries.
class C:
one = 42
def __init__(self,val):
self.two=val
ci=C(50)
print(ci.__dict__)
print(C.__dict__)
The result will be like this:
{'two': 50}
{'__module__': '__main__', 'one': 42, '__init__': <function C.__init__ at 0x00000213069BF6A8>, '__dict__': <attribute '__dict__' of 'C' objects>, '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None}
Note I set the full results in here but what is important that the instance ci dict will be just {'two': 50}, and class dictionary will have the 'one': 42 key value pair inside.
This is all you should know about that specific variables.
classes are like blueprints to create objects. Let's make a metaphor with building a house. You have the blueprint of the house so you can build a house. You can build as many houses as your resources allow.
In this metaphor, the blueprint is the class and the house is the instantiation of the class, creating an object.
The houses have common attributes like having a roof, living room, etc. This is where you init method goes. It constructs the object (house) with the attributes you want.
Lets suppose you have:
`class house:`
`roof = True`
`def __init__(self, color):`
`self.wallcolor = color`
>> create little goldlock's house:
>> goldlock = house() #() invoke's class house, not function
>> goldlock.roof
>> True
all house's have roofs, now let's define goldlock's wall color to white:
>> goldlock.wallcolor = 'white'
>>goldlock.wallcolor
>> 'white'
class foo(object):
mStatic = 12
def __init__(self):
self.x = "OBj"
Considering that foo has no access to x at all (FACT)
the conflict now is in accessing mStatic by an instance or directly by the class .
think of it in the terms of Python's memory management :
12 value is on the memory and the name mStatic (which accessible from the class)
points to it .
c1, c2 = foo(), foo()
this line makes two instances , which includes the name mStatic that points to the value 12 (till now) .
foo.mStatic = 99
this makes mStatic name pointing to a new place in the memory which has the value 99 inside it .
and because the (babies) c1 , c2 are still following (daddy) foo , they has the same name (c1.mStatic & c2.mStatic ) pointing to the same new value .
but once each baby decides to walk alone , things differs :
c1.mStatic ="c1 Control"
c2.mStatic ="c2 Control"
from now and later , each one in that family (c1,c2,foo) has its mStatica pointing to different value .
[Please, try use id() function for all of(c1,c2,foo) in different sates that we talked about , i think it will make things better ]
and this is how our real life goes . sons inherit some beliefs from their father and these beliefs still identical to father's ones until sons decide to change it .
HOPE IT WILL HELP
As noted by S.Lott,
Variable set outside init belong to the class. They're shared by
all instances.
Variables created inside init (and all other method functions) and
prefaced with self. belong to the object instance.
However,
Note that class variables can be accessed via self.<var> until they are masked by an object variable with a similar name This means that reading self.<var> before assigning it a value will return the value of Class.<var> but afterwards it will return obj.<var> . Here is an example
In [20]: class MyClass:
...: elem = 123
...:
...: def update(self,i):
...: self.elem=i
...: def print(self):
...: print (MyClass.elem, self.elem)
...:
...: c1 = MyClass()
...: c2 = MyClass()
...: c1.print()
...: c2.print()
123 123
123 123
In [21]: c1.update(1)
...: c2.update(42)
...: c1.print()
...: c2.print()
123 1
123 42
In [22]: MyClass.elem=22
...: c1.print()
...: c2.print()
22 1
22 42
Second note: Consider slots. They may offer a better way to implement object variables.
Try this and check the difference
class test:
f = 3
def __init__(s, f):
s.__class__.f = f
s.f = s.__class__.f
print(f'def __init__(s, {f})')
print(f's.__class__.f = {f}')
print(f's.f={s.__class__.f}')
print(f'f={f}')
print('===============init over===========')
def setinstancetoOne(s, f):
print(f'def setinstancetoOne(s, {f})')
s.f = f
print(f'class var f = {f}')
def useClassname(test):
print(f'>>>>def useClassname({test})')
print(f'test.f {test.f}')
def p_method(s):
print(f'>>>>def p_method({s})')
print(f's.f {s.f}')
print(f'test.f {test.f}')
print(f's.__class__.f {s.__class__.f}')
print(f'class var f={f}')
# test.__init__.f = 19
t = test(2)
t.useClassname()
t.p_method()
print(f'Outside class t.f {t.f}')
print(f'Outside class test.f {test.f}')
print('______difference__________')
t = test(2)
t.setinstancetoOne(1)
t.useClass()
t.p_method()
print(f'Outside class instance variable(2) {t.f}')
print(f'Outside class class variable(3) {test.f}')

Categories