This question already has an answer here:
'int' object is not callable in python
(1 answer)
Closed 6 years ago.
I'm new to python:
Created a Class:
class NodeStruct:
"""Struct to hold node data for search trees"""
def __init__(self, name, children, parent_name, edge_weight):
self.name = name
self.childNodes = children
self.parent = parent_name
self.weight = edge_weight
def name(self):
return self.name
def parent(self):
return self.parent
def path_cost(self):
return self.weight
def children(self):
return self.childNodes
def child_keys(self):
return self.childNodes.keys()
Instantiate:
this_node = NodeStruct(start, problem[start], 'root', 0)
The Problem: when I make a call to name()
name = this_node.name()
I get the following error:
TypeError: 'str' object is not callable
Looks like it should be straight forward... What am I missing?
When you define your class, name is a function. As soon as you instantiate it, though, __init__ is called, and name is immediately set to whatever you pass in (a string in this case). The names of functions are not kept separate from the names of other objects. Use a unique name.
Which one of the names do you expect this_node.name() to find?
self.name = name
# ...
def name(self):
return self.name
The solution is likely to change the name of the attribute to self._name:
self._name = name
# ...
def name(self):
return self._name
Related
I have following code:
class T:
def __init__(self, name):
self.name = name
self.age = None
#property
def age(self):
return 30
t = T('j')
when I create object t, it'll have error AttributeError: can't set attribute 'age'.
I understand here with #property, actually self._name is created for the object. So self._name will be in conflict with self.name?
Or if I'm wrong, then what's causing the conflict here?
I know that each instance will inherit that attribute, but I want a function or should I call it a method of that class to return the set of all instances created of that class.
So let's say I created 3 instances and call a method from the last one that will return all the previously created instances as well as the one that I am calling it from.
I was able to achieve it by making a list, but would it be possible to return a set?
Is there some kind of constructor that I am missing for it?
class Bee():
instances = []
def __init__(self, name, identifier):
self.name = name
self.identifier = identifier
def __str__(self):
self.instances.append(f"{self.identifier} {self.name}")
return f"{self.identifier} {self.name}"
def get_hive(self):
return self.instances
Normally you would create Hive as a separate class and put the Bees inside. You then have a clear and explicit data structure whose job includes keeping track of all Bees created.
Something like:
class Hive:
def __init__(self):
self.bees = []
def add_bee(self, bee):
self.bees.append(bee)
class Bee:
def __init__(self, name, identifier):
self.name = name
self.identifier = identifier
def __str__(self):
return f"Bee({self.name}, {self.identifier})"
def __repr__(self):
return str(self)
# User code example
hive = Hive()
b1 = Bee('My Bee', 0)
b2 = Bee('Some Other Bee', 1)
hive.add_bee(b1)
hive.add_bee(b2)
print(hive.bees) # display all bees inside the hive
Is it a good style to create classes like that ? I read the PEP8 document but I didn't saw any good example. If not how is it a proper way ? Thanks for any answers.
class Zone:
def __init__(self, index=None, name=None):
self._index = index
self._name = name
#property
def index(self):
return self._index
#property
def name(self):
return self._name
#index.setter
def index(self, index):
self._index = index
#name.setter
def name(self, name):
self._name = name
Your setters and getters don't do anything. With your implementation, the user of this class does this:
z = Zone()
z.name = 'foo'
print(z.name)
Compare to this implementation:
class Zone:
def __init__(self, index=None, name=None):
self.index = index
self.name = name
z = Zone()
z.name = 'foo'
print(z.name)
It works exactly the same with a lot less code.
Unless you do anything in your setters and/or getters, you don't need them.
If what you intend doing is encapsulating your data and setting it with setters and getting it with getters, then what you did will not be helpful. you declared the _name and _index as protected, it does not mean it cannot be accessed by extenal functions, so functions outside the class can easily access and change them, making your getter and setter to be useless.
However, you can declare them as private by using one additional underscore in front, so that your property class will be removed and then the setters class will be useful, it will no longer be accessed by external functions.
class Zone:
def __init__(self,index=None,name=None):
self.__index = index
self.__name = name
def index(self, index):
self.__index = index
def name(self, name):
self.__name = name
def get_name(self):
return self.__name
zone=Zone()
zone.name('ben')
print(zone.get_name())
>>>ben
print(zone.__name)
>>> AttributeError: 'Zone' object has no attribute '__name'
I am trying to figure out if there's a way to (unit test) verify that the property and the setter is actually called to set the name attribute.
class DummyName:
def __init__(self):
self.name = ''
#property
def name(self):
return self.name
#name.setter
def name(self, name):
if not isinstance(name, basestring):
raise Exception('Name must be a string.')
self.name = name
Trying to do something like this...
#mock.patch.object(DummyName, 'name', new_callable=PropertyMock)
def testNameProperty(self, mock_name):
MockName = Mock()
mock_name.return_value = MockName
dummyName = DummyName()
dummyName.name = 'test_name'
# assert setter is called to set the name
# assert name is called to get the name
# assert name is 'test_name'
Seems like name() and setter are never accessed. the Anyone has a better idea? Thanks!
By using mocks like that you've overwritten the code you're trying to test. Mocks are for calls that are external to the code under test.
An appropriate test for this code is to assert that the exception is raised if you pass something that isn't a string.
def testNameProperty(self):
dummyName = DummyName()
with self.assertRaises(Exception):
dummyName.name = 12345
Your class needs to inherit from object.
class DummyName(object):
def __init__(self):
self._name = ''
#property
def name(self):
return self._name
#name.setter
def name(self, name):
if not isinstance(name, basestring):
raise Exception('Name must be a string.')
self._name = name
You also need to use different variables for the name inside the class, or you'll hit maximum recursion.
How can I get slots to work with #property for the class below. I have several thousand instances of below class which is causing memory issues and so I added the slots
I created instances with data and then add location information later to the instances.
After adding slots my instance creation is not working and I am getting the following error
AttributeError: 'Host' object has no attribute '_location'
class Host(object):
__slots__ = ['data', 'location']
def __init__(self, data, location=''):
self.data = data
self.location = location
#property
def location(self):
return self._location
#location.setter
def location(self, value):
self._location = value.lower()
def __repr__(self):
if self.location == '':
self.loc = 'Not Found'
else:
self.loc = self.location
return 'Host(name={}, location={})'.format(self.name, self.loc)
__slots__ works by creating descriptors on the class that have direct access to the in-memory data structure of your instance. You are masking the location descriptor with your property object, and you defined a new attribute _location than is not in the slots.
Make _location the slot (as that is the attribute you are actually storing):
class Host(object):
__slots__ = ['data', '_location']
The location property (also a descriptor object) can then properly assign to self._location, an attribute backed by the slot descriptor.
Note that you do not need to use self.loc in the __repr__, just make that a local variable instead. You also are trying to use a self.name attribute which doesn't exist; it is not clear what value that is supposed to be however:
def __repr__(self):
loc = self.location or 'Not Found'
name = self.data['name'] # or some other expression
return 'Host(name={}, location={})'.format(name, loc)
The definition for __slots__ should have the names of the underlying attributes that will store the data referenced by your properties. In the example below, name mangling is invoked for variables that should not be accessed outside of the class. The code is similar to yours and has no errors according to the PEP8 online website.
#! /usr/bin/env python3
def main():
print(Host('Hello, world!', 'Earth'))
print(Host('Hello, Xyz!'))
class Host:
__slots__ = '__name', '__location'
def __init__(self, name, location=''):
self.name = name
self.location = location
def __repr__(self):
return '{!s}({!r}, {!r})'.format(
type(self).__name__,
self.name,
self.location
)
#property
def name(self):
return self.__name
#name.setter
def name(self, value):
self.__name = value
#property
def location(self):
return self.__location
#location.setter
def location(self, value):
self.__location = value.casefold() if value else 'Not Found'
if __name__ == '__main__':
main()