Python class and variables - python

Learning Python and I ran into some problems when I was working on making a linked list class.
This is just a quick node and dirty node class. In java I would of down private Node next and private int val but I only knew of global as the python cousin. How does this look?
#class Node class
class Node(object):
global next
global val
def __init__(self):
next
val
def setNext(self, aNext):
self.next = aNext
def getNext(self):
return self.next
def setVal(self, aVal):
self.val = aVal
def getVal(self):
return self.val
Then I tried to use a Node in another class with
from Node import *
head = Node()
How ever I am getting an error of undefined variable. Sorry for the simple question just new to python. Appreciate the help.

I would implement this this way:
class Node(object):
def __init__(self, next=None, val=None):
self.next = next
self.val = val
That's it. No getters or setters - Python doesn't use them. Instead, you refactor into a property if you need to move away from the basic attribute reference logic.
You can then create nodes with or without values or successors:
tailnode = Node()
tailnode.val = 'foo'
midnode = Node(val='bar')
midnode.next = tailnode
headnode = Node(val='baz', next=midnode)

You don't need the "global val" / "global next" .. It's a mistake even.
instead just write
val = None
next = None
and initiate them in the __init__()
Meaning, the first lines in your class should be like:
class Node(object):
# You can choose whether to initialize the variables in the c'tor or using your setter methods
def __init__(self, val=None, next=None):
self.next = next
self.val = val

If you really want private variables in Python… then you don't want private variables, and should read Peter DeGlopper's answer.
If you still really, really want private variables in Python… well, you can't have them. But you can have "cooperatively private" variables—variables that nobody will find unless they go looking for them, and that won't clutter the screen when you introspect things in the interpreter, and so on, and, most importantly, that Python programmers know, by convention, that they aren't supposed to touch. All you have to do is start the name with an underscore.
However, your code isn't creating member variables at all, for a number of reasons.
First, global does not declare or define a variable; all it does is tell Python, "when you see this variable later, don't use the normal rules to figure out if it's local or global, always use the global copy". You still have to assign a value to the variable somewhere; otherwise, you'll get a NameError.
Next, variables that you assign in the class definition are class members—similar to Java's static members, although not identical. Each class member is shared by all instances of the class. That's not what you want here; each Node is supposed to have its own separate val and next, not share one with all other Nodes, right?
Normal instance member variables are always accessed through dot syntax—as self.foo from inside the class's methods, or as spam.foo from outside.
So, where do you declare those? You don't. Python doesn't declare anything. You can add new members to an object at any time. The usual way to create a standard set of instance members is in the __init__ method:
class Node(object):
def __init__(self):
self._next = None
self._val = None
def setNext(self, aNext):
self._next = aNext
def getNext(self):
return self._next
def setVal(self, aVal):
self._val = aVal
def getVal(self):
return self._val
But really, you can just let the setters create them. That way, you'll catch the error if someone calls getNext without having called setNext first (which is, I assume, illegal).
class Node(object):
def setNext(self, aNext):
self._next = aNext
def getNext(self):
return self._next
def setVal(self, aVal):
self._val = aVal
def getVal(self):
return self._val
Or, alternatively, force the user to initialize the object with valid values at construction time:
def __init__(self, next, val):
self._next = next
self._val = val
Again, there's no good reason to use setters and getters in the first place in Python.
So, the simplest implementation of your class is:
class Node(object):
pass
While the most Pythonic is:
class Node(object):
def __init__(self, next, val):
self.next = next
self.val = val
… which, you'll notice, is Peter DeGlopper's answer, which, as I said at the start, is probably what you want. :)

Python doesn't really use private variables.
Something like this would be best:
class Node(object):
def __init__(self):
self.val = None
self.next = None
Then, you make and set the node like this:
>>> node = Node()
>>> node.val = 5
>>> node2 = Node()
>>> node2 = 1
>>> node.next = node2
>>> node.next.val
1
If you want to create node with Node(5, Node(1)), use:
class Node(object):
def __init__(self, value=None, next=None):
self.value = value
self.next = next

Related

When defining class attributes, which method of writing is more "Pythonic"?

I do this fairly frequently, and maybe it's bad design and there's a better way to do it, but I haven't ever had any issue.
When defining an object with a parent and assigning an attribute of that object to an attribute of the parent, which of these methods of writing is more "Pythonic"?
Assuming we are doing something like...
class SomeParent:
def __init__(self, value):
self.value = value
class SomeChild { ... }
parentObj = SomeParent(value="foo")
childObj = SomeChild(parent=parentObj)
Would the "proper" way to write the __init__ for SomeChild be...
class SomeChild:
def __init__(self, parent):
self.parent = parent
self.value = parent.value
Or...
class SomeChild:
def __init__(self, parent):
self.parent = parent
self.value = self.parent.value
The only difference being the use of self when defining value on the child object. Obviously, they both (seemingly) work exactly the same, does it even matter which is used? Or am I overthinking this?
You can do this more cleanly with a property:
class A:
def __init__(self, value):
self.value = value
class B:
def __init__(self, a):
self.a = a
#property
def value(self):
return self.a.value
assert B(A(2)).value == 2
This way, B.value will automatically update with a.value.
Note: I purposefully don't use the names "parent" and "child" which would imply inheritence. You are not using inheritence.

Alleged misunderstanding in using super [duplicate]

I have to do an unrolled linked list for one of my classes. I'm new to python, but not to programming, and for some reason I cannot get around this little problem!
I have a class Node that is to be the node object used within the unrolled linked list. The unrolled linked list class performs all the operations on the Node class.
class UnrolledLinkedList(object):
""" INNER NODE CLASS """
class Node(object):
def __init__(self):
self.array = []
self.next_node = None
""" END NODE CLASS """
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = Node()
""" OTHER FUNCTIONS OF UNROLLEDLINKEDLIST CLASS """
The problem comes at the last line of the UnrolledLinkedList class' init function: "global name Node is not defined". I double checked my indentation and looked all over the internet for examples of something like this, but couldn't find any. Would someone mind explaining to me what's wrong?
Methods do not include their class as a scope to be searched. If you want this to work then you will need to use either UnrolledLinkedList.Node or self.Node instead.
The inner class Node is a member of the class UnrolledLinkedList and can only be accessed via self.
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = self.Node()
Use:
self.head = self.Node()
and it works.
A class does not create its own name space. Using self.Node(), Python first searches all attributes of the instances. Since it does not find the name Node there, it it searches the class UnrolledLinkedList for Node.
Alternatively, you can use the class name directly:
UnrolledLinkedList.Node()
You can achieve the same without nesting the class Node:
class Node(object):
def __init__(self):
self.array = []
self.next_node = None
class UnrolledLinkedList(object):
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = Node()
Qualify Node() with self:
class UnrolledLinkedList(object):
class Node(object):
def __init__(self):
self.array = []
self.next_node = None
def __init__(self, max_node_capacity=16):
self.max_node_capacity = max_node_capacity
self.head = self.Node()
Python needs to qualify references to things. In this case, you could either say UnrolledLinkedList.Node() or self.Node().

Invoke a class function with a parameter in python

Let's say I have a simple linked list class:
class LL:
def __init__(self):
self.next = None
self.previous = None
def next(self):
return self.next
def previous(self):
return self.previous
In this case, I want to invoke previous or next, based on what is passed into a function in another class, like so:
class foo:
def __init__(self):
self.node = LL()
def move(direction):
self.node = self.node.direction
S.t. when it makes a call, it would call self.node.next() or self.node.previous().
Where move("next") would make a call to self.node.next().
This doesn't work. Nor does
self.node = self.node.direction()
How would I go about accomplishing something like this?
I'm not sure how to even formally describe this- assigning a class attribute by calling an alternate class' method via a parameter?
For your case, it would be best to keep it simple with an if statement.
def move(direction):
if direction == 'next':
self.node = self.node.next()
elif direction == 'previous':
self.node = self.node.previous()
else:
#handle the invalid input however you think is best
However, you should rename either the field or the method for both next and previous. I would recommend changing next(self) to getNext(self). Alternately, you could change self.next to self._next to indicate that the field is not intended to be accessed directly.
As #user2357112 demonstrated, your LL class itself has shadowing issues. You'll probably want to modify it to perhaps one of the following:
class LL:
def __init__(self):
self._next = None
self._previous = None
# assign a different name
def next(self):
... do something like move the node to next
... maybe change self._next on the way...
return self._next
# Or make use of property decorator
#property
def previous(self):
... do something like move the node to previous
return self._previous
#previous.setter
def previous(self, value):
... do something to change self._previous
Somehow I still don't think that's what you're after, but to answer the spirit of your question, you can use a dict like a switch statement in your foo() class like so:
class foo:
def __init__(self):
self.node = LL()
def move(direction):
_moves = {
'next': self.node.next,
'previous': self.node.previous,
'nowhere': self.node.nowhere
}
# if you're invoking a method
_moves.get(direction)()
# if you're just referencing an attribute
_moves.get(direction)
Conceptually I think it's more important to think about what you're trying to achieve with LL and foo before proceeding though.

Python - How explicitly change evaluation of class object?

The function my_func gets one argument, that could be integer or a class:
class SomeClass:
val = 0
def __init__(self):
self.val = 0
def set(self, val):
self.val = val
def get(self):
return self.val
and I want to work with both types as one.
Can I somehow explicitly tell Python, that evaluation of an object of type SomeClass, should return the val field of the object, but not the object it selves.
That means to get the following code work (somehow):
s = SomeClass()
s.set(3)
test = s # this line should assign value 3(int) to test
test # prints 3
Not really, no, not in the broad sense that you seem to ask for. You can overload many operations, not assignment. That's because variables are just references to objects and have no type attached. At any given time there can be many references to your object. It matters how you use the object, not what you assigned it to.
Instead, I'd make your class convertible to an integer. You can do so with the object.__int__ hook; your setter would explicitly call int() on the object passed in:
class SomeClass:
val = 0
def __init__(self):
self.val = 0
def set(self, val):
self.val = int(val)
def get(self):
return self.val
def __int__(self):
return self.val
If you always use these objects in integer arithmetic, you could add hooks for those operations, such as object.__add__ and object.__sub__; again, it is the context in which the object is used that matters.

Python object state tracking idiom

I have an object that acts as an interface to a remote system, and I need to keep track of various states. Which is the better or more pythonic way of doing this? would one way be preferable if the list of states gets really long or complicated?
A. with object attributes:
class Session (object):
def__init__(self):
self.a_set = False
self.b_set = False
def set_a(self):
self.a_set = True
B. with a dict that represents the state:
class Session (object):
def__init__(self):
self.state = {}
def set_a(self):
self.state['a_set'] = True
Additional Details:
I originally set up a state dict, so that I could do a quick reset:
def reset_state(self):
for k in self.state:
self.state[k] = False
I may end up with a bunch of sub-classes that will need to track additional states, but still reset them all at once.
I just want to make sure I'm not shooting myself in the foot, or doing anything really weird/anti-pattern.
From the user perspective, it should look like the first option; we should be able to use:
if session.a_set:
do_something()
There are a couple different ways to implement that:
# simple method
class Session(object):
def __init__(self):
self.a_set = False
self.b_set = False
def reset(self):
self.b_set = False
However, if you have more than a couple hand-fulls of variables this would quickly become a maintenance nightmare.
I suggest the class decorator approach, with a couple helpers:
# not strictly necessary
class Persist(object):
"""
Do not clear this variable with reset().
"""
def __init__(self, val):
self.val = val
# necessary
class Reset(object):
"""
Clear this variable with reset().
"""
def __init__(self, val):
self.val = val
def BuildResets(cls):
reset = cls.resetable = []
persist = cls.persistent = []
for name, obj in cls.__dict__.items():
if isinstance(obj, Reset):
setattr(cls, name, obj.value)
reset.append(name)
elif isinstance(obj, Persist):
setattr(cls, name, obj.value)
persist.append(name)
return cls
and in use:
#BuildResets
class Session(object):
self.a_set = Persist(False)
self.b_set = Reset(False)
def reset(self):
for name in self.resetable:
setattr(self, name, False)

Categories