Is there a way to access an attribute outside a class? - python

I want to access an attribute outside a class, but even after googling I don't see any similar solution for this particular problem.
class test():
def __init__(self) -> None:
pass
def testpy(self):
self.x = 'Hello world'
value = test().testpy.x
print(value)
>> AttributeError: 'function' object has no attribute 'x'

I think you are confused with what an attribute is.
In your code X is a local variable in the member function testpy. X exists only in that function, and is deleted upon function exit.
If you want a member, write self.x = 'Hello world'. This will create and store a data member called x. Additionally, when you write test().testpy().x you are calling the member function testpy() and are then attempting to call .x on the return result, which will obviously break.

I think you're confusing local scope, with class attributes, and global scope.
You can achieve your result in one of three ways:
Creating a class attribute to access
Using the return keyword to return local values
Using the global keyworld to create a globally scoped variable. Highly not recommended
class test:
def __init__(self) -> None:
self.x = "Hello world"
pass
def testpy(self):
self.x = "Hello world"
x = "Hello world"
global Y
Y = "Hello world - global"
return x
object = test()
value_via_objects_attribute = object.x
value_via_objects_method = object.testpy()
value_via_global = Y
print(value_via_objects_attribute)
print(value_via_objects_method)
print(value_via_global)

In your code, x is a local variable inside a function, not a class attribute. You can return that variable:
class test():
def __init__(self) -> None:
pass
def testpy(self):
x = 'Hello world'
return x
value = test().testpy()
print(value)

Please go through python class tutorial once more.
testpy is a function of class Test, it returns None in the above code. x is an attibute of class Test not function 'testpy'
class Test():
def __init__(self):
pass
def testpy(self):
self.x = 'Hello world'
t = Test()
t.testpy()
value = t.x
print(value)

I think you are confusing your testpy() function with your constructor - the init method. In python, you can initialize a new object by calling the class as if it were a function - ex, "value = test()". When you call this function, the init method gets called, and returns a new object (self). So to declare an attribute on self, in the init function (your constructor), you simply write "self.x = "Hello World".
The full solution to your problem is below.
class test():
def __init__(self):
self.x = 'Hello World'
value = test()
print(value.x)

Related

Create an object from a python function returns a class

I have a function which returns a class:
def my_function():
# some logic
class AClass:
def __init__(self, argument):
init()
return AClass
And when I call this function, it returns a class, not an object of that class, right?
Value = my_function()
My question is how can I create an object from that class AClass?
Thank you.
my_class = my_function()
my_obj = my_class(arg)
Since the method returns a reference to a type you can simply use whatever constructor that is defined for the class directly on the return value.
Take this class for example:
class A:
def __init_(self, n = 0):
self.__n = n
Lets see what happens when reference the type directly when running the interpreter interactively:
>>> A
<class `__main__.A`>
Now lets return the type in a method:
>>> def f():
>>> return A
>>> f()
<class `__main__.A`>
Since the value of referencing the class directly and when returned from a method is the same, you can use that returned value the same you would normally. Therefore a = A() is the same as a = f()(). Even if the class takes parameter you can still reference it directly: a = f()(n = 10)

See function stop from locating defined class in Python

I'd like to define a class inside a function (for testing purpose) and put a value into
a function variable:
def foo():
myvar = None
class myclass:
def run(self):
myvar = 5
mm = myclass()
mm.run()
print(myvar)
The above prints None
Is there any way other than global to make the myvar variable accessible from the class? The correct answer would print 5
It's not possible to assign a value to a variable outside the current scope without global. If you need to persist the value within the class you can define class variables instead. Example:
def foo():
class Class:
var_to_change = None
def run (self):
self.var_to_change = 5
print (Class.var_to_change)
instance = Class()
instance.run()
print (Class.var_to_change)
I haven't tested the above code but it should work in theory.

Python Variables across Class functions - how to call them?

Instead of using a global variable, I'm trying to make an instance of a variable in a class, as it seems to be best practice. How do I reference this variable across other functions in the class? I would have thought that Test.running_sum would work or at least running_sum in test_function, but I'm not having any luck with either. Thanks very much!
class Test:
def __init__(self):
self.root = None
running_sum = 0
def test_function(self):
print(Test.running_sum)
return
x = Test()
x.test_function()
Error:
Traceback (most recent call last):
File "so.py", line 1, in <module>
class Test:
File "so.py", line 10, in Test
x = Test()
NameError: name 'Test' is not defined
Use self parameter provided in the method signature.
Note that what you wrote is not a method, but an external function using class Test. To write a method of Test, the def should be at one level of indentation inside class Test as following:
class Test:
def __init__(self):
self.running_sum = 0
def test_function(self):
print(self.running_sum)
There are several things to add if you want an explanation behind this "best practice".
Assuming you write the following code:
class Test:
numbers = []
def add(self, value):
self.numbers.append(value)
The Test.numbers list is instantiated once and shared accross all instances of Test. Therefore, if 2 different instances add to the list, both act on the same list:
a = Test()
b = Test()
a.add(5)
b.add(10)
assert a.numbers == b.numbers == Test.numbers
When creating instance variables in the __init__ function, __init__ will be run at each instantiation, and therefore, the list will no longer be shared because they will be created for each individual instances.
class Test:
def __init__(self):
self.numbers = []
def add(self, number):
self.numbers.append(number)
a = Test()
b = Test()
a.add(5)
b.add(10)
assert a != b
As an object attribute: each object gets its own.
Test is the class; self is the Test object that invoked the method.
class Test:
def __init__(self):
self.root = None
self.running_sum = 0
def test_function(self):
self.running_sum += 1
print(self.running_sum)
return
x = Test()
y = Test()
x.test_function()
y.test_function()
Output:
1
1
As a class attribute: all objects share the same variable.
self.__class__ is the class of the invoking object (i.e. Test).
class Test:
running_sum = 0
def __init__(self):
self.root = None
def test_function(self):
self.__class__.running_sum += 1
print(self.__class__.running_sum)
return
x = Test()
y = Test()
x.test_function()
y.test_function()
Output:
1
2
how do I reference this variable across other functions in the class
Several things I see wrong here. First of all, you are calling running_sum on the class itself which doesn't make sense since you are declaring running_sum as an attribute of an instance of Test. Second, from the way you formatted your question, it seems that test_function is outside of the class Test which doesn't make sense since you are passing self to it, implying it is an instance method. To resolve you could do this:
class Test:
def __init__(self):
self.running_sum = 0
def test_function(self):
print(self.running_sum)
Then again this also is weird... Why would you need a "test_function" when you can simply test the value of running_sum by simply doing:
x = Test()
x.running_sum
In your __init__ function, you've created a local variable. That variable will no longer exist after the function has completed.
If you want to create a variable specific to the object x then you should create a self.running_sum variable
class Test:
def __init__(self):
self.root = None
self.running_sum = 0
def test_function(self):
print(self.running_sum)
If you want to create a variable specific to the class Test then you should create a Test.running_sum variable.
class Test:
running_sum = 0
def __init__(self):
self.root = None
def test_function(self):
print(Test.running_sum)

Is there a python construct that is a dummy function?

Is there a python construct that corresponds to a function taking no argument, doing nothing and returning nothing ? Something similar to object None but that would be a function instead of an object ?
The context
I want to define a class where the constructor gets a function as an argument and references it to a class attribute. Upon instanciation, the user decides whether he/she wants that function to be an actual function which he/she defines him/herself or leave the default which is to call a dummy function which does nothing.
Here is what I have now :
def sayHello():
print("hello world !")
def doNothing():
pass
class myClass:
def __init__(self, myFunc):
self.doIt = myFunc
myInstance = myClass(sayHello)
myInstance.doIt()
myInstance = myClass(doNothing) # Works but requires defining function doNothing()
myInstance.doIt()
#myInstance = myClass(None) # Returns error "'NoneType' object is not callable"
myInstance.doIt()
How about lambdas?
myInstance = myClass(lambda:None)
Sure you can pass is as default to your __init__ function:
class myClass:
def __init__(self, myFunc = lambda:None):
self.doIt = myFunc
This should work:
class myClass:
def __init__(self, myFunc = lambda : None):
self.doIt = myFunc
myInstance = myClass()
I used the following:
a=lambda:None
a()
print a()
The latter line prints None.
This worked for me:
def none(function=True):
if function==True:
return None
else:
function()

About python class __init__ and Decorators

when I learn 'property' of python, To my surprise, the output is not as same as expected.The code illustrated below:
class HideX(object):
def __init__(self,x):
self.x = x
def get_x(self):
return ~self.__x
def set_x(self,x):
assert isinstance(x,int),\
'"x" must be an integer!'
self.__x = ~x
x = property(get_x, set_x)
inst = HideX(20)
#inst.x = 20#
when it executes inst = HideX(20). I think it will call __init__(self,x) so the instruction self.x = xwill be executed. The problem occurs. I think it will not call x = property(get_x, set_x)because self.x is in the body of class (it is in the top of the class).I've always thought
only in the outside of class (as show in #..#)can we access x = property(get_x, set_x) am I wrong? can you understand what I mean?
sovled:
After repeated tests, I found amazedly that when we executeinst = HideX(20), the code x = property(get_x, set_x)
will be called in the first place ,not the 'init(self,x)'.Totally beyond my expectation!!!(In the java ,when we create an instance,the init() of the class will be first called i think ,maybe i am wrong)
(1)Can you give me an explanation of the intrinsic mechanism? I am a green hand,Thanks for your patience.
the code below is the Segment I copy from :
class HideXX(object):
def __init__(self, x):
self.x = x
#property
def x():
def fget(self):
return ~self.__x
def fset(self,x):
assert isinstance(x,int),\
'"x" must be an integer!'
self.__x = ~x
return locals()
#x = property(**x())
inst = HideXX(1)
But it can not run correctly
the error code is :
File "<string>", line 21, in <module>
File "<string>", line 4, in __init__
AttributeError: can't set attribute
(2)Is the book wrong ?? When I removed #property and add the code 'x = property(**x())' It works!!!
can you explain the reason for me ? thanks very much
For your first question , the answer is simple, x is an attribute of the class (not the object/instance of the class) , it would be evaluated when the class gets defined (not when its object is created).
An Example to show this -
>>> class CA:
... y = print("Hello")
... def __init__(self):
... print("Blah")
...
Hello
>>> c = CA()
Blah
As you can see the value of y gets calculated when the class is defined, its the same with all functions in the class, they get defined when the class gets defined, but they are evaluated only when the function gets called.
Also, using the #property is not same as property(**x()) , when you do the later , **x() resolves to -
{'fget': <function HideXX.x.<locals>.fget at 0x00943B28>, 'fset': <function HideXX.x.<locals>.fset at 0x00943CD8>}
And then these positional arguments are used for setting the getter and setter for the property x , whereas the #property annotation is used to define the getter for property x.

Categories

Resources