python 3: Class function member to modify a class data member [duplicate] - python

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Python: How do I pass a variable by reference?
I have the following case:
class A:
def __init__(self):
self.test = ''
self.func(self.test)
print(self.test)
def func(self,var):
var = 'foo'
I want func to modify self.var and I'd like to be able to pass a self. to this method.
A bit like:
class A()
{
public:
char test[256];
A() { func(test);}
private:
void func(char * var) { var = "foo"; }
};
I haven't written C++ in a while but that's sort of what I'm going for.

Unfortunately, I don't know C++ very well, but I'm guessing you want something like this:
class A:
def __init__(self):
self.test = ''
self.func("test")
print(self.test)
def func(self,var):
setattr(self,var,'foo')
We have to do it this way because we can change (mutate) self.test inside a function (if it's mutable), but we can't change which object it references (which is what you're attempting to do with assignment). consider:
def func1(x):
x.append('foo')
def func2(x):
x = 'foo'
a = []
func1(a)
print a #['foo'] #mutated a in func1
func2(a)
print a #['foo'] #didn't change a in func2, only created a new local variable named `x` and assigned it to the string 'foo'
The only way around this is to pass some sort of proxy-like object which you can change. In this case, we pass the instance as the proxy object (self) and the attribute's name (var) so we know what to change on self. Given those two pieces of information, we can make the desired changes -- Of course, at this point, you're probably best off getting rid of func all together and just using setattr directly.
It's probably also worth asking why you actually want to do this. In general, you can just do:
self.test = "foo"
why would you want to write:
self.func(self.test)
instead? I can understand if you're trying to do that since you're used to having private methods and attributes. But this is python. "We're all consenting adults here." Just rely on the conventions (prefix a variable with _ if you want to warn users against modifying it and prefix with __ to invoke name mangling to avoid collisions in superclasses).

Related

how to access list, declared inside a function, outside the function? [duplicate]

This question already has answers here:
How do I get a result (output) from a function? How can I use the result later?
(4 answers)
Closed 4 months ago.
I am trying to access a local function variable outside the function in Python.
I can make code like this work with global variables:
bye = ''
def hi():
global bye
bye = 5
sigh = 10
hi()
print(bye)
Next, I tried this code, hoping to access bye outside hi() without using global bye:
def hi():
bye = 5
sigh = 10
return
hi()
x = hi()
print(x.bye)
This gives AttributeError: 'NoneType' object has no attribute 'bye'.
Next, I tried:
def hi():
bye = 5
sigh = 10
return bye
hi()
x = hi()
print(x.bye)
This didn't improve matters; I get AttributeError: 'int' object has no attribute 'bye'.
Is there a way to access a local function variable (bye) outside its function (hi()) without using globals and also without printing out the sigh variable? How can I do it?
You could do something along these lines (which worked in both Python v2.7.17 and v3.8.1 when I tested it/them):
def hi():
# other code...
hi.bye = 42 # Create function attribute.
sigh = 10
hi()
print(hi.bye) # -> 42
Functions are objects in Python and can have arbitrary attributes assigned to them.
If you're going to be doing this kind of thing often, you could implement something more generic by creating a function decorator that adds a this argument to each call to the decorated function.
This additional argument will give functions a way to reference themselves without needing to explicitly embed (hardcode) their name into the rest of the definition and is similar to the instance argument that class methods automatically receive as their first argument which is usually named self — I picked something different to avoid confusion, but like the self argument, it can be named whatever you wish.
Here's an example of that approach:
def add_this_arg(func):
def wrapped(*args, **kwargs):
return func(wrapped, *args, **kwargs)
return wrapped
#add_this_arg
def hi(this, that):
# other code...
this.bye = 2 * that # Create function attribute.
sigh = 10
hi(21)
print(hi.bye) # -> 42
Note
This doesn't work for class methods. Just use the instance argument, named self by convention, that's already passed to methods instead of the method's name. You can reference class-level attributes through type(self). See Function's attributes when in a class.
The problem is you were calling print(x.bye) after you set x as a string. When you run x = hi() it runs hi() and sets the value of x to 5 (the value of bye; it does NOT set the value of x as a reference to the bye variable itself). EX: bye = 5; x = bye; bye = 4; print(x) prints 5, not 4.
Also, you don't have to run hi() twice, just run x = hi(), not hi(); x=hi() (the way you had it it was running hi(), not doing anything with the resulting value of 5, and then rerunning the same hi() and saving the value of 5 to the x variable.
So full code should be
def hi():
bye = 5
sigh = 10
return bye
x = hi()
print(x)
If you wanted to return multiple variables, one option would be to use a list, or dictionary, depending on what you need. For example:
def hi():
return { 'bye': 5, 'sigh': 10 }
x = hi()
print x['bye']
def hi():
bye = 5
return bye
print hi()
You could do something along this lines:
def static_example():
if not hasattr(static_example, "static_var"):
static_example.static_var = 0
static_example.static_var += 1
return static_example.static_var
print static_example()
print static_example()
print static_example()
To be able to access a local function's variable, one might add the name of the function and a dot before the name of the local variable (and then, of course, use this construction for calling the variable both in the function's body and outside of it). This solution works in Python 3.7.4.
For example:
def func(): # define a function
# here y is a local variable, which I want to access; func.y
# defines a method for my example function which will allow me to
# access function's local variable y
func.y = 4
x = func.y + 8
return x
func() # now I'm calling the function
a = func.y # I put its local variable into my new variable
print(a) # and print my new variable
If you want to avoid global, one possible approach is to define a class. Each class instance has its own attributes; there is also a class attribute space where instances can share an attribute between them.
Object-oriented programming can be challenging to get into if you are new to Python, but this might actually be a good time to start playing with it.
class Thing:
shared = "foo"
def __init__(self):
"""
This gets called when you create a new Thing()
"""
self.bar = "baz" # default value for new instances
def get_bar(self):
return self.bar
def set_bar(self, value):
self.bar = value
Now, let's create two instances.
first = Thing()
second = Thing()
The get_bar and set_bar methods are not strictly necessary in simple examples like this one. You can also do
second.bar = "ick"
print(second.bar)
# "ick"
print(first.bar)
# "baz"
(though for more complex scenarios, you probably want to require users to call the setter and getter methods; there are ways to force this - see e.g. What's the pythonic way to use getters and setters?)
If you change a class attribute via one instance, it will not be changed in the other instances, either.
second.shared = "poo"
print(first.shared)
# "foo"
But if you change it in the class itself, it will be changed in all the instances which have not separately overridden the shared value.
Thing.shared = "zoom"
print(first.shared)
# "zoom"
print(second.shared)
# "poo", still
To recap, you create a new Thing instance by calling Thing(); this will run the __init__ method before returning the new instance. Inside the class, the instance is the first argument to every (non-static, non-class) method, and conventionally called self (though you could get away with calling it shirley if you wanted to, as far as the Python interpreter is concerned).
There's a lot more to classes; the main selling point is probably that you can create subclasses which inherit from their parent class but can override some behaviors (common examples often involve real-world concepts like animals or vehicles, but a class can just be anything where you want to create a type and encapsulate its behavior, and perhaps override some methods in derived types).

python self is not defined [duplicate]

This question already has answers here:
Python - default value in class method and <code>self</code>
(2 answers)
Closed 3 years ago.
Context
I'm using vscode. And just running script with all the project files in same folder worked fine. It is as below
MainModule
-aFile.py
-bFile.py
-cFile.py
-dFile.py
While working on my project, I decided that it should be better to separate project into two modules.
MainModule
/subModule00
-aFile.py
-bFile.py
/subModule01
-cFile.py
-dFile.py
After that, I needed to test cFile which imports class from aFile. Running it as script caused an error. So I ran cFile as module and it fixed the import error. But a new error rose.
Question
class ExampleClass(ClassFromAfile):
EXAMPLE_CONSTANT = 1000
def __init__(self, someArg0, someArg1):
self.someVar = someArg0
def exmapleMethod(self, someArg2, someArg3=1000, someArg=self.EXAMPLE_CONSTANT):
# ... so on
While debugging below error occurred while defining exampleMehod
name 'self' is not defined
self is not a reserved keyword in Python.
The first argument of a function in a class is the class instance, thus making it a method of the class. [Unless it is a static method (#staticmethod) or class method, in which case the first argument is the class itself (#classmethod) ]
In your example, you want to initialize someArg as a constant EXAMPLE_CONSTANT.
Then you can simply use as below:
class ExampleClass(ClassFromAfile):
EXAMPLE_CONSTANT = 1000
def __init__(self, someArg0, someArg1):
self.someVar = someArg0
def exmapleMethod(self, someArg2, someArg3=1000, someArg=EXAMPLE_CONSTANT):
# ... so on
To make it clear you can do the following:
In [1]: class Test:
...: def test(t_self, a): # not using self and its good still
...: print(a)
...: def best(b):
...: print(b) # This will print out the class instance itself.
...:
In [2]: te = Test()
In [3]: te.best()
<__main__.Test object at 0x7efc1294b278>
In [24]: te.test(1)
In exampleMethod, self is used in someArg = self.EXAMPLE_CONSTANT. You should add self back to EXAMPLE_CONSTANT for it to work properly or remove self. from your parameter.
Both def and class are executable statements in Python, with the usual scoping and execution time rules. In this case, that means the self in the argument list doesn't exist when the def for the method is run. The default argument value expression self.EXAMPLE_CONSTANT gets evaluated when the def statement runs, and at that time self doesn't exist because the method hasn't been called, and ExampleClass doesn't exist because the class block has not finished (both def and class build an object, callable or class respectively, and assign it to a name). Note that this implies that while def defines a callable that is deferred until it is called, class actually executes everything inside; there are no variable or type declarations like in e.g. C++.
The def for the method runs with its local scope within the class block, so you could use a local reference to values that will be class members:
class Foo:
bar=123
def hmm(self, arg=bar):
return arg
There's also a common workaround for when you need a default argument to be evaluated during a call, rather than at def time:
def append(someitem, somelist=None):
if somelist is None:
somelist = list()
somelist.append(someitem)
return somelist # Caller needs this if we made a new list

Why doesn't Python allow referencing a class inside its definition?

Python (3 and 2) doesn't allow you to reference a class inside its body (except in methods):
class A:
static_attribute = A()
This raises a NameError in the second line because 'A' is not defined, while this
class A:
def method(self):
return A('argument')
works fine.
In other languages, for example Java, the former is no problem and it is advantageous in many situations, like implementing singletons.
Why isn't this possible in Python? What are the reasons for this decision?
EDIT:
I edited my other question so it asks only for ways to "circumvent" this restriction, while this questions asks for its motivation / technical details.
Python is a dynamically typed language, and executes statements as you import the module. There is no compiled definition of a class object, the object is created by executing the class statement.
Python essentially executes the class body like a function, taking the resulting local namespace to form the body. Thus the following code:
class Foo(object):
bar = baz
translates roughly to:
def _Foo_body():
bar = baz
return locals()
Foo = type('Foo', (object,), _Foo_body())
As a result, the name for the class is not assigned to until the class statement has completed executing. You can't use the name inside the class statement until that statement has completed, in the same way that you can't use a function until the def statement has completed defining it.
This does mean you can dynamically create classes on the fly:
def class_with_base(base_class):
class Foo(base_class):
pass
return Foo
You can store those classes in a list:
classes = [class_with_base(base) for base in list_of_bases]
Now you have a list of classes with no global names referring to them anywhere. Without a global name, I can't rely on such a name existing in a method either; return Foo won't work as there is no Foo global for that to refer to.
Next, Python supports a concept called a metaclass, which produces classes just like a class produces instances. The type() function above is the default metaclass, but you are free to supply your own for a class. A metaclass is free to produce whatever it likes really, even things that are bit classes! As such Python cannot, up front, know what kind of object a class statement will produce and can't make assumptions about what it'll end up binding the name used to. See What is a metaclass in Python?
All this is not something you can do in a statically typed language like Java.
A class statement is executed just like any other statement. Your first example is (roughly) equivalent to
a = A()
A = type('A', (), {'static_attribute': a})
The first line obviously raises a NameError, because A isn't yet bound to anything.
In your second example, A isn't referenced until method is actually called, by which time A does refer to the class.
Essentially, a class does not exist until its entire definition is compiled in its entirety. This is similar to end blocks that are explicitly written in other languages, and Python utilizes implicit end blocks which are determined by indentation.
The other answers are great at explaining why you can't reference the class by name within the class, but you can use class methods to access the class.
The #classmethod decorator annotes a method that will be passed the class type, instead of the usual class instance (self). This is similar to Java's static method (there's also a #staticmethod decorator, which is a little different).
For a singleton, you can access a class instance to store an object instance (Attributes defined at the class level are the fields defined as static in a Java class):
class A(object):
instance = None
#classmethod
def get_singleton(cls):
if cls.instance is None:
print "Creating new instance"
cls.instance = cls()
return cls.instance
>>> a1 = A.get_singleton()
Creating new instance
>>> a2 = A.get_singleton()
>>> print a1 is a2
True
You can also use class methods to make java-style "static" methods:
class Name(object):
def __init__(self, name):
self.name = name
#classmethod
def make_as_victoria(cls):
return cls("Victoria")
#classmethod
def make_as_stephen(cls):
return cls("Stephen")
>>> victoria = Name.make_as_victoria()
>>> stephen = Name.make_as_stephen()
>>> print victoria.name
Victoria
>>> print stephen.name
Stephen
The answer is "just because".
It has nothing to do with the type system of Python, or it being dynamic. It has to do with the order in which a newly introduced type is initialized.
Some months ago I developed an object system for the language TXR, in which this works:
1> (defstruct foo nil (:static bar (new foo)))
#
2> (new foo)
#S(foo)
3> *2.bar
#S(foo)
Here, bar is a static slot ("class variable") in foo. It is initialized by an expression which constructs a foo.
Why that works can be understood from the function-based API for the instantiation of a new type, where the static class initialization is performed by a function which is passed in. The defstruct macro compiles a call to make-struct-type in which the (new foo) expression ends up in the body of the anonymous function that is passed for the static-initfun argument. This function is called after the type is registered under the foo symbol already.
We could easily patch the C implementation of make_struct_type so that this breaks. The last few lines of that function are:
sethash(struct_type_hash, name, stype);
if (super) {
mpush(stype, mkloc(su->dvtypes, super));
memcpy(st->stslot, su->stslot, sizeof (val) * su->nstslots);
}
call_stinitfun_chain(st, stype);
return stype;
}
The call_stinifun_chain does the initialization which ends up evaluating (new foo) and storing it in the bar static slot, and the sethash call is what registers the type under its name.
If we simply reverse the order in which these functions are called, the language and type system will still be the same, and almost everything will work as before. Yet, the (:static bar (new foo)) slot specifier will fail.
I put the calls in that order because I wanted the language-controlled aspects of the type to be as complete as possible before exposing it to the user-definable initializations.
I can't think of any reason for foo not to be known at the time when that struct type is being initialized, let alone a good reason. It is legitimate for static construction to create an instance. For example, we could use it to create a "singleton".
This looks like a bug in Python.

Access a function variable outside the function without using "global" [duplicate]

This question already has answers here:
How do I get a result (output) from a function? How can I use the result later?
(4 answers)
Closed 4 months ago.
I am trying to access a local function variable outside the function in Python.
I can make code like this work with global variables:
bye = ''
def hi():
global bye
bye = 5
sigh = 10
hi()
print(bye)
Next, I tried this code, hoping to access bye outside hi() without using global bye:
def hi():
bye = 5
sigh = 10
return
hi()
x = hi()
print(x.bye)
This gives AttributeError: 'NoneType' object has no attribute 'bye'.
Next, I tried:
def hi():
bye = 5
sigh = 10
return bye
hi()
x = hi()
print(x.bye)
This didn't improve matters; I get AttributeError: 'int' object has no attribute 'bye'.
Is there a way to access a local function variable (bye) outside its function (hi()) without using globals and also without printing out the sigh variable? How can I do it?
You could do something along these lines (which worked in both Python v2.7.17 and v3.8.1 when I tested it/them):
def hi():
# other code...
hi.bye = 42 # Create function attribute.
sigh = 10
hi()
print(hi.bye) # -> 42
Functions are objects in Python and can have arbitrary attributes assigned to them.
If you're going to be doing this kind of thing often, you could implement something more generic by creating a function decorator that adds a this argument to each call to the decorated function.
This additional argument will give functions a way to reference themselves without needing to explicitly embed (hardcode) their name into the rest of the definition and is similar to the instance argument that class methods automatically receive as their first argument which is usually named self — I picked something different to avoid confusion, but like the self argument, it can be named whatever you wish.
Here's an example of that approach:
def add_this_arg(func):
def wrapped(*args, **kwargs):
return func(wrapped, *args, **kwargs)
return wrapped
#add_this_arg
def hi(this, that):
# other code...
this.bye = 2 * that # Create function attribute.
sigh = 10
hi(21)
print(hi.bye) # -> 42
Note
This doesn't work for class methods. Just use the instance argument, named self by convention, that's already passed to methods instead of the method's name. You can reference class-level attributes through type(self). See Function's attributes when in a class.
The problem is you were calling print(x.bye) after you set x as a string. When you run x = hi() it runs hi() and sets the value of x to 5 (the value of bye; it does NOT set the value of x as a reference to the bye variable itself). EX: bye = 5; x = bye; bye = 4; print(x) prints 5, not 4.
Also, you don't have to run hi() twice, just run x = hi(), not hi(); x=hi() (the way you had it it was running hi(), not doing anything with the resulting value of 5, and then rerunning the same hi() and saving the value of 5 to the x variable.
So full code should be
def hi():
bye = 5
sigh = 10
return bye
x = hi()
print(x)
If you wanted to return multiple variables, one option would be to use a list, or dictionary, depending on what you need. For example:
def hi():
return { 'bye': 5, 'sigh': 10 }
x = hi()
print x['bye']
def hi():
bye = 5
return bye
print hi()
You could do something along this lines:
def static_example():
if not hasattr(static_example, "static_var"):
static_example.static_var = 0
static_example.static_var += 1
return static_example.static_var
print static_example()
print static_example()
print static_example()
To be able to access a local function's variable, one might add the name of the function and a dot before the name of the local variable (and then, of course, use this construction for calling the variable both in the function's body and outside of it). This solution works in Python 3.7.4.
For example:
def func(): # define a function
# here y is a local variable, which I want to access; func.y
# defines a method for my example function which will allow me to
# access function's local variable y
func.y = 4
x = func.y + 8
return x
func() # now I'm calling the function
a = func.y # I put its local variable into my new variable
print(a) # and print my new variable
If you want to avoid global, one possible approach is to define a class. Each class instance has its own attributes; there is also a class attribute space where instances can share an attribute between them.
Object-oriented programming can be challenging to get into if you are new to Python, but this might actually be a good time to start playing with it.
class Thing:
shared = "foo"
def __init__(self):
"""
This gets called when you create a new Thing()
"""
self.bar = "baz" # default value for new instances
def get_bar(self):
return self.bar
def set_bar(self, value):
self.bar = value
Now, let's create two instances.
first = Thing()
second = Thing()
The get_bar and set_bar methods are not strictly necessary in simple examples like this one. You can also do
second.bar = "ick"
print(second.bar)
# "ick"
print(first.bar)
# "baz"
(though for more complex scenarios, you probably want to require users to call the setter and getter methods; there are ways to force this - see e.g. What's the pythonic way to use getters and setters?)
If you change a class attribute via one instance, it will not be changed in the other instances, either.
second.shared = "poo"
print(first.shared)
# "foo"
But if you change it in the class itself, it will be changed in all the instances which have not separately overridden the shared value.
Thing.shared = "zoom"
print(first.shared)
# "zoom"
print(second.shared)
# "poo", still
To recap, you create a new Thing instance by calling Thing(); this will run the __init__ method before returning the new instance. Inside the class, the instance is the first argument to every (non-static, non-class) method, and conventionally called self (though you could get away with calling it shirley if you wanted to, as far as the Python interpreter is concerned).
There's a lot more to classes; the main selling point is probably that you can create subclasses which inherit from their parent class but can override some behaviors (common examples often involve real-world concepts like animals or vehicles, but a class can just be anything where you want to create a type and encapsulate its behavior, and perhaps override some methods in derived types).

Calling private function within the same class python [duplicate]

This question already has answers here:
How can I call a function within a class?
(2 answers)
Closed 6 months ago.
How can i call a private function from some other function within the same class?
class Foo:
def __bar(arg):
#do something
def baz(self, arg):
#want to call __bar
Right now, when i do this:
__bar(val)
from baz(), i get this:
NameError: global name '_Foo__createCodeBehind' is not defined
Can someone tell me what the reason of the error is?
Also, how can i call a private function from another private function?
There is no implicit this-> in Python like you have in C/C++ etc. You have to call it on self.
class Foo:
def __bar(self, arg):
#do something
def baz(self, arg):
self.__bar(arg)
These methods are not really private though. When you start a method name with two underscores Python does some name mangling to make it "private" and that's all it does, it does not enforce anything like other languages do. If you define __bar on Foo, it is still accesible from outside of the object through Foo._Foo__bar. E.g., one can do this:
f = Foo()
f._Foo__bar('a')
This explains the "odd" identifier in the error message you got as well.
You can find it here in the docs.
__bar is "private" (in the sense that its name has been mangled), but it's still a method of Foo, so you have to reference it via self and pass self to it. Just calling it with a bare __bar() won't work; you have to call it like so: self.__bar(). So...
>>> class Foo(object):
... def __bar(self, arg):
... print '__bar called with arg ' + arg
... def baz(self, arg):
... self.__bar(arg)
...
>>> f = Foo()
>>> f.baz('a')
__bar called with arg a
You can access self.__bar anywhere within your Foo definition, but once you're outside the definition, you have to use foo_object._Foo__bar(). This helps avoid namespace collisions in the context of class inheritance.
If that's not why you're using this feature, you might reconsider using it. The convention for creating "private" variables and methods in Python is to prepend an underscore to the name. This has no syntactic significance, but it conveys to users of your code that the variable or method is part of implementation details that may change.

Categories