简体   繁体   中英

class without init method accepting arguments

    from sqlalchemy import create_engine
    
    from sqlalchemy import Sequence
    Base = declarative_base()
    Column(Integer, Sequence('user_id_seq'), primary_key=True)
    engine = create_engine('sqlite:///:memory:', echo=True)
    class User(Base):
        __tablename__ = 'users'
        id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
        name = Column(String(50))
        fullname = Column(String(50))
        nickname = Column(String(50))
    
        def __repr__(self):
            return "<User(name='%s', fullname='%s', nickname='%s')>" % (
                                    self.name, self.fullname, self.nickname)
    
    class User1(Base):
        __tablename__ = 'users1'
        id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
        name = Column(String(50))
        fullname = Column(String(50))
        nickname = Column(String(50))
        
        def __init__(self, name, fullname, nickname):
            self.name = name
            self.fullname = fullname
            self.nickname = nickname

    
        def __repr__(self):
            return "<User(name='%s', fullname='%s', nickname='%s')>" % (
                                    self.name, self.fullname, self.nickname)
    
 ed_user = User(name='ed', fullname='Ed Jones', nickname='edsnickname')
 ed_user = User1(name='edd', fullname='Edd Jones', nickname='edsnick')

i picked up this piece of code from the sqlalchemy documentation website, I think everything is okay, but i have a problem understanding the last line, the class user inherits from the base class, buy the user class is not having an init methods in other to accept any argument. can some please explain this to me.. thanks. this two-class achieves the same result they create a table, but in the second instance, the User1 has an init method declared, so obviously the creation of the table happens in the base class, but in the second instance the class and instance variable were declared I want to know how will the base class be able to create the table if it is not receiving any data from the child class.

Python is a very dynamic language. There are several ways to achieve this. One is inheriting from its superclass, as @vrevolverr says. But unfortunately here is not this case. You can confirm that by running print(Base.__init__ is User.__init__) , which will give you a False . That means User.__init__ is not inherited from Base .

Another evidence is that print('__init__' in User.__dict__) gives you True , which means that User class has its own __init__ method. And this method can only be given by its metaclass. So the answer comes out. By the way, in your case, this metaclass is DeclarativeMeta in sqlalchemy.ext.declarative .

Just FYI. Simply put, metaclass can do something during the creating process of a class. For example, add a method to this class. This is where your __init__ comes from.


Update:

My original answer also solves your second question. But I still want to add some comments.

First, does User1.__init__ take effect? The answer is NO. Try this simple test:

def init(self, name, fullname, nickname):
    self.name = name
    self.fullname = fullname
    self.nickname = nickname

class User(Base):
    ...
    __init__ = init

print(User.__init__ is init) # False

You can see that the __init__ method defined by you is already replaced.

Then, how to perform this "magic"? See below:

def init1(self):
    pass

def init2(self):
    pass

class MyMeta(type):
    # You can also do this in __new__
    def __init__(cls, *args, **kwargs):
        cls.__init__ = init2
        type.__init__(cls, *args, **kwargs)


class MyClass(metaclass=MyMeta):
    __init__ = init1

print(MyClass.__init__ is init1) # False
print(MyClass.__init__ is init2) # True

If the child class (the class which inherits) does not have a class constructor ( init method), the child class will call the constructor of the parent class. However, if the child class has a constructor, it will call its own constructor.

Consider the following examples:

Child class without constructor

class ParentClass:

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


class ChildClass(ParentClass):

    def child_method(self):
        print(self.parent_arg)


c = ChildClass(parent_arg="Test")
c.child_method() # Output: Test

Child class with constructor

class ChildClass(ParentClass):

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

    def child_method(self):
        print(self.child_arg) # Output: Child Test

        # This will throw an error since this attribute is created by the parent constructor
        print(self.parent_arg)

c = ChildClass(child_arg="Child Test")
c.child_method()

To call the parent constructor, pass the arguments for parent class through the constructor of child class and use super() to call the constructor of parent class

def __init__(self, child_arg, parent_arg):
    self.child_arg = child_arg
    super().__init__(parent_arg)

print(self.parent_arg) # This will then work

if I understand your question well, you want to understand why the User class contains no __init__ method yet it was able to receive arguments, just as @snakecharmerb answered, the User class was able to receive arguments even though it has no init method of it own, this is possible because the class from which User inherited called base have all ready implemented the init method, so you can use the init method from the base class without declaring anyone explicitly. for instance if you inherit a car from your dad, you will be able to use that car even though you don't have a car you bought for yourself.

in the second class User1 the constructor or the init method is used to create a new instance or new row inside the table, every instance of the User1 class you create will be equivalent to a new row in the table

class User(db.Model):
    
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), unique=True, index=True)
    username = db.Column(db.String(20), unique=True, index=True)
    hash_passwrd = db.Column(db.String(200))



    def __init__(self, email, username, password):
        self.email = email
        self.username = username
        self.hash_passwrd = generate_password_hash(password)


adams = user('adams@email.com', 'adams', 'adams@1')
ben= user('ben@email.com', 'ben', 'ben@1')
poolo= user('poolo@email.com', 'poolo', 'poolo@1')

somewhere in your in your code you will have your database object

db.session.add_all([adams, ben, poolo])
db.session.commit()

now these three class object are now rows inside your table.

when you instaciate a class like this in flask it means you are creating a new row inside your user table, I hope this helps.

Perhaps the below little snippet helps to explain what is going on:

class A:
    def __init__(self, a):
        self.a = a

class B(A):

    def printme(self):
        print(self.a)

b = B(10)
b.printme()

result

10

class B inherits class A which has an __init__ method that defines self.a , which is called when the instance B is created which is then used in class B method printme .

so obviously the creation of the table happens in the base class

This is a misconception. The model class defines the structure of a table, and that table is created when Base.metadata.create_all or similar is called. This is independent of the creation of any instances of the class.

Creating an instance of the model class - user = User(...) is the equivalent of creating a row on the table, not the table itself. If an __init__ method assigns values to the class' attributes, these values become the row values. If no __init__ function is defined, the declarative machinery calls a default constructor (or a function passed as declarative_base 's constructor argument) to assign the values passed to the Model's constructor.

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