Access 'Self' of an Object Through the Parameters

Access `self` of an object through the parameters

Not recommended, but instance_eval would somehow work:

[1, 2, 3, 4].instance_eval { at(rand(size)) }

And you can also break out of tap:

[1, 2, 3, 4].tap { |a| break a.at(rand(a.size)) }

There's an open feature request to add a method that yields self and returns the block's result. If that makes it into Ruby, you could write:

[1, 2, 3, 4].insert_method_name_here { |a| a.at(rand(a.size)) }

The proper way to access the self property of a class

I wouldn't go down that rabbit hole. Even if assigning back to self would have worked, it would be a nightmare to debug and maintain.

I'd use classmethods to allow creating one type from another. Assigning back is not more clumsy than secretly changing types under the hood.

classmethods are the idiomatic way to create objects of a certain type from objects of another type in Python. It is essentially a "workaround" for the fact that Python does not support constructor overloading (or any method overloading, for that matter).

Explicit is better than implicit.

class newString(str):
@classmethod
def from_newInt(cls, new_int_obj):
return cls(str(new_int_obj))

class newInt(int):
@classmethod
def from_newString(cls, new_string_obj):
return cls(int(new_string_obj))

s = newString('1')
i = newInt(1)
print(type(newString.from_newInt(i)))
print(type(newInt.from_newString(s)))
# <class '__main__.newString'>
# <class '__main__.newInt'>

Accessing self in a function attribute

You can use descriptors here:

class deco(object):

def __init__(self, func):
self.func = func
self.parent_obj = None

def __get__(self, obj, type=None):
self.parent_obj = obj
return self

def __call__(self, *args, **kwargs):
return self.func(self.parent_obj, *args, **kwargs)

def string(self, *args, **kwargs):
return str(self(*args, **kwargs))

class Test(object):

def __init__(self, value):
self._value = value

@deco
def plus(self, n):
return self._value + n

so that:

>>> test = Test(3)
>>> test.plus(1)
4
>>> test.plus.string(1)
'4'

This warrants an explanation. deco is a decorator, but it is also a descriptor. A descriptor is an object that defines alternative behavior that is to be invoked when the object is looked up as an attribute of its parent. Interestingly, bounds methods are themselves implemented using the descriptor protocol

That's a mouthful. Let's look at what happens when we run the example code. First, when we define the plus method, we apply the deco decorator. Now normally we see functions as decorators, and the return value of the function is the decorated result. Here we are using a class as a decorator. As a result, Test.plus isn't a function, but rather an instance of the deco type. This instance contains a reference to the plus function that we wish to wrap.

The deco class has a __call__ method that allows instances of it to act like functions. This implementation simply passes the arguments given to the plus function it has a reference to. Note that the first argument will be the reference to the Test instance.

The tricky part comes in implementing test.plus.string(1). To do this, we need a reference to the test instance of which the plus instance is an attribute. To accomplish this, we use the descriptor protocol. That is, we define a __get__ method which will be invoked whenever the deco instance is accessed as an attribute of some parent class instance. When this happens, it stores the parent object inside itself. Then we can simply implement plus.string as a method on the deco class, and use the reference to the parent object stored within the deco instance to get at the test instance to which plus belongs.

This is a lot of magic, so here's a disclaimer: Though this looks cool, it's probably not a great idea to implement something like this.

Access 'self' within an object when other arguments are also commited (perl)

Use of uninitiated value $person in concatenation (.) or String at Line 22.

When calling test2 method you've forgot $person argument, ie.

$i->test2();

should be

$i->test2("Someone");

What is the purpose of the `self` parameter? Why is it needed?

The reason you need to use self. is because Python does not use special syntax to refer to instance attributes. Python decided to do methods in a way that makes the instance to which the method belongs be passed automatically, but not received automatically: the first parameter of methods is the instance the method is called on. That makes methods entirely the same as functions, and leaves the actual name to use up to you (although self is the convention, and people will generally frown at you when you use something else.) self is not special to the code, it's just another object.

Python could have done something else to distinguish normal names from attributes -- special syntax like Ruby has, or requiring declarations like C++ and Java do, or perhaps something yet more different -- but it didn't. Python's all for making things explicit, making it obvious what's what, and although it doesn't do it entirely everywhere, it does do it for instance attributes. That's why assigning to an instance attribute needs to know what instance to assign to, and that's why it needs self..

where does the 'self' object comes from in the method __init__?

__init__ behaves like any other normal function in a class. It gets called by the interpreter at a special time if it is defined, but there is nothing special about it. You can call it any time yourself, just like a regular method.

Here are some facts to help you see the picture:

Function objects are non-data descriptors in python. That means that function objects have a __get__ method, but not __set__. And if course they have a __call__ method to actually run the function.

When you put a def statement in a class body, it creates a regular function, just like it would elsewhere. You can see this by looking at type(Test.__init__). To call Test.__init__, you would have to manually pass in a self parameter.

The magic happens when you call __init__ on an instance of Test. For example:

a = Test()
a.__init__()

This code actually calls __init__ twice (which we'll get into momentarily). The explicit second call does not pass in a parameter to the method. That's because a.__init__ has special meaning when the name __init__ is present in the class but not the instance. If __init__ is a descriptor, the interpreter will not return it directly, but rather will call __get__ on it and return the result. This is called binding.

a.__init__() is roughly equivalent to type(a).__init__.__get__(a, None)(). The call .__get__(a, None) returns a callable object that is a bound method. It is like a special type of partial function, in which the first positional parameter is set to a. You can see this by checking type(a.__init__).

The self parameter is passed to methods as the first positional parameter. As such, it does not have to be called self. The name is just a convention. def __init__(this): or def __init__(x) would work just as well.

Finally, let's discuss how a = Test() ends up calling __init__. Class objects are callable in python. They have a class themselves, called a metaclass (usually just type), which actually defines a __call__ method. When you do Test(), you are literally calling the class.

By default, the __call__ method of a class looks something (very roughly approximately) like this:

def __call__(cls, *args, **kwargs):
self = cls.__new__(cls, *args, **kwargs)
if isinstance(self, cls):
type(self).__init__(self, *args, **kwargs)

So a new instance is only created by __new__, not __init__. The latter is an initializer, not a constructor or allocator. In fact, as I mentioned before, you can call __init__ as often as you like on most classes. Notable exceptions include immutable built-in classes like tuple and int.

As an initializer, __init__ obviously needs access to the object it is initializing. Your example does nothing with self, but it is pretty standard to set instance attributes and do something things to prep the object. For cases like yours, an explicit __init__ is not necessary at all, since a missing function will be found in the base class hierarchy.

Can I access class variables using self?

Assigning remote to self in __init__ means that instance.remote is found first when you access it through self (granted no descriptors are around). To get both options, access either from self or from type(self), that is, either from the instance or the class:

def print_remote(self):
print(type(self).remote) # class remote
print(self.remote) # instance remote

type(self).remote is essentially equivalent to self.__class__.remote but, in general, you should avoid grabbing dunder names (__*__) when there's a built in that does it for you (type in this case)

These live in different dictionaries and are different variables. self.remote lives in the instance dict while class.remote in the class dict.

>>> Foo().__dict__['remote']
True
>>> Foo.__dict__['remote']
False

When you access through cls with a classmethod (or type(self) in a normal method) you'll get the class one, when you access through self you get the instance one.

How can a JavaScript object refer to values in itself?

Maybe you can think about removing the attribute to a function. I mean something like this:

var obj = {  key1: "it ",  key2: function() {    return this.key1 + " works!";  }};
alert(obj.key2());

How have access to both cls and self in a method

As a very brief review, self refers to a current instance of the class while cls variables are attached to the class itelf i.e., shared among every instance. Here are some references to help with this, and how I got to your solution:

  • https://stackoverflow.com/a/25577642/5557662
  • Python datamodel docs

I modified your sample code to illustrate the difference and included a solution:

class MyClass:
__var2 = 'var2'
var3 = 'var3'

def __init__(self):
self.__var1 = 'var1'

def normal_method(self):
print(self.__var1)

@classmethod
def class_method(cls):
print(cls.__var2)

def my_method(self):
print(self.__var1)
print(self.__var2)
print(self.__class__.__var2)

if __name__ == '__main__':
print(MyClass.__dict__['var3'])

clzz = MyClass()
clzz.my_method()

__var2 and var3 are variables saved to the class. You can access any class variable without an instance via __dict__ which represents the name space.

Since class variables become a part of every instance, you can just call self to access them. Alternatively, you can explicitly call self.__class__.__var2 to make it clear where the intended variable is actually stored.

Passing 'self' parameter during methods decorating in Python

It's not working with you current design because of how classes work in Python.

When a class is instantiated, the functions on it get bound to the instance -
they become bound methods, so that self is automatically passed.

You can see it happen:

class A:
def method1(self):
pass

>>> A.method1
<function A.method1 at 0x7f303298ef28>
>>> a_instance = A()
>>> a_instance.method1
<bound method A.method1 of <__main__.A object at 0x7f303a36c518>>

When A is instantiated, method1 is magically transformed from a
function into a bound method.

Your decorator replaces method1 - instead of a real function,
it is now an instance of _PrintingArguments. The magic
that turns functions into bound methods is not applied to random
objects, even if they define __call__ so that they behave like a function. (But that magic can be applied, if your class implements the Descriptor protocol, see ShadowRanger's answer!).

class Decorator:
def __init__(self, func):
self.func = func

def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)

class A:
@Decorator
def method1(self):
pass

>>> A.method1
<__main__.Decorator object at 0x7f303a36cbe0>
>>> a_instance = A()
>>> a_instance.method1
<__main__.Decorator object at 0x7f303a36cbe0>

There is no magic. method1 on the instance of A is not a bound method,
it's just a random object with a __call__ method, which will not have
self passed automatically.

If you want to decorate methods you have to replace the decorated function
with another real function, an arbitrary object with __call__ will not do.

You could adapt your current code to return a real function:

import functools

class _PrintingArguments:
def __init__(self, default_comment, comment_variable):
self.comment_variable = comment_variable
self.default_comment = default_comment

def __call__(self, function):
@functools.wraps(function)
def decorated(*args, **kwargs):
comment = kwargs.pop(self.comment_variable, self.default_comment)
params_str = [repr(arg) for arg in args] + ["{}={}".format(k, repr(v)) for k, v in kwargs.items()]
function_call_log = "{}({})".format(function.__name__, ", ".join(params_str))
print("Function execution - '{}'\n\t{}".format(comment, function_call_log))
function_return = function(*args, **kwargs)
print("\tFunction executed\n")
return function_return
return decorated

def function_log(_function=None, default_comment="No comment.", comment_variable="comment"):
decorator = _PrintingArguments(
default_comment=default_comment,
comment_variable=comment_variable,
)
if _function is None:
return decorator
else:
return decorator(_function)


Related Topics



Leave a reply



Submit