I am a quit new python programer and just for curiosity I want to know how I can reach to the name of instance which is made in the body of main,in the methods of my class . I want to know whether there is a built-in method for classes or I should manage it myself. by the way, I don't want to use lists or Dictionaries. a sample code is following:
class Vec2D(object):
def __init__(self,X, Y):
self.x=X
self.y=Y
print "X coordinate is ",self.x # I want to add it here
print "Y coordinate is ",self.y # and here
if __name__ == '__main__':
mypoint1 = Vec2D(0,1)
mypoint2 = Vec2D(1,2)
It could be considered as a reporting issue...
You can't. A value has no way to know what variable refers to it.
The reason is quite simple; you can have multiple variables refer to the same value:
mypoint3 = mypoint1
Now what name does the instance have?
Well, for starters, you couldn't print the name in __init__() because the object is still being constructed and hasn't been assigned one yet. Even if it were, there's no built-in way to find out what it is in Python.
However it is possible to search for the object after construction in the module's global namespace, which allows you to do things like this:
class Vec2D(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
my_name = '<unknown>'
namespace = globals().copy()
for name,obj in namespace.items():
if obj is self:
my_name = name
break
return "\n".join(["{!r}:",
" X coordinate is {}",
" Y coordinate is {}"]).format(my_name, self.x, self.y)
if __name__ == '__main__':
mypoint1 = Vec2D(0,1)
mypoint2 = Vec2D(1,2)
print mypoint1
print mypoint2
Output:
'mypoint1':
X coordinate is 0
Y coordinate is 1
'mypoint2':
X coordinate is 1
Y coordinate is 2
However this isn't foolproof because if there are two names for the same object, the for search loop will stop as soon as it finds one of them. It could be modified to find them all, I suppose...
As #MartijnPieters said, these's no way to get the variable name of an instance. The names are not kept after interpreting.
But if you do have the special need, I think there're at least 2 approaches for you.
Let's say you have an instance MyInstance of class MyClass, then
str(MyInstance) will give you a string like <__main__.MyClass instance at 0x1044b6f80>, it uniquely indicates MyInstanceduring the runtime. You might want to use it as the name of the instance.
Explicitly define a "name" in the construction of the class, like:
class MyClass:
def __init__(self, name):
self.name = name
. Afterwards you can always get the name by:
MyInstance = MyClass("Instance1")
print MyInstance.name
Related
I'm developing a programming language in Python where you can program a simulation of simple machines. I have written a function that takes some input, parses it, and finds out what the first word is.
Now, for the first word insert, I need to take the next words obj, name, x, and y.
obj: what type of simple machine it is
name: what you want to call the object
x: X coordinate on the graph
y: Y coordinate on the graph
I have already made a function nextword that iterates through the rest of the code and defines each variable as those words, so with the following code:
insert pulley JohnThePulley 3 4
It sees first word is insert, and calls my insert function.
Then, it sets obj to pulley, name to JohnThePulley, and so on.
However, now I need to make an object in the daughter class pulley, under the mother class simple_machines, that has the name JohnThePulley, etc.
The situation I'm in is that for the first word insert, for example, I don't know at all what the next word will be, from all the choices of daughter classes that they can call. I need to create the specified object along with the provided name, the provided X coordinate and the provided Y coordinate.
I have tried doing simple formatting in python using '{}'.format(name) or .format(obj), but those don't work.
# Insert function
def insert(code):
c = 4
syntax = np.array([obj, name, x, y])
nextword(parser.code_array, syntax, c)
objc += 1
return
# Nextword function, code_array[0] is insert, syntax is an array that
# contains all the variables that need to be defined for any function
def nextword(code_array, syntax, c):
assert len(code_array) == c + 1, "Too Many Words!"
for m in range(0, c):
syntax[m] = code_array[m + 1]
return
# Mother Class simple_machines with properties
class simple_machines:
def __init__(self, obj, name, x, y, coords):
self.obj = (
obj
) # what type of obj, in this case, pulley
self.name = name # name, JohnThePulley
self.x = x # 3 in this case
self.y = y # 4 in this case
self.coords = (x, y) # (3,4) in this case
return
# Pulley Class, here so I can later define special properties for a pulley
class pulley(simple_machines):
def __init__(self, name, x, y):
super(simple_machines, self).__init__()
return
# Code that I tried
def insert(code):
c = 4
syntax = np.array([obj, name, x, y])
nextword(parser.code_array, syntax, c)
"{}".format(name) = "{}".format(obj)(
name, x, y
) # this is what my
# instantiation would look like, formatting an object with name, then
# calling a class formatted with obj, and inserting their input of
# name,x,y as the properties
return
I expect an object in pulley to be created with the name JohnThePulley, and the coordinates X = 3 and Y = 4. What I'd like to result in, in simpler terms, is an object called name in a class called obj with the attributes name.x, name.y, etc
However, I get errors like:
NameError: name 'obj' is not defined
or:
SyntaxError: can't assign to function call
The first one apparently means that the word obj isn't being assigned, but the second one apparently means that I can't format a function name or format a variable name and define it as a function (even though I'm instantiating it as a class).
What am I doing wrong? How can I fix this?
name 'obj' is not defined is because obj is defined in another function. You have to use MYOBJECT.obj, not obj alone, and also keep a reference to MYOBJECT.
'{}'.format(obj)(name,x,y) doesn't mean anything, '{}'.format(obj) is a string and isn't callable.
SyntaxError: can't assign to function call is the actual problem you seem to be interested in. You could do globals()['{}'.format(name)] = stuff but it doesn't work for local variables and objects (and your linter is not going to like it).
If you want to do the same for objects you can use setattr(MYOBJECT, '{}'.format(name), '{}'.format(obj))
All of the solutions above are in technical terms considered "ugly" and what you're probably looking for is a dictionary, while it isn't OOP, dictionaries are used behind the scenes to handle exactly what you want to do with objects. An object without methods is essentially a just dictionary.
mydico = dict()
mydico[name] = obj
Also, if name is a string, then '{}'.format(name) is equivalent to name.
In python, is it possible to chain together class methods and functions together? For example, if I want to instantiate a class object and call a method on it that affects an instance variable's state, could I do that? Here is an example:
class Test(object):
def __init__(self):
self.x = 'Hello'
#classmethod
def make_upper(y):
y.x = y.x.upper()
What I'm wanting to do is this:
h = Test().make_upper()
I want to instantiate a class object and affect the state of a variable in one line of code, but I would also like to be able to chain together multiple functions that can affect state or do something else on the object. Is this possible in python like it is in jQuery?
Yes, sure. Just return self from the instance methods you are interested in:
class Test(object):
def __init__(self):
self.x = 'Hello'
def make_upper(self):
self.x = self.x.upper()
return self
def make_lower(self):
self.x = self.x.lower()
return self
h = Test().make_upper()
print(h.x)
Output:
HELLO
Yes and no. The chaining certainly works, but h is the return value of make_upper(), not the object returned by Test(). You need to write this as two lines.
h = Test()
h.make_upper()
However, PEP-572 was recently accepted for inclusion in Python 3.8, which means someday you could write
(h := Test()).make_upper()
The return value of Test() is assigned to h in the current scope and used as the value of the := expression, which then invokes its make_upper method. I'm not sure I would recommend using := in this case, though; the currently required syntax is much more readable.
Please guide to an explain of the difference between
object = class()
and
var = class method returning a class:
class Countsome(object):
#classmethod
def get(cls, x, y):
self = cls()
sum = self.add2(x, y)
print sum
return cls
def add2(self, x, y):
sum = x+y
return sum
xyz = Countsome.get(5, 9)
==========================================
class CountSome(object):
def __init__(self):
pass
def add2(self, x, y):
sum = x+y
print sum
xyz = CountSome()
xyz.add2(5, 9)
Looking to understand where I should use one, I am just printing the sum so not returning, so please assume I am asking this question for these kind of tasks(where returning results like sum is not important).
And looking for answers like, which one would be efficient, when.
What are the benefits of each and scenarios best suited for each. Guide to a source if possible
You kinda get it wrong. classmethod should be use when you need to perform action that doesn't need an instance but does need the cls object:
A class method receives the class as implicit first argument, just like an instance method receives the instance.
For example, if you have a COUNTER object in your class which counts how many instances were instantiated.
The second code is actually using staticmethod; that is a method defined in a class but don't need access to any class / instance attributes. staticmethod can be defined outside of a class but resides in it for convenience
This question already has answers here:
Why do you need explicitly have the "self" argument in a Python method? [duplicate]
(10 answers)
Closed 6 years ago.
Consider this code:
class example(object):
def __init__ (): # No self
test() # No self
def test(x,y): # No self
return x+y
def test1(x,y): # No self
return x-y
print(example.test(10,5))
print(example.test1(10,5))
15
5
This works as expected. I believe I can write a whole program not using self. What am I missing? What is this self; why is it needed in some practical way?
I have read a lot about it - (stack, Python documentation), but I just don't understand why it's needed, since I can obviously create a program without it.
You can perfectly create a program without it. But then you'd be missing one of the key features of classes. If you can do without self, I'd argue you can do without classes and just do something purely with functions :)
Classes allow you to create objects which have a PROPERTY associated to them, and self allows you to access those values. So say you have a square.
g code:
class Square(object):
def __init__ (self, length, height):
self.length = length # THIS square's length, not others
self.height = height # THIS square's height, not other
def print_length_and_height(self):
print(self.length, self.height) # THIS square's length and height
square1 = Square(2,2)
square2 = Square(4,4)
square1.print_length_and_height() # 2 2
square2.print_length_and_height() # 4 4
Now, this example is quite silly, of course, but i think it shows what SELF specifically is for: it refers to the particular instance of an object.
By all means, if you don't see the point to it, just do away with classes and just use functions, there nothing wrong with that.
You haven't utilised a class or object properly. Cutting out the garbage code, your program reduces to:
def test(x,y): #No class
return x+y
def test1(x,y): #No class
return x-y
print(example.test(10,5))
print(example.test1(10,5))
Output:
15
5
Your "class" is no more useful than if you wrapped your program in the nested structures:
if True:
for i in range(1):
...
A proper object will have attributes (data fields) and functions that operate on that data (see below). Your code has an empty object; hence, you have nothing on which to operate, no need for self, and no need for a class at all.
Rather, use a class when you need to encapsulate a data representation and associated operations. Below, I've reused some of your code to make example do some trivial complex number work. There are many extensions and improvements to make in this; I kept it relatively close to your original work.
class example(object):
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
sign = ' + ' if self.b >= 0 else ' - '
return str(self.a) + sign + str(abs(self.b)) + 'i'
def add(self, x):
self.a += x.a
self.b += x.b
def sub(self, x):
self.a -= x.a
self.b -= x.b
complex1 = example(10, 5)
complex2 = example(-3, 2)
complex1.add(complex2)
print(complex1)
complex2.sub(complex1)
print(complex2)
Output:
7 + 7i
-10 - 5i
Are you familiar with Object-Oriented Paradigm?
If you don't you should check it. Python is a Object-Oriented Language and self lets you define your object properties.
An example:
You have a class named Vehicle. A vehicle could be a bike, a car, even a plane. So something you can include is a name and a type.
class Vehicle():
def init(self, name, type): # Constructor
self.name = name
self.type = type
def info(self):
print("I'm a ")
print(self.name)
That's all, now you have a vehicle with name and type. Every instance of Vehicle would have a name and a type different or not and every intance can access its own variables. I'm sorry I can't explain it better. Firstable you need to know Object-Oriented Paradigm knowledge. Please comment my answer if you have doubts & I'll answer you or give a link where it comes explained better.
I have already read many answers here on Stack Exchange like Python - why use "self" in a class?
After reading these answers, I understand that instance variables are unique to each instance of the class while class variables are shared across all instances.
While playing around, I found that this code which gives the output [1]:
class A:
x = []
def add(self):
self.x.append(1)
x = A()
y = A()
x.add()
print "Y's x: ", y.x
However, this code gives 10 as the output, when in my opinion it should be 11:
class A:
x = 10
def add(self):
self.x += 1
x = A()
y = A()
x.add()
print "Y's x: ", y.x
Why A class variable is not updated when I run x.add()? I am not very experienced in programming, so please excuse me.
Class variables are shadowed by instance attribute. This means that when looking up an attribute, Python first looks in the instance, then in the class. Furthermore, setting a variable on an object (e.g. self) always creates an instance variable - it never changes the class variable.
This means that when, in your second example you do:
self.x += 1
which is (in this case, see footnote) equivalent to:
self.x = self.x + 1
what Python does is:
Look up self.x. At that point, self doesn't have the instance attribute x, so the class attribute A.x is found, with the value 10.
The RHS is evaluated, giving the result 11.
This result is assigned to a new instance attribute x of self.
So below that, when you look up x.x, you get this new instance attribute that was created in add(). When looking up y.x, you still get the class attribute. To change the class attribute, you'd have to use A.x += 1 explicitly – the lookup only happens when reading the value of an attribute.
Your first example is a classical gotcha and the reason you shouldn't use class attributes as "default" values for instance attributes. When you call:
self.x.append(1)
there is no assignment to self.x taking place. (Changing the contents of a mutable object, like a list, is not the same as assignment.) Thus, no new instance attribute is added to x that would shadow it, and looking up x.x and y.x later on gives you the same list from the class attribute.
Note: In Python, x += y is not always equivalent to x = x + y. Python allows you to override the in-place operators separately from the normal ones for a type. This mostly makes sense for mutable objects, where the in-place version will directly change the contents without a reassignment of the LHS of the expression. However, immutable objects (such as numbers in your second example) do not override in-place operators. In that case, the statement does get evaluated as a regular addition and a reassignment, explaining the behaviour you see.
(I lifted the above from this SO answer, see there for more details.)