Abc Xyz
Abc Xyz

Reputation: 1424

Python - return default method on class initialization

I'm refactoring code and wonder if this is possible.

def a(array):
    class MyClass(object):
        def length():
            return len(array)
    return MyClass
                                                                               
print(a([1,2,3,4]).length())                                                      
print(a([1,2,3,4]))

It returns

4
<class '__main__.a.<locals>.MyClass'>

and i want:

4
4

Trying hard, i read about metaclass and __new__ but cant figure out how to do it.

or

class a():          
    def __init__(self, array):
        self.array = array
    def length(self):
        return len(self.array)

print(a([1,2,3,4]).length()) #   4                                                  
print(a([1,2,3,4]))          #   <__main__.a object at 0x7fab704c9e50>

It's not working, it has 50% functionality.

So sad i don't have time right now but with my today's knowledge its impossible to do it with metaclass. In sqlite3 we can use cur.execute("SQL;"), cur.execute("SQL;").fetchone() so it is possible to do it.

class Metaclass(type):
    def __new__(metacls, name, bases, attrs):                                                                     
        try:                                                                   
            return attrs['length']()                                                                                                                                              
        except KeyError:                                                                          
            pass                                                               

        return type.__new__(metacls, name, bases, attrs)

def a(array):
    class MyClass(metaclass=Metaclass):
        def length():
            return len(array)
    return MyClass

print(a([1,2,3,4]).length()) #   <-  This is not working.                                                 
print(a([1,2,3,4]))          #   4

I would like to hear if it could be done better or smarter tham my solution, because using function returning class it's a hack in my opinion.

Studied this code and its impossible to know when to replace returning object, i will retype this to class without function. Just checked same problem with just single class. Had trouble with passing arguments from method to metaclass.

Upvotes: 0

Views: 598

Answers (2)

Abc Xyz
Abc Xyz

Reputation: 1424

This is what i was doing

import sqlite3                                                                                                   
import contextlib                                                                                                
class cur_execute():                                                                                            
    def __init__(self, sql, data=[]):                                                                            
        self.sql = sql                                                                                           
        self.data = data                                                                                         
                                                                                                             
    def fetchall(self):                                                                                          
        with sqlite3.connect('/opt/portal/db/portal.sqlite3') as con:                                            
            con.execute('pragma journal_mode=wal;')                                                              
            con.row_factory = sqlite3.Row                                                                        
            with contextlib.closing(con.cursor()) as c:                                                          
                for row in c.execute(self.sql, self.data):                                                       
                    yield row                                                                                    
                                                                                                             
    def __iter__(self):                                                                                          
        yield from self.fetchall()                                                                               
                                                                                                             
for row in cur_execute("SELECT * FROM ITEMS;").fetchall():                                                      
    print(str(row))                                                                                              
for row in cur_execute("SELECT * FROM ITEMS;"):                                                                 
    print(str(row))

__repr__ and __iter__ are solution for this king of problems.

Upvotes: 0

ForceBru
ForceBru

Reputation: 44828

You can simply define __repr__ for your class and make it return the length of the list as a string:

class a():          
    def __init__(self, array):
        self.array = array
    def length(self):
        return len(self.array)

    def __repr__(self):
        return str(self.length())

Example:

>>> print(a([1,2,3,4]))
4

Upvotes: 2

Related Questions