Suppose I have the following codes:
lens_A = Lens(...) # declare an object of type 'Lens' called 'lens_A'
table = Bench() # declare an object 'Bench' called 'table'
table.addcomponent(lens_A, 10)
addcomponent(self, component, position): # a method inside the class Bench
self.__component_class.append(component)
self.__component_position.append(position)
self.__component_name.append(...) # how to do this????
I want to write the last line such that I can add the name of the class variable ('lensA') to the list self.__component_name, but not the location of the instance (which is done in self.__component_class). How to do that?
You can find it but it may not be practical and this may not work depending on the scope where it is executed. It seems like a hack and not the correct way to solve the problem.
# locals() might work instead of globals()
>>> class Foo(object):
pass
>>> lion = Foo()
>>> zebra = Foo()
>>> zebra, lion
(<__main__.Foo object at 0x02F82CF0>, <__main__.Foo object at 0x03078FD0>)
>>> for k, v in globals().items():
if v in (lion, zebra):
print 'object:{} - name:{}'.format(v, k)
object:<__main__.Foo object at 0x03078FD0> - name:lion
object:<__main__.Foo object at 0x02F82CF0> - name:zebra
>>>
Related
This following code works fine, and shows a way to create attributes and methods in execution time:
class Pessoa:
pass
p = Pessoa( )
p.nome = 'fulano'
if hasattr(p, 'nome'):
print(p)
p.get_name = lambda self:'Sr.{}'.format(self.nome)
But, I think my way to create methods is not correct. There are another way to create a method dynamically ?
[Although this has really been answered in Steven Rumbalski's comment, pointing to two independent questions, I'm adding a short combined answer here.]
Yes, you're right that this does not correctly define a method.
>>> class C:
... pass
...
>>> p = C()
>>> p.name = 'nickie'
>>> p.get_name = lambda self: 'Dr. {}'.format(self.name)
>>> p.get_name()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() takes exactly 1 argument (0 given)
Here's how you can call the function that is stored in object p's attribute called get_name:
>>> p.get_name(p)
'Dr. nickie'
For properly defining an instance method dynamically, take a look at the answers to a relevant question.
If you want to define a class method dynamically, you have to define it as:
>>> C.get_name = lambda self: 'Dr. {}'.format(self.name)
Although the method will be added to existing objects, this will not work for p (as it already has its own attribute get_name). However, for a new object:
>>> q = C()
>>> q.name = 'somebody'
>>> q.get_name()
'Dr. somebody'
And (obviously), the method will fail for objects that don't have a name attribute:
>>> r = C()
>>> r.get_name()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
AttributeError: C instance has no attribute 'name'
There are two ways to dynamically create methods in Python 3:
create a method on the class itself: just assign a function to a member ; it is made accessible to all objects of the class, even if they were created before the method was created:
>>> class A: # create a class
def __init__(self, v):
self.val = v
>>> a = A(1) # create an instance
>>> def double(self): # define a plain function
self.val *= 2
>>> A.double = double # makes it a method on the class
>>> a.double() # use it...
>>> a.val
2
create a method on an instance of the class. It is possible in Python 3 thanks to the types module:
>>> def add(self, x): # create a plain function
self.val += x
>>> a.add = types.MethodType(add, a) # make it a method on an instance
>>> a.add(2)
>>> a.val
4
>>> b = A(1)
>>> b.add(2) # chokes on another instance
Traceback (most recent call last):
File "<pyshell#55>", line 1, in <module>
b.add(2)
AttributeError: 'A' object has no attribute 'add'
>>> type(a.add) # it is a true method on a instance
<class 'method'>
>>> type(a.double)
<class 'method'>
A slight variation on method 1 (on class) can be used to create static or class methods:
>>> def static_add(a,b):
return a+b
>>> A.static_add = staticmethod(static_add)
>>> a.static_add(3,4)
7
>>> def show_class(cls):
return str(cls)
>>> A.show_class = classmethod(show_class)
>>> b.show_class()
"<class '__main__.A'>"
Here is how I add methods to classes imported from a library. If I modified the library I would lose the changes at the next library upgrade. I can't create a new derived class because I can't tell the library to use my modified instance. So I monkey patch the existing classes by adding the missing methods:
# Import the standard classes of the shapely library
import shapely.geometry
# Define a function that returns the points of the outer
# and the inner polygons of a Polygon
def _coords_ext_int_polygon(self):
exterior_coords = [self.exterior.coords[:]]
interior_coords = [interior.coords[:] for interior in self.interiors]
return exterior_coords, interior_coords
# Define a function that returns the points of the outer
# and the inner polygons of a MultiPolygon
def _coords_ext_int_multi_polygon(self):
if self.is_empty:
return [], []
exterior_coords = []
interior_coords = []
for part in self:
i, e = part.coords_ext_int()
exterior_coords += i
interior_coords += e
return exterior_coords, interior_coords
# Define a function that saves outer and inner points to a .pt file
def _export_to_pt_file(self, file_name=r'C:\WizardTemp\test.pt'):
'''create a .pt file in the format that pleases thinkdesign'''
e, i = self.coords_ext_int()
with open(file_name, 'w') as f:
for rings in (e, i):
for ring in rings:
for x, y in ring:
f.write('{} {} 0\n'.format(x, y))
# Add the functions to the definition of the classes
# by assigning the functions to new class members
shapely.geometry.Polygon.coords_ext_int = _coords_ext_int_polygon
shapely.geometry.Polygon.export_to_pt_file = _export_to_pt_file
shapely.geometry.MultiPolygon.coords_ext_int = _coords_ext_int_multi_polygon
shapely.geometry.MultiPolygon.export_to_pt_file = _export_to_pt_file
Notice that the same function definition can be assigned to two different classes.
EDIT
In my example I'm not adding methods to a class of mine, I'm adding methods to shapely, an open source library I installed.
In your post you use p.get_name = ... to add a member to the object instance p. I first define a funciton _xxx(), then I add it to the class definition with class.xxx = _xxx.
I don't know your use case, but usually you add variables to instances and you add methods to class definitions, that's why I am showing you how to add methods to the class definition instead of to the instance.
Shapely manages geometric objects and offers methods to calculate the area of the polygons, to add or subtract polygons to each other, and many other really cool things.
My problem is that I need some methods that shapely doesn't provide out of the box.
In my example I created my own method that returns the list of points of the outer profile and the list of points of the inner profiles. I made two methods, one for the Polygon class and one for the MultiPolygon class.
I also need a method to export all the points to a .pt file format. In this case I made only one method that works with both the Polygon and the MultiPolygon classes.
This code is inside a module called shapely_monkeypatch.py (see monkey patch). When the module is imported the functions with the name starting by _ are defined, then they are assigned to the existing classes with names without _. (It is a convention in Python to use _ for names of variables or functions intended for internal use only.)
I shall be maligned, pilloried, and excoriated, but... here is one way I make a keymap for an alphabet of methods within __init__(self).
def __init__(this):
for c in "abcdefghijklmnopqrstuvwxyz":
this.keymap[ord(c)] = eval(f"this.{c}")
Now, with appropriate code, I can press a key in pygame to execute the mapped method.
It is easy enough to use lambdas so one does not even need pre-existing methods... for instance, if __str__(this) is a method, capital P can print the instance string representation using this code:
this.keymap[ord('P')] = lambda: print(this)
but everyone will tell you that eval is bad.
I live to break rules and color outside the boundaries.
I think I have some misconception about class and instance variables. Here is an example code:
class Animal(object):
energy = 10
skills = []
def work(self):
print 'I do something'
self.energy -= 1
def new_skill(self, skill):
self.skills.append(skill)
if __name__ == '__main__':
a1 = Animal()
a2 = Animal()
a1.work()
print a1.energy # result:9
print a2.energy # result:10
a1.new_skill('bark')
a2.new_skill('sleep')
print a1.skills # result:['bark', 'sleep']
print a2.skills # result:['bark', 'sleep']
I thought that energy and skill were class variables, because I declared them out of any method. I modify its values inside the methods in the same way (with self in his declaration, maybe incorrect?). But the results show me that energy takes different values for each object (like a instance variable), while skills seems to be shared (like a class variable). I think I've missed something important...
The trick here is in understanding what self.energy -= 1 does. It's really two expressions; one getting the value of self.energy - 1, and one assigning that back to self.energy.
But the thing that's confusing you is that the references are not interpreted the same way on both sides of that assignment. When Python is told to get self.energy, it tries to find that attribute on the instance, fails, and falls back to the class attribute. However, when it assigns to self.energy, it will always assign to an instance attribute, even though that hadn't previously existed.
You are running into initialization issues based around mutability.
First, the fix. skills and energy are class attributes.
It is a good practice to consider them as read only, as initial values for instance attributes. The classic way to build your class is:
class Animal(object):
energy = 10
skills = []
def __init__(self,en=energy,sk=None):
self.energy = en
self.skills = [] if sk is None else sk
....
Then each instance will have its own attributes, all your problems will disappear.
Second, what's happening with this code?
Why is skills shared, when energy is per-instance?
The -= operator is subtle. it is for in-place assignation if possible. The difference here is that list types are mutable so in-place modification often occurs:
In [6]:
b=[]
print(b,id(b))
b+=['strong']
print(b,id(b))
[] 201781512
['strong'] 201781512
So a1.skills and a2.skills are the same list, which is also accessible as Animal.skills. But energy is a non-mutable int, so modification is impossible. In this case a new int object is created, so each instance manages its own copy of the energy variable:
In [7]:
a=10
print(a,id(a))
a-=1
print(a,id(a))
10 1360251232
9 1360251200
Upon initial creation both attributes are the same object:
>>> a1 = Animal()
>>> a2 = Animal()
>>> a1.energy is a2.energy
True
>>> a1.skills is a2.skills
True
>>> a1 is a2
False
When you assign to a class attribute, it is made local to the instance:
>>> id(a1.energy)
31346816
>>> id(a2.energy)
31346816
>>> a1.work()
I do something
>>> id(a1.energy)
31346840 # id changes as attribute is made local to instance
>>> id(a2.energy)
31346816
The new_skill() method does not assign a new value to the skills array, but rather it appends which modifies the list in place.
If you were to manually add a skill, then the skills list would be come local to the instance:
>>> id(a1.skills)
140668681481032
>>> a1.skills = ['sit', 'jump']
>>> id(a1.skills)
140668681617704
>>> id(a2.skills)
140668681481032
>>> a1.skills
['sit', 'jump']
>>> a2.skills
['bark', 'sleep']
Finally, if you were to delete the instance attribute a1.skills, the reference would revert back to the class attribute:
>>> a1.skills
['sit', 'jump']
>>> del a1.skills
>>> a1.skills
['bark', 'sleep']
>>> id(a1.skills)
140668681481032
Access the class variables through the class, not through self:
class Animal(object):
energy = 10
skills = []
def work(self):
print 'I do something'
self.__class__.energy -= 1
def new_skill(self, skill):
self.__class__.skills.append(skill)
Actually in you code
a1.work();
print a1.energy;
print a2.energy
when you are calling a1.work() an instance variable for a1 object is getting created with the same name that is 'energy'.
And When interpreter comes to 'print a1.energy' it execute the instance variable of object a1.
And when interpreter comes to 'print a2.energy' it execute the class variable, and since you have not changed the value of class variable it shows 10 as output.
I'm trying to use a variable in other python modules, like this:
In a.py:
class Names:
def userNames(self):
self.name = 'Richard'
In z.py:
import a
d = a.Names.name
print d
However this doesn't recognise the variable name and the following error is received:
AttributeError: type object 'Names' has no attribute 'name'
Thanks
There are lots of different scopes a variable can be bound to, which is what you seem to be confused about. Here are a few:
# a.py
a = 1 # (1) is module scope
class A:
a = 2 # (2) is class scope
def __init__(self, a=3): # (3) is function scope
self.a = a # (4) self.a is object scope
def same_as_class(self):
return self.a == A.a # compare object- and class-scope variables
def same_as_module(self):
return self.a == a # compare object- and module-scope variables
Now see how these different variables (I only called them all a to make the point, please don't do this for real) are named, and how they all have different values:
>>> import a
>>> a.a
1 # module scope (1)
>>> a.A.a
2 # class scope (2)
>>> obj1 = a.A() # note the argument defaults to 3 (3)
>>> obj1.a # and this value is bound to the object-scope variable (4)
3
>>> obj.same_as_class()
False # compare the object and class values (3 != 2)
>>> obj2 = a.A(2) # now create a new object, giving an explicit value for (3)
>>> obj2.same_as_class()
True
Note we can also change any of these values:
>>> obj1.same_as_module()
False
>>> obj1.a = 1
>>> obj1.same_as_module()
True
For reference, your z.py above should probably look like:
import a
n = a.Names()
d.userNames()
d = n.name
print d
because a.Name is a class, but you're trying to refer to an object-scope variable. An object is an instance of a class: I've called my instance n. Now I have an object, I can get at the object-scope variable. This is equivalent to Goranek's answer.
In terms of my previous example, you were trying to access obj1.a without having an obj1 or anything like it. I'm not really sure how to make this clearer, without turning this into an introductory essay on OO and Python's type system.
"I've checked again and it's because I'm importing from is a Tornado Framework and the variable is within a class."
Accordingly, your problem is not the one shown in your question.
If you actually want to access the variable of a class (and likely, you don't), then do this:
from othermodule import ClassName
print ClassName.var_i_want
You probably want to access the variable as held inside an instance:
from othermodule import ClassName, some_func
classnameinstance = some_func(blah)
print classnameinstance.var_i_want
Update Now that you have completely changed your question, here is the answer to your new question:
IN this code:
class Names:
def userNames(self):
name = 'Richard'
name is not a variable accessible outside of the activation of the method userNames. This is known as a local variable. You would create an instance variable by changing the code to:
def userNames(self):
self.name = 'Richard'
Then, if you have an instance in a variable called classnameinstance you can do:
print classnameinstance.name
This will only work if the variable has been already created on the instance, as by calling userNames.
You don't need to import the class itself if there is some other way to receive instances of the class.
file:a.py
class Names:
def userNames(self):
self.name = 'Richard'
file:z.py
import a
c = a.Names()
c.userNames()
what_you_want_is = c.name
Btw, this code makes no sense..but this is apparently what you want
Better a.py
class Names:
def userNames(self, name):
self.name = name
Better z.py
import a
c = a.Names()
c.userNames("Stephen or something")
what_you_want_is = c.name
# what_you_want_is is "Stephen or something"
I saw the following Python documentation which says that "define variables in a Class" will be class variables:
"Programmer's note: Variables defined in the class definition are
class variables; they are shared by all instances. "
but as I wrote sample code like this:
class CustomizedMethods(object):
class_var1 = 'foo'
class_var2 = 'bar'
cm1 = CustomizedMethods()
cm2 = CustomizedMethods()
print cm1.class_var1, cm1.class_var2 #'foo bar'
print cm2.class_var1, cm2.class_var2 #'foo bar'
cm2.class_var1, cm2.class_var2 = 'bar','for'
print cm1.class_var1, cm1.class_var2 #'foo bar' #here not changed as my expectation
print cm2.class_var1, cm2.class_var2 #'bar foo' #here has changed but they seemed to become instance variables.
I'm confused since what I tried is different from Python's official documentation.
When you assign an attribute on the instance, it is assigned on the instance, even if it previously existed on the class. At first, class_var1 and class_var2 are indeed class attributes. But when you do cm1.class_var1 = "bar", you are not changing this class attribute. Rather, you are creating a new attribute, also called class_var1, but this one is an instance attribute on the instance cm1.
Here is another example showing the difference, although it still may be a bit tough to grasp:
>>> class A(object):
... var = []
>>> a = A()
>>> a.var is A.var
True
>>> a.var = []
>>> a.var is A.var
False
At first, a.var is A.var is true (i.e., they are the same object): since a doesn't have it's own attribute called var, trying to access that goes through to the class. After you give a its own instance attribute, it is no longer the same as the one on the class.
You're assigning attributes on the instances, so yes, they become instance variables at that point. Python looks for attributes on whatever object you specify, then if it can't find them there, looks up the inheritance chain (to the class, the class's parents, etc.). So the attribute you assign on the instance "shadows" or "hides" the class's attribute of the same name.
Strings are immutable, so the difference between a class and instance variable isn't as noticable. For immutable variables in a class definition, the main thing to notice is less use of memory (i.e., if you have 1,000 instances of CustomizedMethods, there's still only one instance of the string "foo" stored in memory.)
However, using mutable variables in a class can introduce subtle bugs if you don't know what you're doing.
Consider:
class CustomizedMethods(object):
class_var = {}
cm1 = CustomizedMethods()
cm2 = CustomizedMethods()
cm1.class_var['test'] = 'foo'
print cm2.class_var
'foo'
cm2.class_var['test'] = 'bar'
print cm1.class_var
'bar'
When you reassigned the cm2 variables, you created new instance variables that "hid" the class variables.
>>> CustomizedMethods.class_var1 = 'one'
>>> CustomizedMethods.class_var2 = 'two'
>>> print cm1.class_var1, cm1.class_var2
one two
>>> print cm2.class_var1, cm2.class_var2
bar for
Try to
print cm1.__dict__
print cm2.__dict__
it will be enlightning...
When you ask cm2 for an attribute it first looks among the attributes of the instance (if one matches the name) and then if there is no matching attribute among the class attributes.
So class_var1 and class_var2 are the names of the class attributes.
Try also the following:
cm2.__class__.class_var1 = "bar_foo"
print cm1.class_var1
what do you expect?
The way I usually declare a class variable to be used in instances in Python is the following:
class MyClass(object):
def __init__(self):
self.a_member = 0
my_object = MyClass()
my_object.a_member # evaluates to 0
But the following also works. Is it bad practice? If so, why?
class MyClass(object):
a_member = 0
my_object = MyClass()
my_object.a_member # also evaluates to 0
The second method is used all over Zope, but I haven't seen it anywhere else. Why is that?
Edit: as a response to sr2222's answer. I understand that the two are essentially different. However, if the class is only ever used to instantiate objects, the two will work he same way. So is it bad to use a class variable as an instance variable? It feels like it would be but I can't explain why.
The question is whether this is an attribute of the class itself or of a particular object. If the whole class of things has a certain attribute (possibly with minor exceptions), then by all means, assign an attribute onto the class. If some strange objects, or subclasses differ in this attribute, they can override it as necessary. Also, this is more memory-efficient than assigning an essentially constant attribute onto every object; only the class's __dict__ has a single entry for that attribute, and the __dict__ of each object may remain empty (at least for that particular attribute).
In short, both of your examples are quite idiomatic code, but they mean somewhat different things, both at the machine level, and at the human semantic level.
Let me explain this:
>>> class MyClass(object):
... a_member = 'a'
...
>>> o = MyClass()
>>> p = MyClass()
>>> o.a_member
'a'
>>> p.a_member
'a'
>>> o.a_member = 'b'
>>> p.a_member
'a'
On line two, you're setting a "class attribute". This is litterally an attribute of the object named "MyClass". It is stored as MyClass.__dict__['a_member'] = 'a'. On later lines, you're setting the object attribute o.a_member to be. This is completely equivalent to o.__dict__['a_member'] = 'b'. You can see that this has nothing to do with the separate dictionary of p.__dict__. When accessing a_member of p, it is not found in the object dictionary, and deferred up to its class dictionary: MyClass.a_member. This is why modifying the attributes of o do not affect the attributes of p, because it doesn't affect the attributes of MyClass.
The first is an instance attribute, the second a class attribute. They are not the same at all. An instance attribute is attached to an actual created object of the type whereas the class variable is attached to the class (the type) itself.
>>> class A(object):
... cls_attr = 'a'
... def __init__(self, x):
... self.ins_attr = x
...
>>> a1 = A(1)
>>> a2 = A(2)
>>> a1.cls_attr
'a'
>>> a2.cls_attr
'a'
>>> a1.ins_attr
1
>>> a2.ins_attr
2
>>> a1.__class__.cls_attr = 'b'
>>> a2.cls_attr
'b'
>>> a1.ins_attr = 3
>>> a2.ins_attr
2
Even if you are never modifying the objects' contents, the two are not interchangeable. The way I understand it, accessing class attributes is slightly slower than accessing instance attributes, because the interpreter essentially has to take an extra step to look up the class attribute.
Instance attribute
"What's a.thing?"
Class attribute
"What's a.thing? Oh, a has no instance attribute thing, I'll check its class..."
I have my answer! I owe to #mjgpy3's reference in the comment to the original post. The difference comes if the value assigned to the class variable is MUTABLE! THEN, the two will be changed together. The members split when a new value replaces the old one
>>> class MyClass(object):
... my_str = 'a'
... my_list = []
...
>>> a1, a2 = MyClass(), MyClass()
>>> a1.my_str # This is the CLASS variable.
'a'
>>> a2.my_str # This is the exact same class variable.
'a'
>>> a1.my_str = 'b' # This is a completely new instance variable. Strings are not mutable.
>>> a2.my_str # This is still the old, unchanged class variable.
'a'
>>> a1.my_list.append('w') # We're changing the mutable class variable, but not reassigning it.
>>> a2.my_list # This is the same old class variable, but with a new value.
['w']
Edit: this is pretty much what bukzor wrote. They get the best answer mark.