I want to get the instance handle of an attribute when this attribute is passed to a function without its instance. To make it more clear see the example code below:
class aClass():
def __init__(self):
self.anInstanceAttribute = 'ok'
def aFunction(anInstanceAttribute):
print(anInstanceAttribute)
#how to get the instance handle ('the self') of the anInstanceAttribute?
a = aClass()
aFunction(a.anInstanceAttribute)
This is not possible without introspection/frame hacks.
aFunction(a.anInstanceAttribute)
The function arguments are fully evaluated before calling the function. So, the function receives the string object "ok" and knows nothing about the instance a. If you want the function to know something about the instance, then pass in a instead.
Related
Sample Code:
class Mysterious:
def fake_staic():
print('fake staic')
def fake_sta_parameters(self):
print(f"fake_sta_parameters {self}")
Mysterious.fake_sta_parameters("fbc")
# output fake_sta_parameters fbc
Mysterious.fake_staic()
# output fake staic
Please define code as follows. Why can it be executed normally? Please help me explain, thanks
def fake_staic():
print('fake staic')
this function does not have self as argument and is call with class name, hence it will be treated as class method, or static method.
Whereas in second function,
def fake_sta_parameters(self):
print(f"fake_sta_parameters {self}")
you are providing it self argument, but calling it using class, and passing a value as its argument, hence self here is treated as argument and replaced with "fbc".
If you try calling this fake_sta_parameters() using object of your class, then it will give insufficient arguments error, as when a function called using object of the class, will always consider/expect function's first argument to be self reference, and hence above function will throw error as it wont have sufficient arguments to receive 'fbc' value.
Consider the following class:
class Employee:
def __init__(self,first,last,pay):
self.first=first;self.last=last
self.pay=pay
self.email=first.lower()+'.'+last.lower()+"#company.com"
def fullname(self): return "{} {}".format(self.first, self.last)
if I access the fullname method like this:
em1.fullname #assume em1 object already exists
I get the following output:
<bound method Employee.fullname of <__main__.Employee object at 0x7ff7883acc88>>`
However, if I access the fullname method like this:
Employee.fullname
I get the following output: <function Employee.fullname at 0x7ff7883c9268>
Why are there two different definitions for the same function/method? I'm still accessing the same method/function object in memory, right?
When you access fullname via an instance em1.fullname, you get a bound method, which means a version of fullname that automatically gets em1 as its first argument.
So you can call em1.fullname() without having to pass any explicit argument. But if you called Employee.fullname() you would get an error because of the missing argument self.
This applies even when the method call is separated from the attribute access:
bound = em1.fullname
unbound = Employee.fullname
bound() # OK, first argument is em1
unbound() # Error, no argument for self
unbound(em1) # OK, first argument supplied
I'm still accessing the same method/function object in memory, right?
Most definitely not, and it is apparent in the output you provided. The first lives at 0x7ff7883acc88 while the second at 0x7ff7883c9268.
The first one belongs to an instance, while the second one belongs to the Employee class itself.
You can access the same function.
However, in order to call the function, with em1.fullname you just need:
em1.fullname()
But with Employee.fullname, you need to supply the self argument and you would need:
Employee.fullname(em1)
I am trying to create class that having one instance method, is it possible to create instance method without self.
class A():
def display():
print("Hi")
a = A()
a.display()
I am getting like this: Type Error: display() takes no arguments (1 given)
For an instance method, you need to add a parameter that represents the instance itself. It MUST be present and it MUST be the first parameter of the method - that's mandatory, you cannot change this. It can be called whatever you want, although self is the standard used by the community, which you should also follow.
class A():
def display(self):
print('Hi')
Now, as you probably noticed, we're not doing anything in particular with the instance in the display method. To avoid this redundancy, we need to use a different type of method.
A method which does not take an instance as an argument is called a static method and is represented by the #staticmethod decorator directy above the function definition:
class A():
#staticmethod
def display():
print('Hi')
Both snippets will run without errors and, producing the same output when you execute the following code:
a = A()
a.display()
But the second version is preferred - because explicit is better than implicit.
Using #staticmethod will work... but I won't recommend it for beginner uses
Usually function define an object behavior so you'll need the object itself using self !
As others have pointed out, an instance method must have at least one parameter, as the object itself is passed (implicitly) as the first argument. But why?
This def statement, like any other, defines a function, not a method. So where does the method come from? Let's go step by step.
class A:
def display(self):
print("Hi")
If we look directly in the dictionary that stores a class's attributes, we see that display is bound to an instance of function.
>>> type(A.__dict__['display'])
<class 'function'>
We get the same result if we try to access the attribute using the normal dot syntax:
>>> type(A.display)
<class 'function'>
But something ... different ... happens if we try to access that function via an instance of the class:
>>> type(A().display)
<class 'method'>
Where did the method come from? Anytime you access an attribute, the machinery that handles such access looks to see if the result has a __get__ method. The function type provides such a method, so instead of getting the function itself back, you get the result of calling that function's __get__ method. That is, A().display is really the same as A.display.__get__(A(), A). And what __get__ returns is an object that does two things:
Saves a reference to the instance A()
Saves a reference to the function A.display.
When you try to call this object, what it does is takes any arguments passed to it, and passes the saved reference to A() along with those arguments to the function A.display. That is,
a = A()
a.display() == A.display.__get__(a, A)(a)
An that's why display gets defined with one more argument than is seemingly necessary.
Others have also mentioned static methods. What does #staticmethod do? staticmethod is another type, whose instances wrap a function. The staticmethod definition of __get__, though, doesn't do anything other than return the underlying function, not any kind of new method object. So given
class A:
#staticmethod
def display():
print("Hi")
we can see that display is an instance of static method, not a function:
>>> >>> type(A.__dict__['display'])
<class 'staticmethod'>
and that the __get__ method returns the function itself, whether the attribute is accessed via the class
>>> type(A.display)
<class 'function'>
or an instance
>>> type(A().display)
<class 'function'>
In Python when we define class all its members including variables and methods also becomes attributes of that class. In following example MyClass1.a and MyClass1.mydef1 are attributes of class MyClass1.
class MyClass1:
a = 10
def mydef1(self):
return 0
ins1 = MyClass1() # create instance
print(MyClass1.a) # access class attribute which is class variable
print(MyClass1.mydef1) # No idea what to do with it so just printing
print(ins1.mydef1) # No idea what to do with it so just printing
Output
10
<function MyClass1.mydef1 at 0x0000000002122EA0>
<bound method MyClass1.mydef1 of <__main__.MyClass1 object at 0x000000000212D0F0>>
Here attribute a is a variable and it can be used like any other variable.
But mydef1 is a method, if it is not invoked and just used like MyClass1.mydef1 or ins1.mydef1, it returns object for that method(correct me if I am wrong).
So my question is, what can we do with the Class/instance methods without invoking it? Are there any use cases for it or is it just good to know thing?
An attribute of a class that happens to be a function becomes a method for instances or that class:
inst.foo(params, ...)
is internally translated into:
cls.foo(inst, params, ...)
That means that what is actually invoked is the attribute from the class of the instance, and the instance itself is prepended to the argument list. It is just Python syntax to invoke methods on objects.
In your example the correct uses would be:
print(MyClass1.mydef1(ins1)) # prints 0
print(ins1.mydef1()) # also prints 0
Well instance methods can be called with the appropriate parameters of course:
print(ins1.mydef1()) # no parameters, so empty parenthesis, this call should print "0" in your example instead of the method description
If you use it without the parenthesis, you are playing with reference to the function, I don't think you can have any use of it, except checking the list of methods available in a class or something like that.
I am trying to set a static variable inside a function. Essentially, I want this variable to be false initially. After the first time this function is called, I want the variable to be set to true.
I currently have the following:
class LKTracker(object):
def track_points(self,width,height):
if not hasattr(track_points, "gotInitialFeatures"):
track_points.gotInitialFeatures = None
if not track_points.gotInitialFeatures:
#do some stuff
track_points.gotInitialFeatures = True
With this code, I keep receiving the following error:
NameError: global name 'track_points' is not defined
Anyone know what is happening here?
In a global function, you can refer directly to the function object by looking up the name.
This does not work in a method; you'd have to look the method up on the class instead:
LKTracker.track_points
This still won't do what you want, however, because you'd get a unbound method object at that moment:
>>> LKTracker.track_points
<unbound method LKTracker.track_points>
Method objects are created on demand (because functions are descriptors), and creating an attribute on a method object is futile; they generally only live for a short while.
You'd need to access the function instead:
>>> LKTracker.track_points.__func__
<function track_points at 0x103e7c500>
but you can do the same thing on self:
self.track_points.__func__
Now you can add a attribute:
track_points = self.track_points.__func__
if not hasattr(track_points, "gotInitialFeatures"):
track_points.gotInitialFeatures = None
if not track_points.gotInitialFeatures:
#do some stuff
track_points.gotInitialFeatures = True
But it would be much easier to just store that attribute on the class instead:
if not hasattr(LKTracker, 'gotInitialFeatures'):
You shall init static variable before call a function.
def static_var(varname, value):
def decorate(func):
setattr(func, varname, value)
return func
return decorate
and now you can:
#static_var("gotInitialFeatures", False)
def track_points(self, width, height):
...