简体   繁体   中英

call method on returned value of another method in class

So I want to call method on returned value from another method of same class.

class A():

    def __init__(self,data):
        self.data = data

    def values(self,key):
        return list(list(x.values())[0] for x in self.data['data'] if key in x.keys())

    def length(self):
        return len(self)

data ={"data":[{"country":"india"},{"state":"punjab"},{"country":"usa"}]}
obj = A(data)
res = obj.values('country') # returns ['india', 'usa']
res1 = obj.values('country').length() #  returns AttributeError: 'list' object has no attribute 'length'
print(res)
print(res1)

i want both res and res1 to work.

I have also tried using @property decorator

class B():
    def __init__(self,data):
        self.data = data

    def __call__(self, key):
        self.key = key
        return self

    @property
    def values(self):
        self.valu =  list(list(x.values())[0] for x in self.data['data'] if self.key in x.keys())
        return self

    def length(self):
        return len(self.valu)

data ={"data":[{"country":"india"},{"state":"punjab"},{"country":"usa"}]}
obj = B(data)
res = obj('country').values.length()     #  returns 2
res1 = obj('country').values      # returns <__main__.A object at 0x103a9fbe0>
print(res)
print(res1)

This way res works but res1 does not.

Thanks

.length() is not a python list function. Use len(listobject) instead.

Eg:

len(obj('country').values)

If you want to print the values. In your second example:

#Use 
res1 = obj('country').data

#instead of
res1 = obj('country').values

Use below code to get list of countries


res1 = [_dict.get('country') for _dict in obj('country').data.get('data') if 'country' in _dict.keys()]

print(res1)
#['india', 'usa']

Final Updated working code:

class B():
    def __init__(self,data):
        self.data = data

    def __call__(self, key):
        self.key = key
        return self

    @property
    def values(self):
        self.valu =  list(list(x.values())[0] for x in self.data['data'] if self.key in x.keys())
        return self

    def length(self):
        return len(self.valu)

data ={"data":[{"country":"india"},{"state":"punjab"},{"country":"usa"}]}
obj = B(data)
res = obj('country').values.length()     #  returns 2
res1 = [_dict.get('country') for _dict in obj('country').data.get('data') if 'country' in _dict.keys()]      # returns ['usa', 'india']
print(res)
print(res1)

I think the confusion here is on what object is the .length method invoked. In the first case, it is invoked on a list which does not have a .length method. In the second case, it is invoked on the B object which indeed has a .length method. The most straightforward and preferred solution is what @Subhrajyoti Das suggested.

If you still want your code (as described in the question) to work (or just want to know if this could actually be done), you could define a custom list object which would look like as follows:

class CustomList(list):
    def length(self):
        return len(self)

Now instead of making a list , you would make a CustomList .

Edit: Adding the complete example, as requested in the comment.

class CustomList(list):
    def length(self):
        return len(self)

class A():

    def __init__(self,data):
        self.data = data

    def values(self,key):
        return CustomList(CustomList(x.values())[0] for x in self.data['data'] if key in x.keys())

    def length(self):
        return len(self)

data ={"data":[{"country":"india"},{"state":"punjab"},{"country":"usa"}]}
obj = A(data)
res = obj.values('country') # returns ['india', 'usa']
res1 = obj.values('country').length() # 2
object has no attribute 'length'
print(res)
print(res1)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM