In python, we could do this,
class TT(object):
def __init__(self):
self.f='ff'
x=TT()
print x.f
If I change the code to:
class TT(object):
def__init__(uu):
uu.f='ff'
x=TT()
print x.f
I will get the same results, both are 'ff'. Is 'uu' here just the alias for 'self'? Or any other difference? When should I use this?
Thanks.
There is no name for the object variable that is set in stone: you can use practically whatever name you want to identify it. However, to easily distinguish between the object variable and other passed variables, it is a commonly-adopted convention to name that variable "self", just to make it more readable for others who are examining your code.
You can technically use whatever name you want, but it is considered bad practice in the programming world.
It's not just __init__, it's all Python's methods: self is merely a convention. The first variable in the method will be the object itself, and it doesn't matter how you name it, self or uu or big_honcho or this; but if you use anything but self, people who read your code will likely be confused for a second or a thousand.
This is in contrast to many other OO languages which have an implicit variable for the current object, usually either self (e.g. Ruby) or this (e.g. JavaScript).
Related
In a method of a class:
def weight(self, grid):
...
if self.is_vertical:
self = self.T
...
I'd like to reassign self to its transposed value if the condition is true. Depending on the if-statement, I'd like to use self in a method later in its original or transposed condition.
As I understand, in a method, self is just a parameter name, but not the real reference or a pointer to an instance of a class, as in C++ or similar languages, so I can freely reassign it for use inside the scope of a method.
My question is why PyCharm's Inspection Info warns me that
...first parameter, such as 'self' or 'cls', is reassigned in a method. In most cases imaginable, there's no point in such reassignment, and it indicates an error.
while it works fine? Why does it indicates an error?
Why does it indicates an error?
Because there's no good reason to do it. Nothing uses the self variable automatically, so there's no need to reassign it. If you need a variable that sometimes refers to the object that the method was called on but could also hold some other value, use a different variable for this.
def mymethod(self):
cur = self
...
cur = cur.T
...
Note that self is just a local variable within this method. Reassigning self doesn't have any effect on the object itself, or the variable that the method was called on. It's practically useless to do this, so it almost always indicates that the programmer was confused. That's why Pycharm warns about it.
Since everyone expects self to refer to the object that the method was called on, reassigning it will also be confusing to other programmers. When working on code later in the method, they may not realize that self might not refer to that object. Imaging trying to have a conversation with someone who says "From now on, whenever I say 'me' or 'I', I actually mean that guy over there."
This is just the flip side of why we have the self and cls naming convention in the first place. As far as Python is concerned, you can use any name for the first parameter of a method. But we recommend everyone use these names so that when we read each others' code, we won't have to remember what variable refers to the current object in each method.
Python itself doesn't care, it won't cause an error message there.
Consider the following code, I expected it to generate error. But it worked. mydef1(self) should only be invoked with instance of MyClass1 as an argument, but it is accepting MyClass1 as well as rather vague object as instance.
Can someone explain why mydef is accepting class name(MyClass1) and object as argument?
class MyClass1:
def mydef1(self):
return "Hello"
print(MyClass1.mydef1(MyClass1))
print(MyClass1.mydef1(object))
Output
Hello
Hello
There are several parts to the answer to your question because your question signals confusion about a few different aspects of Python.
First, type names are not special in Python. They're just another variable. You can even do something like object = 5 and cause all kinds of confusion.
Secondly, the self parameter is just that, a parameter. When you say MyClass1.mydef1 you're asking for the value of the variable with the name mydef1 inside the variable (that's a module, or class, or something else that defines the __getattr__ method) MyClass1. You get back a function that takes one argument.
If you had done this:
aVar = MyClass1()
aVar.mydef1(object)
it would've failed. When Python gets a method from an instance of a class, the instance's __getattr__ method has special magic to bind the first argument to the same object the method was retrieved from. It then returns the bound method, which now takes one less argument.
I would recommend fiddling around in the interpreter and type in your MyClass1 definition, then type in MyClass1.mydef1 and aVar = MyClass1(); aVar.mydef1 and observe the difference in the results.
If you come from a language like C++ or Java, this can all seem very confusing. But, it's actually a very regular and logical structure. Everything works the same way.
Also, as people have pointed out, names have no type associated with them. The type is associated with the object the name references. So any name can reference any kind of thing. This is also referred to as 'dynamic typing'. Python is dynamically typed in another way as well. You can actually mess around with the internal structure of something and change the type of an object as well. This is fairly deep magic, and I wouldn't suggest doing it until you know what you're doing. And even then you shouldn't do it as it will just confuse everybody else.
Python is dynamically typed, so it doesn't care what gets passed. It only cares that the single required parameter gets an argument as a value. Once inside the function, you never use self, so it doesn't matter what the argument was; you can't misuse what you don't use in the first place.
This question only arises because you are taking the uncommon action of running an instance method as an unbound method with an explicit argument, rather than invoking it on an instance of the class and letting the Python runtime system take care of passing that instance as the first argument to mydef1: MyClass().mydef1() == MyClass.mydef1(MyClass()).
Python is not a statically-typed language, so you can pass to any function any objects of any data types as long as you pass in the right number of parameters, and the self argument in a class method is no different from arguments in any other function.
There is no problem with that whatsoever - self is an object like any other and may be used in any context where object of its type/behavior would be welcome.
Python - Is it okay to pass self to an external function
I am reading a book about Object-Oriented Programming in Python. There is a sentence that I am confused by:
The interpreter automatically binds the instance upon which the method is invoked to the self parameter.
In this sentence what is bound to the instance. the method, or the self parameter?
This is actually not such a bad question and I'm not sure why it got downvoted so quickly...
Even though Python supports object-oriented, I find it to be much closer to functional-programming languages, one of the reasons for that is that functions are invoked "on" objects, not "by" them.
For example: len(obj) where in a "true" object oriented programing language you'd expect to be able to do something like obj.length()
In regards to the self parameter, you're calling obj.method(other_args) but what really happens under the hood is a translation of this call to: method(obj, other_args) you can see that when the method is declared you're doing it with the self variable passed in as the first argument:
class ...
def method(self, other_args):
...
so it's basically all about the "translation" of obj.method(other_args) to method(obj, other_args)
This is a followup to function that returns a dict whose keys are the names of the input arguments, which I learned many things (paraphrased):
Python objects, on the whole, don't know their names.
No, this is not possible in general with *args. You'll have to use keyword arguments
When the number of arguments is fixed, you can do this with locals
Using globals(). This will only work if the values are unique in the module scope, so it's fragile
You're probably better off not doing this anyway and rethinking the problem.
The first point highlighting my fundamental misunderstanding of Python variables. The responses were very pedagogic and nearly instantaneous, clearly this is both a well-understood yet easily confused topic.
Since I'd like to learn how to do things proper, is it considered bad practice to create a dummy class to simply hold the variables with names attached to them?
class system: pass
S = system ()
S.T = 1.0
S.N = 20
S.L = 10
print vars(S)
This accomplishes my original intent, but I'm left wondering if there is something I'm not considering that can bite me later.
I do it as a homage to Javascript, where you don't have any distinction between dictionaries and instance variables. I think it's not necessarily an antipattern, also because differently from dictionaries, if you don't have the value it raises AttributeError instead of KeyError, and it is easier to spot typos of the name. As I said, not an antipattern, provided that
the scope of the class is restricted to a very specific usage
the routine or method you are calling (e.g. vars in your example) is private in nature. I would not want a public interface with that calling semantics, nor I want it as a returned entity
the name of the "dummy" class is extremely clear in its intent and the kind of aggregate it represents.
the lifetime of that object is short and uneventful. It is just a temporary bag of data.
If these constraints are not respected, go for a fully recognized class with properties.
you can do that, but why not use a dictionary?
but if you do that, you're better off passing keywords args to the class's constructor, and then let the constructor copy them to the app's members. something like:
class Foo(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
I understand why Python requires explicit self qualifier when referring to instance attributes.
But I often forget it, since I didn't need it in C++.
The bug I introduce this way is sometimes extremely hard to catch; e.g., suppose I write
if x is not None:
f()
instead of
if self.x is not None:
f()
Suppose attribute x is usually None, so f() is rarely called. And suppose f() only creates a subtle side effect (e.g., a change in a numeric value, or clearing the cache, etc.). Unless I have insane amount of unit tests, this mistake is likely to remain unnoticed for a long time.
I am wondering if anyone knows coding techniques or IDE features that could help me catch or avoid this type of bug.
Don't name your instance attributes the same things as your globals/locals.
If there isn't a global/local of the same name, you'll get a global "foo" is not defined error when you try to access self.foo but forget the self..
As a corollary: give your variables descriptive names. Don't name everything x - not only does this make it far less likely you'll have variables with the same name as attributes, it also makes your code easier to read.